2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
48 #include <glibmm/miscutils.h>
49 #include <gtkmm/image.h>
50 #include <gdkmm/color.h>
51 #include <gdkmm/bitmap.h>
53 #include "gtkmm2ext/bindings.h"
54 #include "gtkmm2ext/grouped_buttons.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/tearoff.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/window_title.h"
59 #include "gtkmm2ext/choice.h"
60 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioengine.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/profile.h"
67 #include "ardour/route_group.h"
68 #include "ardour/session_playlists.h"
69 #include "ardour/tempo.h"
70 #include "ardour/utils.h"
72 #include "control_protocol/control_protocol.h"
76 #include "analysis_window.h"
77 #include "audio_clock.h"
78 #include "audio_region_view.h"
79 #include "audio_streamview.h"
80 #include "audio_time_axis.h"
81 #include "automation_time_axis.h"
82 #include "bundle_manager.h"
83 #include "canvas-noevent-text.h"
84 #include "canvas_impl.h"
85 #include "crossfade_edit.h"
89 #include "editor_cursors.h"
90 #include "editor_drag.h"
91 #include "editor_group_tabs.h"
92 #include "editor_locations.h"
93 #include "editor_regions.h"
94 #include "editor_route_groups.h"
95 #include "editor_routes.h"
96 #include "editor_snapshots.h"
97 #include "editor_summary.h"
98 #include "global_port_matrix.h"
99 #include "gui_object.h"
100 #include "gui_thread.h"
101 #include "keyboard.h"
103 #include "midi_time_axis.h"
104 #include "mixer_strip.h"
105 #include "mixer_ui.h"
106 #include "mouse_cursors.h"
107 #include "playlist_selector.h"
108 #include "public_editor.h"
109 #include "region_layering_order_editor.h"
110 #include "rgb_macros.h"
111 #include "rhythm_ferret.h"
112 #include "selection.h"
114 #include "simpleline.h"
115 #include "tempo_lines.h"
116 #include "time_axis_view.h"
122 #include "imageframe_socket_handler.h"
126 using namespace ARDOUR;
129 using namespace Glib;
130 using namespace Gtkmm2ext;
131 using namespace Editing;
133 using PBD::internationalize;
135 using Gtkmm2ext::Keyboard;
137 const double Editor::timebar_height = 15.0;
139 static const gchar *_snap_type_strings[] = {
141 N_("Timecode Frames"),
142 N_("Timecode Seconds"),
143 N_("Timecode Minutes"),
173 static const gchar *_snap_mode_strings[] = {
180 static const gchar *_edit_point_strings[] = {
187 static const gchar *_zoom_focus_strings[] = {
197 #ifdef USE_RUBBERBAND
198 static const gchar *_rb_opt_strings[] = {
201 N_("Balanced multitimbral mixture"),
202 N_("Unpitched percussion with stable notes"),
203 N_("Crisp monophonic instrumental"),
204 N_("Unpitched solo percussion"),
205 N_("Resample without preserving pitch"),
211 pane_size_watcher (Paned* pane)
213 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
217 Quartz: impossible to access
219 so stop that by preventing it from ever getting too narrow. 35
220 pixels is basically a rough guess at the tab width.
225 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
227 gint pos = pane->get_position ();
229 if (pos > max_width_of_lhs) {
230 pane->set_position (max_width_of_lhs);
235 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
237 /* time display buttons */
238 , minsec_label (_("Mins:Secs"))
239 , bbt_label (_("Bars:Beats"))
240 , timecode_label (_("Timecode"))
241 , samples_label (_("Samples"))
242 , tempo_label (_("Tempo"))
243 , meter_label (_("Meter"))
244 , mark_label (_("Location Markers"))
245 , range_mark_label (_("Range Markers"))
246 , transport_mark_label (_("Loop/Punch Ranges"))
247 , cd_mark_label (_("CD Markers"))
248 , edit_packer (4, 4, true)
250 /* the values here don't matter: layout widgets
251 reset them as needed.
254 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
256 /* tool bar related */
258 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
260 , toolbar_selection_clock_table (2,3)
262 , automation_mode_button (_("mode"))
264 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
267 , image_socket_listener(0)
272 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
273 , meters_running(false)
274 , _pending_locate_request (false)
275 , _pending_initial_locate (false)
276 , _last_cut_copy_source_track (0)
278 , _region_selection_change_updates_region_list (true)
279 , _following_mixer_selection (false)
280 , _control_point_toggled_on_press (false)
281 , _stepping_axis_view (0)
285 /* we are a singleton */
287 PublicEditor::_instance = this;
291 selection = new Selection (this);
292 cut_buffer = new Selection (this);
294 clicked_regionview = 0;
295 clicked_axisview = 0;
296 clicked_routeview = 0;
297 clicked_control_point = 0;
298 last_update_frame = 0;
299 pre_press_cursor = 0;
300 _drags = new DragManager (this);
301 current_mixer_strip = 0;
304 snap_type_strings = I18N (_snap_type_strings);
305 snap_mode_strings = I18N (_snap_mode_strings);
306 zoom_focus_strings = I18N (_zoom_focus_strings);
307 edit_point_strings = I18N (_edit_point_strings);
308 #ifdef USE_RUBBERBAND
309 rb_opt_strings = I18N (_rb_opt_strings);
313 snap_threshold = 5.0;
314 bbt_beat_subdivision = 4;
317 last_autoscroll_x = 0;
318 last_autoscroll_y = 0;
319 autoscroll_active = false;
320 autoscroll_timeout_tag = -1;
325 current_interthread_info = 0;
326 _show_measures = true;
328 show_gain_after_trim = false;
330 have_pending_keyboard_selection = false;
331 _follow_playhead = true;
332 _stationary_playhead = false;
333 editor_ruler_menu = 0;
334 no_ruler_shown_update = false;
336 range_marker_menu = 0;
337 marker_menu_item = 0;
338 tempo_or_meter_marker_menu = 0;
339 transport_marker_menu = 0;
340 new_transport_marker_menu = 0;
341 editor_mixer_strip_width = Wide;
342 show_editor_mixer_when_tracks_arrive = false;
343 region_edit_menu_split_multichannel_item = 0;
344 region_edit_menu_split_item = 0;
347 current_stepping_trackview = 0;
349 entered_regionview = 0;
351 clear_entered_track = false;
354 button_release_can_deselect = true;
355 _dragging_playhead = false;
356 _dragging_edit_point = false;
357 select_new_marker = false;
359 layering_order_editor = 0;
360 no_save_visual = false;
362 within_track_canvas = false;
364 scrubbing_direction = 0;
368 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
369 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
370 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
371 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
372 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
374 _edit_point = EditAtMouse;
375 _internal_editing = false;
376 current_canvas_cursor = 0;
378 frames_per_unit = 2048; /* too early to use reset_zoom () */
380 _scroll_callbacks = 0;
382 zoom_focus = ZoomFocusLeft;
383 set_zoom_focus (ZoomFocusLeft);
384 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
386 bbt_label.set_name ("EditorTimeButton");
387 bbt_label.set_size_request (-1, (int)timebar_height);
388 bbt_label.set_alignment (1.0, 0.5);
389 bbt_label.set_padding (5,0);
391 bbt_label.set_no_show_all();
392 minsec_label.set_name ("EditorTimeButton");
393 minsec_label.set_size_request (-1, (int)timebar_height);
394 minsec_label.set_alignment (1.0, 0.5);
395 minsec_label.set_padding (5,0);
396 minsec_label.hide ();
397 minsec_label.set_no_show_all();
398 timecode_label.set_name ("EditorTimeButton");
399 timecode_label.set_size_request (-1, (int)timebar_height);
400 timecode_label.set_alignment (1.0, 0.5);
401 timecode_label.set_padding (5,0);
402 timecode_label.hide ();
403 timecode_label.set_no_show_all();
404 samples_label.set_name ("EditorTimeButton");
405 samples_label.set_size_request (-1, (int)timebar_height);
406 samples_label.set_alignment (1.0, 0.5);
407 samples_label.set_padding (5,0);
408 samples_label.hide ();
409 samples_label.set_no_show_all();
411 tempo_label.set_name ("EditorTimeButton");
412 tempo_label.set_size_request (-1, (int)timebar_height);
413 tempo_label.set_alignment (1.0, 0.5);
414 tempo_label.set_padding (5,0);
416 tempo_label.set_no_show_all();
418 meter_label.set_name ("EditorTimeButton");
419 meter_label.set_size_request (-1, (int)timebar_height);
420 meter_label.set_alignment (1.0, 0.5);
421 meter_label.set_padding (5,0);
423 meter_label.set_no_show_all();
425 mark_label.set_name ("EditorTimeButton");
426 mark_label.set_size_request (-1, (int)timebar_height);
427 mark_label.set_alignment (1.0, 0.5);
428 mark_label.set_padding (5,0);
430 mark_label.set_no_show_all();
432 cd_mark_label.set_name ("EditorTimeButton");
433 cd_mark_label.set_size_request (-1, (int)timebar_height);
434 cd_mark_label.set_alignment (1.0, 0.5);
435 cd_mark_label.set_padding (5,0);
436 cd_mark_label.hide();
437 cd_mark_label.set_no_show_all();
439 range_mark_label.set_name ("EditorTimeButton");
440 range_mark_label.set_size_request (-1, (int)timebar_height);
441 range_mark_label.set_alignment (1.0, 0.5);
442 range_mark_label.set_padding (5,0);
443 range_mark_label.hide();
444 range_mark_label.set_no_show_all();
446 transport_mark_label.set_name ("EditorTimeButton");
447 transport_mark_label.set_size_request (-1, (int)timebar_height);
448 transport_mark_label.set_alignment (1.0, 0.5);
449 transport_mark_label.set_padding (5,0);
450 transport_mark_label.hide();
451 transport_mark_label.set_no_show_all();
453 initialize_rulers ();
454 initialize_canvas ();
456 _summary = new EditorSummary (this);
458 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
459 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
461 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
463 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
464 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
466 edit_controls_vbox.set_spacing (0);
467 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
468 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
470 HBox* h = manage (new HBox);
471 _group_tabs = new EditorGroupTabs (this);
472 h->pack_start (*_group_tabs, PACK_SHRINK);
473 h->pack_start (edit_controls_vbox);
474 controls_layout.add (*h);
476 controls_layout.set_name ("EditControlsBase");
477 controls_layout.add_events (Gdk::SCROLL_MASK);
478 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
480 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
481 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
483 _cursors = new MouseCursors;
485 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
486 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
487 0.0, 1.0, 100.0, 1.0));
489 pad_line_1->property_color_rgba() = 0xFF0000FF;
494 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
495 time_canvas_vbox.set_size_request (-1, -1);
497 ruler_label_event_box.add (ruler_label_vbox);
498 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
499 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
501 time_button_event_box.add (time_button_vbox);
502 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
503 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
505 /* these enable us to have a dedicated window (for cursor setting, etc.)
506 for the canvas areas.
509 track_canvas_event_box.add (*track_canvas);
511 time_canvas_event_box.add (time_canvas_vbox);
512 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
514 edit_packer.set_col_spacings (0);
515 edit_packer.set_row_spacings (0);
516 edit_packer.set_homogeneous (false);
517 edit_packer.set_border_width (0);
518 edit_packer.set_name ("EditorWindow");
520 /* labels for the rulers */
521 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
522 /* labels for the marker "tracks" */
523 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
525 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
527 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
529 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
531 bottom_hbox.set_border_width (2);
532 bottom_hbox.set_spacing (3);
534 _route_groups = new EditorRouteGroups (this);
535 _routes = new EditorRoutes (this);
536 _regions = new EditorRegions (this);
537 _snapshots = new EditorSnapshots (this);
538 _locations = new EditorLocations (this);
540 add_notebook_page (_("Regions"), _regions->widget ());
541 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
542 add_notebook_page (_("Snapshots"), _snapshots->widget ());
543 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
544 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
546 _the_notebook.set_show_tabs (true);
547 _the_notebook.set_scrollable (true);
548 _the_notebook.popup_disable ();
549 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
550 _the_notebook.show_all ();
552 _notebook_shrunk = false;
554 editor_summary_pane.pack1(edit_packer);
556 Button* summary_arrows_left_left = manage (new Button);
557 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
558 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
559 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
561 Button* summary_arrows_left_right = manage (new Button);
562 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
563 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
564 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
566 VBox* summary_arrows_left = manage (new VBox);
567 summary_arrows_left->pack_start (*summary_arrows_left_left);
568 summary_arrows_left->pack_start (*summary_arrows_left_right);
570 Button* summary_arrows_right_up = manage (new Button);
571 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
572 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
573 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
575 Button* summary_arrows_right_down = manage (new Button);
576 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
577 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
578 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
580 VBox* summary_arrows_right = manage (new VBox);
581 summary_arrows_right->pack_start (*summary_arrows_right_up);
582 summary_arrows_right->pack_start (*summary_arrows_right_down);
584 Frame* summary_frame = manage (new Frame);
585 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
587 summary_frame->add (*_summary);
588 summary_frame->show ();
590 _summary_hbox.pack_start (*summary_arrows_left, false, false);
591 _summary_hbox.pack_start (*summary_frame, true, true);
592 _summary_hbox.pack_start (*summary_arrows_right, false, false);
594 editor_summary_pane.pack2 (_summary_hbox);
596 edit_pane.pack1 (editor_summary_pane, true, true);
597 edit_pane.pack2 (_the_notebook, false, true);
599 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
601 /* XXX: editor_summary_pane might need similar to the edit_pane */
603 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
605 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
606 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
608 top_hbox.pack_start (toolbar_frame);
610 HBox *hbox = manage (new HBox);
611 hbox->pack_start (edit_pane, true, true);
613 global_vpacker.pack_start (top_hbox, false, false);
614 global_vpacker.pack_start (*hbox, true, true);
616 global_hpacker.pack_start (global_vpacker, true, true);
618 set_name ("EditorWindow");
619 add_accel_group (ActionManager::ui_manager->get_accel_group());
621 status_bar_hpacker.show ();
623 vpacker.pack_end (status_bar_hpacker, false, false);
624 vpacker.pack_end (global_hpacker, true, true);
626 /* register actions now so that set_state() can find them and set toggles/checks etc */
629 /* when we start using our own keybinding system for the editor, this
630 * will be uncommented
636 _snap_type = SnapToBeat;
637 set_snap_to (_snap_type);
638 _snap_mode = SnapOff;
639 set_snap_mode (_snap_mode);
640 set_mouse_mode (MouseObject, true);
641 pre_internal_mouse_mode = MouseObject;
642 pre_internal_snap_type = _snap_type;
643 pre_internal_snap_mode = _snap_mode;
644 internal_snap_type = _snap_type;
645 internal_snap_mode = _snap_mode;
646 set_edit_point_preference (EditAtMouse, true);
648 _playlist_selector = new PlaylistSelector();
649 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
651 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
655 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
656 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
658 nudge_forward_button.set_name ("TransportButton");
659 nudge_backward_button.set_name ("TransportButton");
661 fade_context_menu.set_name ("ArdourContextMenu");
663 /* icons, titles, WM stuff */
665 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
666 Glib::RefPtr<Gdk::Pixbuf> icon;
668 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
669 window_icons.push_back (icon);
671 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
672 window_icons.push_back (icon);
674 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
678 window_icons.push_back (icon);
680 if (!window_icons.empty()) {
681 // set_icon_list (window_icons);
682 set_default_icon_list (window_icons);
685 WindowTitle title(Glib::get_application_name());
686 title += _("Editor");
687 set_title (title.get_string());
688 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
691 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
693 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
694 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
696 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
698 /* allow external control surfaces/protocols to do various things */
700 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
701 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
702 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
703 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
704 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
705 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
706 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
707 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
708 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
709 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
710 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
711 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
712 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
713 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
715 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
716 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
717 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
718 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
719 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
721 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
723 /* problematic: has to return a value and thus cannot be x-thread */
725 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
727 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
729 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
731 _ignore_region_action = false;
732 _last_region_menu_was_main = false;
733 _popup_region_menu_item = 0;
735 _show_marker_lines = false;
736 _over_region_trim_target = false;
738 /* Button bindings */
740 button_bindings = new Bindings;
742 XMLNode* node = button_settings();
744 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
745 button_bindings->load (**i);
752 setup_fade_images ();
758 if(image_socket_listener) {
759 if(image_socket_listener->is_connected())
761 image_socket_listener->close_connection() ;
764 delete image_socket_listener ;
765 image_socket_listener = 0 ;
769 delete button_bindings;
771 delete _route_groups;
777 Editor::button_settings () const
779 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
780 XMLNode* node = find_named_node (*settings, X_("Buttons"));
783 node = new XMLNode (X_("Buttons"));
790 Editor::add_toplevel_controls (Container& cont)
792 vpacker.pack_start (cont, false, false);
797 Editor::get_smart_mode () const
799 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
803 Editor::catch_vanishing_regionview (RegionView *rv)
805 /* note: the selection will take care of the vanishing
806 audioregionview by itself.
809 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
813 if (clicked_regionview == rv) {
814 clicked_regionview = 0;
817 if (entered_regionview == rv) {
818 set_entered_regionview (0);
821 if (!_all_region_actions_sensitized) {
822 sensitize_all_region_actions (true);
825 _over_region_trim_target = false;
829 Editor::set_entered_regionview (RegionView* rv)
831 if (rv == entered_regionview) {
835 if (entered_regionview) {
836 entered_regionview->exited ();
839 if ((entered_regionview = rv) != 0) {
840 entered_regionview->entered (internal_editing ());
843 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
844 /* This RegionView entry might have changed what region actions
845 are allowed, so sensitize them all in case a key is pressed.
847 sensitize_all_region_actions (true);
852 Editor::set_entered_track (TimeAxisView* tav)
855 entered_track->exited ();
858 if ((entered_track = tav) != 0) {
859 entered_track->entered ();
864 Editor::show_window ()
866 if (!is_visible ()) {
869 /* XXX: this is a bit unfortunate; it would probably
870 be nicer if we could just call show () above rather
871 than needing the show_all ()
874 /* re-hide stuff if necessary */
875 editor_list_button_toggled ();
876 parameter_changed ("show-summary");
877 parameter_changed ("show-group-tabs");
878 parameter_changed ("show-zoom-tools");
880 /* now reset all audio_time_axis heights, because widgets might need
886 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
887 tv = (static_cast<TimeAxisView*>(*i));
891 if (current_mixer_strip) {
892 current_mixer_strip->hide_things ();
893 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
901 Editor::instant_save ()
903 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
908 _session->add_instant_xml(get_state());
910 Config->add_instant_xml(get_state());
915 Editor::zoom_adjustment_changed ()
921 double fpu = zoom_range_clock->current_duration() / _canvas_width;
922 bool clamped = clamp_frames_per_unit (fpu);
925 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
932 Editor::control_vertical_zoom_in_all ()
934 tav_zoom_smooth (false, true);
938 Editor::control_vertical_zoom_out_all ()
940 tav_zoom_smooth (true, true);
944 Editor::control_vertical_zoom_in_selected ()
946 tav_zoom_smooth (false, false);
950 Editor::control_vertical_zoom_out_selected ()
952 tav_zoom_smooth (true, false);
956 Editor::control_view (uint32_t view)
958 goto_visual_state (view);
962 Editor::control_unselect ()
964 selection->clear_tracks ();
968 Editor::control_select (uint32_t rid, Selection::Operation op)
970 /* handles the (static) signal from the ControlProtocol class that
971 * requests setting the selected track to a given RID
978 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
984 TimeAxisView* tav = axis_view_from_route (r);
989 selection->add (tav);
991 case Selection::Toggle:
992 selection->toggle (tav);
994 case Selection::Extend:
997 selection->set (tav);
1001 selection->clear_tracks ();
1006 Editor::control_step_tracks_up ()
1008 scroll_tracks_up_line ();
1012 Editor::control_step_tracks_down ()
1014 scroll_tracks_down_line ();
1018 Editor::control_scroll (float fraction)
1020 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1026 double step = fraction * current_page_frames();
1029 _control_scroll_target is an optional<T>
1031 it acts like a pointer to an framepos_t, with
1032 a operator conversion to boolean to check
1033 that it has a value could possibly use
1034 playhead_cursor->current_frame to store the
1035 value and a boolean in the class to know
1036 when it's out of date
1039 if (!_control_scroll_target) {
1040 _control_scroll_target = _session->transport_frame();
1041 _dragging_playhead = true;
1044 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1045 *_control_scroll_target = 0;
1046 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1047 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1049 *_control_scroll_target += (framepos_t) floor (step);
1052 /* move visuals, we'll catch up with it later */
1054 playhead_cursor->set_position (*_control_scroll_target);
1055 UpdateAllTransportClocks (*_control_scroll_target);
1057 if (*_control_scroll_target > (current_page_frames() / 2)) {
1058 /* try to center PH in window */
1059 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1065 Now we do a timeout to actually bring the session to the right place
1066 according to the playhead. This is to avoid reading disk buffers on every
1067 call to control_scroll, which is driven by ScrollTimeline and therefore
1068 probably by a control surface wheel which can generate lots of events.
1070 /* cancel the existing timeout */
1072 control_scroll_connection.disconnect ();
1074 /* add the next timeout */
1076 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1080 Editor::deferred_control_scroll (framepos_t /*target*/)
1082 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1083 // reset for next stream
1084 _control_scroll_target = boost::none;
1085 _dragging_playhead = false;
1090 Editor::access_action (std::string action_group, std::string action_item)
1096 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1099 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1107 Editor::on_realize ()
1109 Window::on_realize ();
1114 Editor::map_position_change (framepos_t frame)
1116 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1118 if (_session == 0) {
1122 if (_follow_playhead) {
1123 center_screen (frame);
1126 playhead_cursor->set_position (frame);
1130 Editor::center_screen (framepos_t frame)
1132 double page = _canvas_width * frames_per_unit;
1134 /* if we're off the page, then scroll.
1137 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1138 center_screen_internal (frame, page);
1143 Editor::center_screen_internal (framepos_t frame, float page)
1148 frame -= (framepos_t) page;
1153 reset_x_origin (frame);
1158 Editor::update_title ()
1160 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1163 bool dirty = _session->dirty();
1165 string session_name;
1167 if (_session->snap_name() != _session->name()) {
1168 session_name = _session->snap_name();
1170 session_name = _session->name();
1174 session_name = "*" + session_name;
1177 WindowTitle title(session_name);
1178 title += Glib::get_application_name();
1179 set_title (title.get_string());
1181 /* ::session_going_away() will have taken care of it */
1186 Editor::set_session (Session *t)
1188 SessionHandlePtr::set_session (t);
1194 zoom_range_clock->set_session (_session);
1195 _playlist_selector->set_session (_session);
1196 nudge_clock->set_session (_session);
1197 _summary->set_session (_session);
1198 _group_tabs->set_session (_session);
1199 _route_groups->set_session (_session);
1200 _regions->set_session (_session);
1201 _snapshots->set_session (_session);
1202 _routes->set_session (_session);
1203 _locations->set_session (_session);
1205 if (rhythm_ferret) {
1206 rhythm_ferret->set_session (_session);
1209 if (analysis_window) {
1210 analysis_window->set_session (_session);
1214 sfbrowser->set_session (_session);
1217 compute_fixed_ruler_scale ();
1219 /* Make sure we have auto loop and auto punch ranges */
1221 Location* loc = _session->locations()->auto_loop_location();
1223 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1225 if (loc->start() == loc->end()) {
1226 loc->set_end (loc->start() + 1);
1229 _session->locations()->add (loc, false);
1230 _session->set_auto_loop_location (loc);
1233 loc->set_name (_("Loop"));
1236 loc = _session->locations()->auto_punch_location();
1239 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1241 if (loc->start() == loc->end()) {
1242 loc->set_end (loc->start() + 1);
1245 _session->locations()->add (loc, false);
1246 _session->set_auto_punch_location (loc);
1249 loc->set_name (_("Punch"));
1252 refresh_location_display ();
1254 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1255 the selected Marker; this needs the LocationMarker list to be available.
1257 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1258 set_state (*node, Stateful::loading_state_version);
1260 /* catch up with the playhead */
1262 _session->request_locate (playhead_cursor->current_frame);
1263 _pending_initial_locate = true;
1267 /* These signals can all be emitted by a non-GUI thread. Therefore the
1268 handlers for them must not attempt to directly interact with the GUI,
1269 but use Gtkmm2ext::UI::instance()->call_slot();
1272 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1273 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1274 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1275 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1276 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1277 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1278 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1279 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1280 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1281 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1282 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1283 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1284 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1285 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1287 playhead_cursor->canvas_item.show ();
1289 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1290 Config->map_parameters (pc);
1291 _session->config.map_parameters (pc);
1293 restore_ruler_visibility ();
1294 //tempo_map_changed (PropertyChange (0));
1295 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1297 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1298 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1301 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1302 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1305 switch (_snap_type) {
1306 case SnapToRegionStart:
1307 case SnapToRegionEnd:
1308 case SnapToRegionSync:
1309 case SnapToRegionBoundary:
1310 build_region_boundary_cache ();
1317 /* register for undo history */
1318 _session->register_with_memento_command_factory(id(), this);
1320 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1322 start_updating_meters ();
1326 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1328 if (a->get_name() == "RegionMenu") {
1329 /* When the main menu's region menu is opened, we setup the actions so that they look right
1330 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1331 so we resensitize all region actions when the entered regionview or the region selection
1332 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1333 happens after the region context menu is opened. So we set a flag here, too.
1337 sensitize_the_right_region_actions ();
1338 _last_region_menu_was_main = true;
1343 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1345 using namespace Menu_Helpers;
1347 void (Editor::*emf)(FadeShape);
1348 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1351 images = &_xfade_in_images;
1352 emf = &Editor::set_fade_in_shape;
1354 images = &_xfade_out_images;
1355 emf = &Editor::set_fade_out_shape;
1360 _("Linear (for highly correlated material)"),
1361 *(*images)[FadeLinear],
1362 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1366 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1371 *(*images)[FadeConstantPower],
1372 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1375 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1380 *(*images)[FadeSymmetric],
1381 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1390 *(*images)[FadeSlow],
1391 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1394 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 *(*images)[FadeFast],
1400 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1403 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1406 /** Pop up a context menu for when the user clicks on a start crossfade */
1408 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1410 using namespace Menu_Helpers;
1412 MenuList& items (xfade_in_context_menu.items());
1414 if (items.empty()) {
1415 fill_xfade_menu (items, true);
1418 xfade_in_context_menu.popup (button, time);
1421 /** Pop up a context menu for when the user clicks on an end crossfade */
1423 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1425 using namespace Menu_Helpers;
1427 MenuList& items (xfade_out_context_menu.items());
1429 if (items.empty()) {
1430 fill_xfade_menu (items, false);
1433 xfade_out_context_menu.popup (button, time);
1437 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1439 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1441 using namespace Menu_Helpers;
1442 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1445 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1449 MenuList& items (fade_context_menu.items());
1452 switch (item_type) {
1454 case FadeInHandleItem:
1455 if (arv->audio_region()->fade_in_active()) {
1456 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1458 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1461 items.push_back (SeparatorElem());
1463 if (Profile->get_sae()) {
1465 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1466 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1473 *_fade_in_images[FadeLinear],
1474 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1483 *_fade_in_images[FadeSlow],
1484 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1492 *_fade_in_images[FadeFast],
1493 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *_fade_in_images[FadeSymmetric],
1502 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1507 _("Constant Power"),
1508 *_fade_in_images[FadeConstantPower],
1509 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1512 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1518 case FadeOutHandleItem:
1519 if (arv->audio_region()->fade_out_active()) {
1520 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1522 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1525 items.push_back (SeparatorElem());
1527 if (Profile->get_sae()) {
1528 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1529 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1535 *_fade_out_images[FadeLinear],
1536 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1540 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1545 *_fade_out_images[FadeSlow],
1546 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1549 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1554 *_fade_out_images[FadeFast],
1555 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1558 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1563 *_fade_out_images[FadeSymmetric],
1564 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1569 _("Constant Power"),
1570 *_fade_out_images[FadeConstantPower],
1571 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1574 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1580 fatal << _("programming error: ")
1581 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1586 fade_context_menu.popup (button, time);
1590 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1592 using namespace Menu_Helpers;
1593 Menu* (Editor::*build_menu_function)();
1596 switch (item_type) {
1598 case RegionViewName:
1599 case RegionViewNameHighlight:
1600 case LeftFrameHandle:
1601 case RightFrameHandle:
1602 if (with_selection) {
1603 build_menu_function = &Editor::build_track_selection_context_menu;
1605 build_menu_function = &Editor::build_track_region_context_menu;
1610 if (with_selection) {
1611 build_menu_function = &Editor::build_track_selection_context_menu;
1613 build_menu_function = &Editor::build_track_context_menu;
1618 if (clicked_routeview->track()) {
1619 build_menu_function = &Editor::build_track_context_menu;
1621 build_menu_function = &Editor::build_track_bus_context_menu;
1626 /* probably shouldn't happen but if it does, we don't care */
1630 menu = (this->*build_menu_function)();
1631 menu->set_name ("ArdourContextMenu");
1633 /* now handle specific situations */
1635 switch (item_type) {
1637 case RegionViewName:
1638 case RegionViewNameHighlight:
1639 case LeftFrameHandle:
1640 case RightFrameHandle:
1641 if (!with_selection) {
1642 if (region_edit_menu_split_item) {
1643 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1644 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1646 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1649 if (region_edit_menu_split_multichannel_item) {
1650 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1651 region_edit_menu_split_multichannel_item->set_sensitive (true);
1653 region_edit_menu_split_multichannel_item->set_sensitive (false);
1666 /* probably shouldn't happen but if it does, we don't care */
1670 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1672 /* Bounce to disk */
1674 using namespace Menu_Helpers;
1675 MenuList& edit_items = menu->items();
1677 edit_items.push_back (SeparatorElem());
1679 switch (clicked_routeview->audio_track()->freeze_state()) {
1680 case AudioTrack::NoFreeze:
1681 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1684 case AudioTrack::Frozen:
1685 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1688 case AudioTrack::UnFrozen:
1689 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1695 if (item_type == StreamItem && clicked_routeview) {
1696 clicked_routeview->build_underlay_menu(menu);
1699 /* When the region menu is opened, we setup the actions so that they look right
1702 sensitize_the_right_region_actions ();
1703 _last_region_menu_was_main = false;
1705 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1706 menu->popup (button, time);
1710 Editor::build_track_context_menu ()
1712 using namespace Menu_Helpers;
1714 MenuList& edit_items = track_context_menu.items();
1717 add_dstream_context_items (edit_items);
1718 return &track_context_menu;
1722 Editor::build_track_bus_context_menu ()
1724 using namespace Menu_Helpers;
1726 MenuList& edit_items = track_context_menu.items();
1729 add_bus_context_items (edit_items);
1730 return &track_context_menu;
1734 Editor::build_track_region_context_menu ()
1736 using namespace Menu_Helpers;
1737 MenuList& edit_items = track_region_context_menu.items();
1740 /* we've just cleared the track region context menu, so the menu that these
1741 two items were on will have disappeared; stop them dangling.
1743 region_edit_menu_split_item = 0;
1744 region_edit_menu_split_multichannel_item = 0;
1746 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1749 boost::shared_ptr<Track> tr;
1750 boost::shared_ptr<Playlist> pl;
1752 if ((tr = rtv->track())) {
1753 add_region_context_items (edit_items, tr);
1757 add_dstream_context_items (edit_items);
1759 return &track_region_context_menu;
1763 Editor::analyze_region_selection ()
1765 if (analysis_window == 0) {
1766 analysis_window = new AnalysisWindow();
1769 analysis_window->set_session(_session);
1771 analysis_window->show_all();
1774 analysis_window->set_regionmode();
1775 analysis_window->analyze();
1777 analysis_window->present();
1781 Editor::analyze_range_selection()
1783 if (analysis_window == 0) {
1784 analysis_window = new AnalysisWindow();
1787 analysis_window->set_session(_session);
1789 analysis_window->show_all();
1792 analysis_window->set_rangemode();
1793 analysis_window->analyze();
1795 analysis_window->present();
1799 Editor::build_track_selection_context_menu ()
1801 using namespace Menu_Helpers;
1802 MenuList& edit_items = track_selection_context_menu.items();
1803 edit_items.clear ();
1805 add_selection_context_items (edit_items);
1806 // edit_items.push_back (SeparatorElem());
1807 // add_dstream_context_items (edit_items);
1809 return &track_selection_context_menu;
1813 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1815 using namespace Menu_Helpers;
1817 /* OK, stick the region submenu at the top of the list, and then add
1821 RegionSelection rs = get_regions_from_selection_and_entered ();
1823 string::size_type pos = 0;
1824 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1826 /* we have to hack up the region name because "_" has a special
1827 meaning for menu titles.
1830 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1831 menu_item_name.replace (pos, 1, "__");
1835 if (_popup_region_menu_item == 0) {
1836 _popup_region_menu_item = new MenuItem (menu_item_name);
1837 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1838 _popup_region_menu_item->show ();
1840 _popup_region_menu_item->set_label (menu_item_name);
1843 const framepos_t position = get_preferred_edit_position (false, true);
1845 edit_items.push_back (*_popup_region_menu_item);
1846 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1847 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1849 edit_items.push_back (SeparatorElem());
1852 /** Add context menu items relevant to selection ranges.
1853 * @param edit_items List to add the items to.
1856 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1858 using namespace Menu_Helpers;
1860 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1861 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1863 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1866 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (
1870 _("Move Range Start to Previous Region Boundary"),
1871 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1875 edit_items.push_back (
1877 _("Move Range Start to Next Region Boundary"),
1878 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1882 edit_items.push_back (
1884 _("Move Range End to Previous Region Boundary"),
1885 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1889 edit_items.push_back (
1891 _("Move Range End to Next Region Boundary"),
1892 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1898 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1900 edit_items.push_back (SeparatorElem());
1901 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1905 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1907 edit_items.push_back (SeparatorElem());
1908 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1910 edit_items.push_back (SeparatorElem());
1911 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1912 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1913 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1915 edit_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1917 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1918 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1919 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1920 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1925 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1927 using namespace Menu_Helpers;
1931 Menu *play_menu = manage (new Menu);
1932 MenuList& play_items = play_menu->items();
1933 play_menu->set_name ("ArdourContextMenu");
1935 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1936 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1937 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1938 play_items.push_back (SeparatorElem());
1939 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1941 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1945 Menu *select_menu = manage (new Menu);
1946 MenuList& select_items = select_menu->items();
1947 select_menu->set_name ("ArdourContextMenu");
1949 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1950 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1951 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1952 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1953 select_items.push_back (SeparatorElem());
1954 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1955 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1956 select_items.push_back (SeparatorElem());
1957 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1958 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1959 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1960 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1961 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1962 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1963 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1965 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1969 Menu *cutnpaste_menu = manage (new Menu);
1970 MenuList& cutnpaste_items = cutnpaste_menu->items();
1971 cutnpaste_menu->set_name ("ArdourContextMenu");
1973 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1974 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1975 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1977 cutnpaste_items.push_back (SeparatorElem());
1979 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1980 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1982 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1984 /* Adding new material */
1986 edit_items.push_back (SeparatorElem());
1987 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1988 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1992 Menu *nudge_menu = manage (new Menu());
1993 MenuList& nudge_items = nudge_menu->items();
1994 nudge_menu->set_name ("ArdourContextMenu");
1996 edit_items.push_back (SeparatorElem());
1997 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1998 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1999 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2000 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2002 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2006 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2008 using namespace Menu_Helpers;
2012 Menu *play_menu = manage (new Menu);
2013 MenuList& play_items = play_menu->items();
2014 play_menu->set_name ("ArdourContextMenu");
2016 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2017 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2018 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2022 Menu *select_menu = manage (new Menu);
2023 MenuList& select_items = select_menu->items();
2024 select_menu->set_name ("ArdourContextMenu");
2026 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2027 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2028 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2029 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2030 select_items.push_back (SeparatorElem());
2031 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2032 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2033 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2034 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2036 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2040 Menu *cutnpaste_menu = manage (new Menu);
2041 MenuList& cutnpaste_items = cutnpaste_menu->items();
2042 cutnpaste_menu->set_name ("ArdourContextMenu");
2044 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2045 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2046 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2048 Menu *nudge_menu = manage (new Menu());
2049 MenuList& nudge_items = nudge_menu->items();
2050 nudge_menu->set_name ("ArdourContextMenu");
2052 edit_items.push_back (SeparatorElem());
2053 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2054 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2055 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2056 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2058 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2062 Editor::snap_type() const
2068 Editor::snap_mode() const
2074 Editor::set_snap_to (SnapType st)
2076 unsigned int snap_ind = (unsigned int)st;
2080 if (snap_ind > snap_type_strings.size() - 1) {
2082 _snap_type = (SnapType)snap_ind;
2085 string str = snap_type_strings[snap_ind];
2087 if (str != snap_type_selector.get_active_text()) {
2088 snap_type_selector.set_active_text (str);
2093 switch (_snap_type) {
2094 case SnapToBeatDiv128:
2095 case SnapToBeatDiv64:
2096 case SnapToBeatDiv32:
2097 case SnapToBeatDiv28:
2098 case SnapToBeatDiv24:
2099 case SnapToBeatDiv20:
2100 case SnapToBeatDiv16:
2101 case SnapToBeatDiv14:
2102 case SnapToBeatDiv12:
2103 case SnapToBeatDiv10:
2104 case SnapToBeatDiv8:
2105 case SnapToBeatDiv7:
2106 case SnapToBeatDiv6:
2107 case SnapToBeatDiv5:
2108 case SnapToBeatDiv4:
2109 case SnapToBeatDiv3:
2110 case SnapToBeatDiv2: {
2111 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2112 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2114 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2115 current_bbt_points_begin, current_bbt_points_end);
2116 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2117 current_bbt_points_begin, current_bbt_points_end);
2118 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2122 case SnapToRegionStart:
2123 case SnapToRegionEnd:
2124 case SnapToRegionSync:
2125 case SnapToRegionBoundary:
2126 build_region_boundary_cache ();
2134 SnapChanged (); /* EMIT SIGNAL */
2138 Editor::set_snap_mode (SnapMode mode)
2141 string str = snap_mode_strings[(int)mode];
2143 if (str != snap_mode_selector.get_active_text ()) {
2144 snap_mode_selector.set_active_text (str);
2150 Editor::set_edit_point_preference (EditPoint ep, bool force)
2152 bool changed = (_edit_point != ep);
2155 string str = edit_point_strings[(int)ep];
2157 if (str != edit_point_selector.get_active_text ()) {
2158 edit_point_selector.set_active_text (str);
2161 set_canvas_cursor ();
2163 if (!force && !changed) {
2167 const char* action=NULL;
2169 switch (_edit_point) {
2170 case EditAtPlayhead:
2171 action = "edit-at-playhead";
2173 case EditAtSelectedMarker:
2174 action = "edit-at-marker";
2177 action = "edit-at-mouse";
2181 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2183 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2187 bool in_track_canvas;
2189 if (!mouse_frame (foo, in_track_canvas)) {
2190 in_track_canvas = false;
2193 reset_canvas_action_sensitivity (in_track_canvas);
2199 Editor::set_state (const XMLNode& node, int /*version*/)
2201 const XMLProperty* prop;
2208 g.base_width = default_width;
2209 g.base_height = default_height;
2213 if ((geometry = find_named_node (node, "geometry")) != 0) {
2217 if ((prop = geometry->property("x_size")) == 0) {
2218 prop = geometry->property ("x-size");
2221 g.base_width = atoi(prop->value());
2223 if ((prop = geometry->property("y_size")) == 0) {
2224 prop = geometry->property ("y-size");
2227 g.base_height = atoi(prop->value());
2230 if ((prop = geometry->property ("x_pos")) == 0) {
2231 prop = geometry->property ("x-pos");
2234 x = atoi (prop->value());
2237 if ((prop = geometry->property ("y_pos")) == 0) {
2238 prop = geometry->property ("y-pos");
2241 y = atoi (prop->value());
2245 set_default_size (g.base_width, g.base_height);
2248 if (_session && (prop = node.property ("playhead"))) {
2250 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2251 playhead_cursor->set_position (pos);
2253 playhead_cursor->set_position (0);
2256 if ((prop = node.property ("mixer-width"))) {
2257 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2260 if ((prop = node.property ("zoom-focus"))) {
2261 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2264 if ((prop = node.property ("zoom"))) {
2265 reset_zoom (PBD::atof (prop->value()));
2267 reset_zoom (frames_per_unit);
2270 if ((prop = node.property ("snap-to"))) {
2271 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2274 if ((prop = node.property ("snap-mode"))) {
2275 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2278 if ((prop = node.property ("internal-snap-to"))) {
2279 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2282 if ((prop = node.property ("internal-snap-mode"))) {
2283 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2286 if ((prop = node.property ("pre-internal-snap-to"))) {
2287 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2290 if ((prop = node.property ("pre-internal-snap-mode"))) {
2291 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2294 if ((prop = node.property ("mouse-mode"))) {
2295 MouseMode m = str2mousemode(prop->value());
2296 set_mouse_mode (m, true);
2298 set_mouse_mode (MouseObject, true);
2301 if ((prop = node.property ("left-frame")) != 0) {
2303 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2307 reset_x_origin (pos);
2311 if ((prop = node.property ("y-origin")) != 0) {
2312 reset_y_origin (atof (prop->value ()));
2315 if ((prop = node.property ("internal-edit"))) {
2316 bool yn = string_is_affirmative (prop->value());
2317 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2319 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2320 tact->set_active (!yn);
2321 tact->set_active (yn);
2325 if ((prop = node.property ("join-object-range"))) {
2326 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2327 bool yn = string_is_affirmative (prop->value());
2329 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2330 tact->set_active (!yn);
2331 tact->set_active (yn);
2333 set_mouse_mode(mouse_mode, true);
2336 if ((prop = node.property ("edit-point"))) {
2337 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2340 if ((prop = node.property ("show-measures"))) {
2341 bool yn = string_is_affirmative (prop->value());
2342 _show_measures = yn;
2343 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2345 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2346 /* do it twice to force the change */
2347 tact->set_active (!yn);
2348 tact->set_active (yn);
2352 if ((prop = node.property ("follow-playhead"))) {
2353 bool yn = string_is_affirmative (prop->value());
2354 set_follow_playhead (yn);
2355 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2357 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2358 if (tact->get_active() != yn) {
2359 tact->set_active (yn);
2364 if ((prop = node.property ("stationary-playhead"))) {
2365 bool yn = string_is_affirmative (prop->value());
2366 set_stationary_playhead (yn);
2367 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2369 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2370 if (tact->get_active() != yn) {
2371 tact->set_active (yn);
2376 if ((prop = node.property ("region-list-sort-type"))) {
2377 RegionListSortType st;
2378 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2381 if ((prop = node.property ("show-editor-mixer"))) {
2383 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2386 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2387 bool yn = string_is_affirmative (prop->value());
2389 /* do it twice to force the change */
2391 tact->set_active (!yn);
2392 tact->set_active (yn);
2395 if ((prop = node.property ("show-editor-list"))) {
2397 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2400 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2401 bool yn = string_is_affirmative (prop->value());
2403 /* do it twice to force the change */
2405 tact->set_active (!yn);
2406 tact->set_active (yn);
2409 if ((prop = node.property (X_("editor-list-page")))) {
2410 _the_notebook.set_current_page (atoi (prop->value ()));
2413 if ((prop = node.property (X_("show-marker-lines")))) {
2414 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2416 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2417 bool yn = string_is_affirmative (prop->value ());
2419 tact->set_active (!yn);
2420 tact->set_active (yn);
2423 XMLNodeList children = node.children ();
2424 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2425 selection->set_state (**i, Stateful::current_state_version);
2426 _regions->set_state (**i);
2429 if ((prop = node.property ("maximised"))) {
2430 bool yn = string_is_affirmative (prop->value());
2432 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2436 if ((prop = node.property ("nudge-clock-value"))) {
2438 sscanf (prop->value().c_str(), "%" PRId64, &f);
2439 nudge_clock->set (f);
2441 nudge_clock->set_mode (AudioClock::Timecode);
2442 nudge_clock->set (_session->frame_rate() * 5, true);
2449 Editor::get_state ()
2451 XMLNode* node = new XMLNode ("Editor");
2454 id().print (buf, sizeof (buf));
2455 node->add_property ("id", buf);
2457 if (is_realized()) {
2458 Glib::RefPtr<Gdk::Window> win = get_window();
2460 int x, y, width, height;
2461 win->get_root_origin(x, y);
2462 win->get_size(width, height);
2464 XMLNode* geometry = new XMLNode ("geometry");
2466 snprintf(buf, sizeof(buf), "%d", width);
2467 geometry->add_property("x-size", string(buf));
2468 snprintf(buf, sizeof(buf), "%d", height);
2469 geometry->add_property("y-size", string(buf));
2470 snprintf(buf, sizeof(buf), "%d", x);
2471 geometry->add_property("x-pos", string(buf));
2472 snprintf(buf, sizeof(buf), "%d", y);
2473 geometry->add_property("y-pos", string(buf));
2474 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2475 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2476 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2477 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2478 geometry->add_property("edit-vertical-pane-pos", string(buf));
2480 node->add_child_nocopy (*geometry);
2483 maybe_add_mixer_strip_width (*node);
2485 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2486 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2487 node->add_property ("zoom", buf);
2488 node->add_property ("snap-to", enum_2_string (_snap_type));
2489 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2490 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2491 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2492 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2493 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2494 node->add_property ("edit-point", enum_2_string (_edit_point));
2496 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2497 node->add_property ("playhead", buf);
2498 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2499 node->add_property ("left-frame", buf);
2500 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2501 node->add_property ("y-origin", buf);
2503 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2504 node->add_property ("maximised", _maximised ? "yes" : "no");
2505 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2506 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2507 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2508 node->add_property ("mouse-mode", enum2str(mouse_mode));
2509 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2510 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2512 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2514 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2515 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2518 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2520 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2521 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2524 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2525 node->add_property (X_("editor-list-page"), buf);
2527 if (button_bindings) {
2528 XMLNode* bb = new XMLNode (X_("Buttons"));
2529 button_bindings->save (*bb);
2530 node->add_child_nocopy (*bb);
2533 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2535 node->add_child_nocopy (selection->get_state ());
2536 node->add_child_nocopy (_regions->get_state ());
2538 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2539 node->add_property ("nudge-clock-value", buf);
2546 /** @param y y offset from the top of all trackviews.
2547 * @return pair: TimeAxisView that y is over, layer index.
2548 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2549 * in stacked or expanded region display mode, otherwise 0.
2551 std::pair<TimeAxisView *, double>
2552 Editor::trackview_by_y_position (double y)
2554 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2556 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2562 return std::make_pair ( (TimeAxisView *) 0, 0);
2565 /** Snap a position to the grid, if appropriate, taking into account current
2566 * grid settings and also the state of any snap modifier keys that may be pressed.
2567 * @param start Position to snap.
2568 * @param event Event to get current key modifier information from, or 0.
2571 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2573 if (!_session || !event) {
2577 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2578 if (_snap_mode == SnapOff) {
2579 snap_to_internal (start, direction, for_mark);
2582 if (_snap_mode != SnapOff) {
2583 snap_to_internal (start, direction, for_mark);
2589 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2591 if (!_session || _snap_mode == SnapOff) {
2595 snap_to_internal (start, direction, for_mark);
2599 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2601 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2602 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2604 switch (_snap_type) {
2605 case SnapToTimecodeFrame:
2606 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2607 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2609 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2613 case SnapToTimecodeSeconds:
2614 if (_session->config.get_timecode_offset_negative()) {
2615 start += _session->config.get_timecode_offset ();
2617 start -= _session->config.get_timecode_offset ();
2619 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2620 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2622 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2625 if (_session->config.get_timecode_offset_negative()) {
2626 start -= _session->config.get_timecode_offset ();
2628 start += _session->config.get_timecode_offset ();
2632 case SnapToTimecodeMinutes:
2633 if (_session->config.get_timecode_offset_negative()) {
2634 start += _session->config.get_timecode_offset ();
2636 start -= _session->config.get_timecode_offset ();
2638 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2639 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2641 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2643 if (_session->config.get_timecode_offset_negative()) {
2644 start -= _session->config.get_timecode_offset ();
2646 start += _session->config.get_timecode_offset ();
2650 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2656 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2658 const framepos_t one_second = _session->frame_rate();
2659 const framepos_t one_minute = _session->frame_rate() * 60;
2660 framepos_t presnap = start;
2664 switch (_snap_type) {
2665 case SnapToTimecodeFrame:
2666 case SnapToTimecodeSeconds:
2667 case SnapToTimecodeMinutes:
2668 return timecode_snap_to_internal (start, direction, for_mark);
2671 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2672 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2674 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2679 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2680 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2682 start = (framepos_t) floor ((double) start / one_second) * one_second;
2687 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2688 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2690 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2695 start = _session->tempo_map().round_to_bar (start, direction);
2699 start = _session->tempo_map().round_to_beat (start, direction);
2702 case SnapToBeatDiv128:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2705 case SnapToBeatDiv64:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2708 case SnapToBeatDiv32:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2711 case SnapToBeatDiv28:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2714 case SnapToBeatDiv24:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2717 case SnapToBeatDiv20:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2720 case SnapToBeatDiv16:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2723 case SnapToBeatDiv14:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2726 case SnapToBeatDiv12:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2729 case SnapToBeatDiv10:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2732 case SnapToBeatDiv8:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2735 case SnapToBeatDiv7:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2738 case SnapToBeatDiv6:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2741 case SnapToBeatDiv5:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2744 case SnapToBeatDiv4:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2747 case SnapToBeatDiv3:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2750 case SnapToBeatDiv2:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2759 _session->locations()->marks_either_side (start, before, after);
2761 if (before == max_framepos && after == max_framepos) {
2762 /* No marks to snap to, so just don't snap */
2764 } else if (before == max_framepos) {
2766 } else if (after == max_framepos) {
2768 } else if (before != max_framepos && after != max_framepos) {
2769 /* have before and after */
2770 if ((start - before) < (after - start)) {
2779 case SnapToRegionStart:
2780 case SnapToRegionEnd:
2781 case SnapToRegionSync:
2782 case SnapToRegionBoundary:
2783 if (!region_boundary_cache.empty()) {
2785 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2786 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2788 if (direction > 0) {
2789 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2791 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2794 if (next != region_boundary_cache.begin ()) {
2799 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2800 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2802 if (start > (p + n) / 2) {
2811 switch (_snap_mode) {
2817 if (presnap > start) {
2818 if (presnap > (start + unit_to_frame(snap_threshold))) {
2822 } else if (presnap < start) {
2823 if (presnap < (start - unit_to_frame(snap_threshold))) {
2829 /* handled at entry */
2837 Editor::setup_toolbar ()
2839 HBox* mode_box = manage(new HBox);
2840 mode_box->set_border_width (2);
2841 mode_box->set_spacing(4);
2843 HBox* mouse_mode_box = manage (new HBox);
2844 HBox* mouse_mode_hbox = manage (new HBox);
2845 VBox* mouse_mode_vbox = manage (new VBox);
2846 Alignment* mouse_mode_align = manage (new Alignment);
2848 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2849 // mouse_mode_size_group->add_widget (smart_mode_button);
2850 mouse_mode_size_group->add_widget (mouse_move_button);
2851 mouse_mode_size_group->add_widget (mouse_select_button);
2852 mouse_mode_size_group->add_widget (mouse_zoom_button);
2853 mouse_mode_size_group->add_widget (mouse_gain_button);
2854 mouse_mode_size_group->add_widget (mouse_timefx_button);
2855 mouse_mode_size_group->add_widget (mouse_audition_button);
2856 mouse_mode_size_group->add_widget (mouse_draw_button);
2857 mouse_mode_size_group->add_widget (internal_edit_button);
2859 /* make them just a bit bigger */
2860 mouse_move_button.set_size_request (-1, 25);
2862 mouse_mode_hbox->set_spacing (2);
2864 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2865 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2866 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2867 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2868 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2872 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2874 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2876 mouse_mode_align->add (*mouse_mode_vbox);
2877 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2879 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2881 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2882 if (!Profile->get_sae()) {
2883 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2885 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2887 edit_mode_selector.set_name ("EditModeSelector");
2888 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2889 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2891 mode_box->pack_start (edit_mode_selector, false, false);
2892 mode_box->pack_start (*mouse_mode_box, false, false);
2894 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2895 _mouse_mode_tearoff->set_name ("MouseModeBase");
2896 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2898 if (Profile->get_sae()) {
2899 _mouse_mode_tearoff->set_can_be_torn_off (false);
2902 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2903 &_mouse_mode_tearoff->tearoff_window()));
2904 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2905 &_mouse_mode_tearoff->tearoff_window(), 1));
2906 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2907 &_mouse_mode_tearoff->tearoff_window()));
2908 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2909 &_mouse_mode_tearoff->tearoff_window(), 1));
2913 _zoom_box.set_spacing (2);
2914 _zoom_box.set_border_width (2);
2918 zoom_in_button.set_name ("zoom button");
2919 zoom_in_button.add (*(manage (new Image (::get_icon ("zoom_in")))));
2920 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2921 act->connect_proxy (zoom_in_button);
2923 zoom_out_button.set_name ("zoom button");
2924 zoom_out_button.add (*(manage (new Image (::get_icon ("zoom_out")))));
2925 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2926 act->connect_proxy (zoom_out_button);
2928 zoom_out_full_button.set_name ("zoom button");
2929 zoom_out_full_button.add (*(manage (new Image (::get_icon ("zoom_full")))));
2930 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2931 act->connect_proxy (zoom_out_full_button);
2933 zoom_focus_selector.set_name ("ZoomFocusSelector");
2934 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2935 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2937 _zoom_box.pack_start (zoom_out_button, false, false);
2938 _zoom_box.pack_start (zoom_in_button, false, false);
2939 _zoom_box.pack_start (zoom_out_full_button, false, false);
2941 _zoom_box.pack_start (zoom_focus_selector, false, false);
2943 /* Track zoom buttons */
2944 tav_expand_button.set_name ("TrackHeightButton");
2945 tav_expand_button.set_size_request (-1, 20);
2946 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2947 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2948 act->connect_proxy (tav_expand_button);
2950 tav_shrink_button.set_name ("TrackHeightButton");
2951 tav_shrink_button.set_size_request (-1, 20);
2952 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2953 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2954 act->connect_proxy (tav_shrink_button);
2956 _zoom_box.pack_start (tav_shrink_button);
2957 _zoom_box.pack_start (tav_expand_button);
2959 _zoom_tearoff = manage (new TearOff (_zoom_box));
2961 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2962 &_zoom_tearoff->tearoff_window()));
2963 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2964 &_zoom_tearoff->tearoff_window(), 0));
2965 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2966 &_zoom_tearoff->tearoff_window()));
2967 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2968 &_zoom_tearoff->tearoff_window(), 0));
2970 snap_box.set_spacing (1);
2971 snap_box.set_border_width (2);
2973 snap_type_selector.set_name ("SnapTypeSelector");
2974 set_popdown_strings (snap_type_selector, snap_type_strings);
2975 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2977 snap_mode_selector.set_name ("SnapModeSelector");
2978 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2979 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2981 edit_point_selector.set_name ("EditPointSelector");
2982 set_popdown_strings (edit_point_selector, edit_point_strings);
2983 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2985 snap_box.pack_start (snap_mode_selector, false, false);
2986 snap_box.pack_start (snap_type_selector, false, false);
2987 snap_box.pack_start (edit_point_selector, false, false);
2991 HBox *nudge_box = manage (new HBox);
2992 nudge_box->set_spacing (2);
2993 nudge_box->set_border_width (2);
2995 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2996 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2998 nudge_box->pack_start (nudge_backward_button, false, false);
2999 nudge_box->pack_start (nudge_forward_button, false, false);
3000 nudge_box->pack_start (*nudge_clock, false, false);
3003 /* Pack everything in... */
3005 HBox* hbox = manage (new HBox);
3006 hbox->set_spacing(10);
3008 _tools_tearoff = manage (new TearOff (*hbox));
3009 _tools_tearoff->set_name ("MouseModeBase");
3010 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3012 if (Profile->get_sae()) {
3013 _tools_tearoff->set_can_be_torn_off (false);
3016 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3017 &_tools_tearoff->tearoff_window()));
3018 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3019 &_tools_tearoff->tearoff_window(), 0));
3020 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3021 &_tools_tearoff->tearoff_window()));
3022 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3023 &_tools_tearoff->tearoff_window(), 0));
3025 toolbar_hbox.set_spacing (10);
3026 toolbar_hbox.set_border_width (1);
3028 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3029 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3030 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3032 hbox->pack_start (snap_box, false, false);
3033 if (!Profile->get_small_screen()) {
3034 hbox->pack_start (*nudge_box, false, false);
3036 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3038 hbox->pack_start (panic_box, false, false);
3042 toolbar_base.set_name ("ToolBarBase");
3043 toolbar_base.add (toolbar_hbox);
3045 _toolbar_viewport.add (toolbar_base);
3046 /* stick to the required height but allow width to vary if there's not enough room */
3047 _toolbar_viewport.set_size_request (1, -1);
3049 toolbar_frame.set_shadow_type (SHADOW_OUT);
3050 toolbar_frame.set_name ("BaseFrame");
3051 toolbar_frame.add (_toolbar_viewport);
3055 Editor::setup_tooltips ()
3057 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3058 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3059 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3060 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3061 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3062 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3063 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3064 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3065 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3066 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3067 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3068 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3069 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3070 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3071 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3072 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3073 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3074 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3075 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3076 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3077 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3078 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3079 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3083 Editor::convert_drop_to_paths (
3084 vector<string>& paths,
3085 const RefPtr<Gdk::DragContext>& /*context*/,
3088 const SelectionData& data,
3092 if (_session == 0) {
3096 vector<string> uris = data.get_uris();
3100 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3101 are actually URI lists. So do it by hand.
3104 if (data.get_target() != "text/plain") {
3108 /* Parse the "uri-list" format that Nautilus provides,
3109 where each pathname is delimited by \r\n.
3111 THERE MAY BE NO NULL TERMINATING CHAR!!!
3114 string txt = data.get_text();
3118 p = (const char *) malloc (txt.length() + 1);
3119 txt.copy (const_cast<char *> (p), txt.length(), 0);
3120 const_cast<char*>(p)[txt.length()] = '\0';
3126 while (g_ascii_isspace (*p))
3130 while (*q && (*q != '\n') && (*q != '\r')) {
3137 while (q > p && g_ascii_isspace (*q))
3142 uris.push_back (string (p, q - p + 1));
3146 p = strchr (p, '\n');
3158 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3160 if ((*i).substr (0,7) == "file://") {
3162 string const p = PBD::url_decode (*i);
3164 // scan forward past three slashes
3166 string::size_type slashcnt = 0;
3167 string::size_type n = 0;
3168 string::const_iterator x = p.begin();
3170 while (slashcnt < 3 && x != p.end()) {
3173 } else if (slashcnt == 3) {
3180 if (slashcnt != 3 || x == p.end()) {
3181 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3185 paths.push_back (p.substr (n - 1));
3193 Editor::new_tempo_section ()
3199 Editor::map_transport_state ()
3201 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3203 if (_session && _session->transport_stopped()) {
3204 have_pending_keyboard_selection = false;
3207 update_loop_range_view (true);
3213 Editor::begin_reversible_command (string name)
3216 _session->begin_reversible_command (name);
3221 Editor::begin_reversible_command (GQuark q)
3224 _session->begin_reversible_command (q);
3229 Editor::commit_reversible_command ()
3232 _session->commit_reversible_command ();
3237 Editor::history_changed ()
3241 if (undo_action && _session) {
3242 if (_session->undo_depth() == 0) {
3243 label = S_("Command|Undo");
3245 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3247 undo_action->property_label() = label;
3250 if (redo_action && _session) {
3251 if (_session->redo_depth() == 0) {
3254 label = string_compose(_("Redo (%1)"), _session->next_redo());
3256 redo_action->property_label() = label;
3261 Editor::duplicate_range (bool with_dialog)
3265 RegionSelection rs = get_regions_from_selection_and_entered ();
3267 if ( selection->time.length() == 0 && rs.empty()) {
3273 ArdourDialog win (_("Duplicate"));
3274 Label label (_("Number of duplications:"));
3275 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3276 SpinButton spinner (adjustment, 0.0, 1);
3279 win.get_vbox()->set_spacing (12);
3280 win.get_vbox()->pack_start (hbox);
3281 hbox.set_border_width (6);
3282 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3284 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3285 place, visually. so do this by hand.
3288 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3289 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3290 spinner.grab_focus();
3296 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3297 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3298 win.set_default_response (RESPONSE_ACCEPT);
3300 win.set_position (WIN_POS_MOUSE);
3302 spinner.grab_focus ();
3304 switch (win.run ()) {
3305 case RESPONSE_ACCEPT:
3311 times = adjustment.get_value();
3314 if (selection->time.length() != 0) {
3315 duplicate_selection (times);
3317 duplicate_some_regions (rs, times);
3322 Editor::set_edit_mode (EditMode m)
3324 Config->set_edit_mode (m);
3328 Editor::cycle_edit_mode ()
3330 switch (Config->get_edit_mode()) {
3332 if (Profile->get_sae()) {
3333 Config->set_edit_mode (Lock);
3335 Config->set_edit_mode (Splice);
3339 Config->set_edit_mode (Lock);
3342 Config->set_edit_mode (Slide);
3348 Editor::edit_mode_selection_done ()
3350 string s = edit_mode_selector.get_active_text ();
3353 Config->set_edit_mode (string_to_edit_mode (s));
3358 Editor::snap_type_selection_done ()
3360 string choice = snap_type_selector.get_active_text();
3361 SnapType snaptype = SnapToBeat;
3363 if (choice == _("Beats/2")) {
3364 snaptype = SnapToBeatDiv2;
3365 } else if (choice == _("Beats/3")) {
3366 snaptype = SnapToBeatDiv3;
3367 } else if (choice == _("Beats/4")) {
3368 snaptype = SnapToBeatDiv4;
3369 } else if (choice == _("Beats/5")) {
3370 snaptype = SnapToBeatDiv5;
3371 } else if (choice == _("Beats/6")) {
3372 snaptype = SnapToBeatDiv6;
3373 } else if (choice == _("Beats/7")) {
3374 snaptype = SnapToBeatDiv7;
3375 } else if (choice == _("Beats/8")) {
3376 snaptype = SnapToBeatDiv8;
3377 } else if (choice == _("Beats/10")) {
3378 snaptype = SnapToBeatDiv10;
3379 } else if (choice == _("Beats/12")) {
3380 snaptype = SnapToBeatDiv12;
3381 } else if (choice == _("Beats/14")) {
3382 snaptype = SnapToBeatDiv14;
3383 } else if (choice == _("Beats/16")) {
3384 snaptype = SnapToBeatDiv16;
3385 } else if (choice == _("Beats/20")) {
3386 snaptype = SnapToBeatDiv20;
3387 } else if (choice == _("Beats/24")) {
3388 snaptype = SnapToBeatDiv24;
3389 } else if (choice == _("Beats/28")) {
3390 snaptype = SnapToBeatDiv28;
3391 } else if (choice == _("Beats/32")) {
3392 snaptype = SnapToBeatDiv32;
3393 } else if (choice == _("Beats/64")) {
3394 snaptype = SnapToBeatDiv64;
3395 } else if (choice == _("Beats/128")) {
3396 snaptype = SnapToBeatDiv128;
3397 } else if (choice == _("Beats")) {
3398 snaptype = SnapToBeat;
3399 } else if (choice == _("Bars")) {
3400 snaptype = SnapToBar;
3401 } else if (choice == _("Marks")) {
3402 snaptype = SnapToMark;
3403 } else if (choice == _("Region starts")) {
3404 snaptype = SnapToRegionStart;
3405 } else if (choice == _("Region ends")) {
3406 snaptype = SnapToRegionEnd;
3407 } else if (choice == _("Region bounds")) {
3408 snaptype = SnapToRegionBoundary;
3409 } else if (choice == _("Region syncs")) {
3410 snaptype = SnapToRegionSync;
3411 } else if (choice == _("CD Frames")) {
3412 snaptype = SnapToCDFrame;
3413 } else if (choice == _("Timecode Frames")) {
3414 snaptype = SnapToTimecodeFrame;
3415 } else if (choice == _("Timecode Seconds")) {
3416 snaptype = SnapToTimecodeSeconds;
3417 } else if (choice == _("Timecode Minutes")) {
3418 snaptype = SnapToTimecodeMinutes;
3419 } else if (choice == _("Seconds")) {
3420 snaptype = SnapToSeconds;
3421 } else if (choice == _("Minutes")) {
3422 snaptype = SnapToMinutes;
3425 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3427 ract->set_active ();
3432 Editor::snap_mode_selection_done ()
3434 string choice = snap_mode_selector.get_active_text();
3435 SnapMode mode = SnapNormal;
3437 if (choice == _("No Grid")) {
3439 } else if (choice == _("Grid")) {
3441 } else if (choice == _("Magnetic")) {
3442 mode = SnapMagnetic;
3445 RefPtr<RadioAction> ract = snap_mode_action (mode);
3448 ract->set_active (true);
3453 Editor::cycle_edit_point (bool with_marker)
3455 switch (_edit_point) {
3457 set_edit_point_preference (EditAtPlayhead);
3459 case EditAtPlayhead:
3461 set_edit_point_preference (EditAtSelectedMarker);
3463 set_edit_point_preference (EditAtMouse);
3466 case EditAtSelectedMarker:
3467 set_edit_point_preference (EditAtMouse);
3473 Editor::edit_point_selection_done ()
3475 string choice = edit_point_selector.get_active_text();
3476 EditPoint ep = EditAtSelectedMarker;
3478 if (choice == _("Marker")) {
3479 set_edit_point_preference (EditAtSelectedMarker);
3480 } else if (choice == _("Playhead")) {
3481 set_edit_point_preference (EditAtPlayhead);
3483 set_edit_point_preference (EditAtMouse);
3486 RefPtr<RadioAction> ract = edit_point_action (ep);
3489 ract->set_active (true);
3494 Editor::zoom_focus_selection_done ()
3496 string choice = zoom_focus_selector.get_active_text();
3497 ZoomFocus focus_type = ZoomFocusLeft;
3499 if (choice == _("Left")) {
3500 focus_type = ZoomFocusLeft;
3501 } else if (choice == _("Right")) {
3502 focus_type = ZoomFocusRight;
3503 } else if (choice == _("Center")) {
3504 focus_type = ZoomFocusCenter;
3505 } else if (choice == _("Playhead")) {
3506 focus_type = ZoomFocusPlayhead;
3507 } else if (choice == _("Mouse")) {
3508 focus_type = ZoomFocusMouse;
3509 } else if (choice == _("Edit point")) {
3510 focus_type = ZoomFocusEdit;
3513 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3516 ract->set_active ();
3521 Editor::edit_controls_button_release (GdkEventButton* ev)
3523 if (Keyboard::is_context_menu_event (ev)) {
3524 ARDOUR_UI::instance()->add_route (this);
3525 } else if (ev->button == 1) {
3526 selection->clear_tracks ();
3533 Editor::mouse_select_button_release (GdkEventButton* ev)
3535 /* this handles just right-clicks */
3537 if (ev->button != 3) {
3545 Editor::set_zoom_focus (ZoomFocus f)
3547 string str = zoom_focus_strings[(int)f];
3549 if (str != zoom_focus_selector.get_active_text()) {
3550 zoom_focus_selector.set_active_text (str);
3553 if (zoom_focus != f) {
3560 Editor::ensure_float (Window& win)
3562 win.set_transient_for (*this);
3566 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3568 /* recover or initialize pane positions. do this here rather than earlier because
3569 we don't want the positions to change the child allocations, which they seem to do.
3575 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3584 XMLNode* geometry = find_named_node (*node, "geometry");
3586 if (which == static_cast<Paned*> (&edit_pane)) {
3588 if (done & Horizontal) {
3592 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3593 _notebook_shrunk = string_is_affirmative (prop->value ());
3596 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3597 /* initial allocation is 90% to canvas, 10% to notebook */
3598 pos = (int) floor (alloc.get_width() * 0.90f);
3599 snprintf (buf, sizeof(buf), "%d", pos);
3601 pos = atoi (prop->value());
3604 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3605 edit_pane.set_position (pos);
3608 done = (Pane) (done | Horizontal);
3610 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3612 if (done & Vertical) {
3616 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3617 /* initial allocation is 90% to canvas, 10% to summary */
3618 pos = (int) floor (alloc.get_height() * 0.90f);
3619 snprintf (buf, sizeof(buf), "%d", pos);
3622 pos = atoi (prop->value());
3625 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3626 editor_summary_pane.set_position (pos);
3629 done = (Pane) (done | Vertical);
3634 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3636 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3637 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3638 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3639 top_hbox.remove (toolbar_frame);
3644 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3646 if (toolbar_frame.get_parent() == 0) {
3647 top_hbox.pack_end (toolbar_frame);
3652 Editor::set_show_measures (bool yn)
3654 if (_show_measures != yn) {
3657 if ((_show_measures = yn) == true) {
3659 tempo_lines->show();
3661 (void) redraw_measures ();
3668 Editor::toggle_follow_playhead ()
3670 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3672 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3673 set_follow_playhead (tact->get_active());
3677 /** @param yn true to follow playhead, otherwise false.
3678 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3681 Editor::set_follow_playhead (bool yn, bool catch_up)
3683 if (_follow_playhead != yn) {
3684 if ((_follow_playhead = yn) == true && catch_up) {
3686 reset_x_origin_to_follow_playhead ();
3693 Editor::toggle_stationary_playhead ()
3695 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3697 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3698 set_stationary_playhead (tact->get_active());
3703 Editor::set_stationary_playhead (bool yn)
3705 if (_stationary_playhead != yn) {
3706 if ((_stationary_playhead = yn) == true) {
3708 // FIXME need a 3.0 equivalent of this 2.X call
3709 // update_current_screen ();
3716 Editor::playlist_selector () const
3718 return *_playlist_selector;
3722 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3726 switch (_snap_type) {
3731 case SnapToBeatDiv128:
3734 case SnapToBeatDiv64:
3737 case SnapToBeatDiv32:
3740 case SnapToBeatDiv28:
3743 case SnapToBeatDiv24:
3746 case SnapToBeatDiv20:
3749 case SnapToBeatDiv16:
3752 case SnapToBeatDiv14:
3755 case SnapToBeatDiv12:
3758 case SnapToBeatDiv10:
3761 case SnapToBeatDiv8:
3764 case SnapToBeatDiv7:
3767 case SnapToBeatDiv6:
3770 case SnapToBeatDiv5:
3773 case SnapToBeatDiv4:
3776 case SnapToBeatDiv3:
3779 case SnapToBeatDiv2:
3785 return _session->tempo_map().meter_at (position).divisions_per_bar();
3790 case SnapToTimecodeFrame:
3791 case SnapToTimecodeSeconds:
3792 case SnapToTimecodeMinutes:
3795 case SnapToRegionStart:
3796 case SnapToRegionEnd:
3797 case SnapToRegionSync:
3798 case SnapToRegionBoundary:
3808 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3812 ret = nudge_clock->current_duration (pos);
3813 next = ret + 1; /* XXXX fix me */
3819 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3821 ArdourDialog dialog (_("Playlist Deletion"));
3822 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3823 "If it is kept, its audio files will not be cleaned.\n"
3824 "If it is deleted, audio files used by it alone will be cleaned."),
3827 dialog.set_position (WIN_POS_CENTER);
3828 dialog.get_vbox()->pack_start (label);
3832 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3833 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3834 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3836 switch (dialog.run ()) {
3837 case RESPONSE_ACCEPT:
3838 /* delete the playlist */
3842 case RESPONSE_REJECT:
3843 /* keep the playlist */
3855 Editor::audio_region_selection_covers (framepos_t where)
3857 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3858 if ((*a)->region()->covers (where)) {
3867 Editor::prepare_for_cleanup ()
3869 cut_buffer->clear_regions ();
3870 cut_buffer->clear_playlists ();
3872 selection->clear_regions ();
3873 selection->clear_playlists ();
3875 _regions->suspend_redisplay ();
3879 Editor::finish_cleanup ()
3881 _regions->resume_redisplay ();
3885 Editor::transport_loop_location()
3888 return _session->locations()->auto_loop_location();
3895 Editor::transport_punch_location()
3898 return _session->locations()->auto_punch_location();
3905 Editor::control_layout_scroll (GdkEventScroll* ev)
3907 if (Keyboard::some_magic_widget_has_focus()) {
3911 switch (ev->direction) {
3913 scroll_tracks_up_line ();
3917 case GDK_SCROLL_DOWN:
3918 scroll_tracks_down_line ();
3922 /* no left/right handling yet */
3930 Editor::session_state_saved (string)
3933 _snapshots->redisplay ();
3937 Editor::update_tearoff_visibility()
3939 bool visible = Config->get_keep_tearoffs();
3940 _mouse_mode_tearoff->set_visible (visible);
3941 _tools_tearoff->set_visible (visible);
3942 _zoom_tearoff->set_visible (visible);
3946 Editor::maximise_editing_space ()
3958 Editor::restore_editing_space ()
3970 * Make new playlists for a given track and also any others that belong
3971 * to the same active route group with the `edit' property.
3976 Editor::new_playlists (TimeAxisView* v)
3978 begin_reversible_command (_("new playlists"));
3979 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3980 _session->playlists->get (playlists);
3981 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3982 commit_reversible_command ();
3986 * Use a copy of the current playlist for a given track and also any others that belong
3987 * to the same active route group with the `edit' property.
3992 Editor::copy_playlists (TimeAxisView* v)
3994 begin_reversible_command (_("copy playlists"));
3995 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3996 _session->playlists->get (playlists);
3997 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3998 commit_reversible_command ();
4001 /** Clear the current playlist for a given track and also any others that belong
4002 * to the same active route group with the `edit' property.
4007 Editor::clear_playlists (TimeAxisView* v)
4009 begin_reversible_command (_("clear playlists"));
4010 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4011 _session->playlists->get (playlists);
4012 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4013 commit_reversible_command ();
4017 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4019 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4023 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4025 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4029 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4031 atv.clear_playlist ();
4035 Editor::on_key_press_event (GdkEventKey* ev)
4037 return key_press_focus_accelerator_handler (*this, ev);
4041 Editor::on_key_release_event (GdkEventKey* ev)
4043 return Gtk::Window::on_key_release_event (ev);
4044 // return key_press_focus_accelerator_handler (*this, ev);
4047 /** Queue up a change to the viewport x origin.
4048 * @param frame New x origin.
4051 Editor::reset_x_origin (framepos_t frame)
4053 pending_visual_change.add (VisualChange::TimeOrigin);
4054 pending_visual_change.time_origin = frame;
4055 ensure_visual_change_idle_handler ();
4059 Editor::reset_y_origin (double y)
4061 pending_visual_change.add (VisualChange::YOrigin);
4062 pending_visual_change.y_origin = y;
4063 ensure_visual_change_idle_handler ();
4067 Editor::reset_zoom (double fpu)
4069 clamp_frames_per_unit (fpu);
4071 if (fpu == frames_per_unit) {
4075 pending_visual_change.add (VisualChange::ZoomLevel);
4076 pending_visual_change.frames_per_unit = fpu;
4077 ensure_visual_change_idle_handler ();
4081 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4083 reset_x_origin (frame);
4086 if (!no_save_visual) {
4087 undo_visual_stack.push_back (current_visual_state(false));
4091 Editor::VisualState::VisualState (bool with_tracks)
4092 : gui_state (with_tracks ? new GUIObjectState : 0)
4096 Editor::VisualState::~VisualState ()
4101 Editor::VisualState*
4102 Editor::current_visual_state (bool with_tracks)
4104 VisualState* vs = new VisualState (with_tracks);
4105 vs->y_position = vertical_adjustment.get_value();
4106 vs->frames_per_unit = frames_per_unit;
4107 vs->leftmost_frame = leftmost_frame;
4108 vs->zoom_focus = zoom_focus;
4111 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4118 Editor::undo_visual_state ()
4120 if (undo_visual_stack.empty()) {
4124 VisualState* vs = undo_visual_stack.back();
4125 undo_visual_stack.pop_back();
4128 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4130 use_visual_state (*vs);
4134 Editor::redo_visual_state ()
4136 if (redo_visual_stack.empty()) {
4140 VisualState* vs = redo_visual_stack.back();
4141 redo_visual_stack.pop_back();
4143 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4145 use_visual_state (*vs);
4149 Editor::swap_visual_state ()
4151 if (undo_visual_stack.empty()) {
4152 redo_visual_state ();
4154 undo_visual_state ();
4159 Editor::use_visual_state (VisualState& vs)
4161 PBD::Unwinder<bool> nsv (no_save_visual, true);
4163 _routes->suspend_redisplay ();
4165 vertical_adjustment.set_value (vs.y_position);
4167 set_zoom_focus (vs.zoom_focus);
4168 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4171 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4173 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4174 (*i)->reset_visual_state ();
4178 _routes->update_visibility ();
4179 _routes->resume_redisplay ();
4182 /** This is the core function that controls the zoom level of the canvas. It is called
4183 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4184 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4187 Editor::set_frames_per_unit (double fpu)
4190 tempo_lines->tempo_map_changed();
4193 frames_per_unit = fpu;
4195 /* convert fpu to frame count */
4197 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4199 if (frames_per_unit != zoom_range_clock->current_duration()) {
4200 zoom_range_clock->set (frames);
4203 bool const showing_time_selection = selection->time.length() > 0;
4205 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4206 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4207 (*i)->reshow_selection (selection->time);
4211 ZoomChanged (); /* EMIT_SIGNAL */
4213 //reset_scrolling_region ();
4215 if (playhead_cursor) {
4216 playhead_cursor->set_position (playhead_cursor->current_frame);
4219 refresh_location_display();
4220 _summary->set_overlays_dirty ();
4222 update_marker_labels ();
4228 Editor::ensure_visual_change_idle_handler ()
4230 if (pending_visual_change.idle_handler_id < 0) {
4231 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4236 Editor::_idle_visual_changer (void* arg)
4238 return static_cast<Editor*>(arg)->idle_visual_changer ();
4242 Editor::idle_visual_changer ()
4244 /* set_horizontal_position() below (and maybe other calls) call
4245 gtk_main_iteration(), so it's possible that a signal will be handled
4246 half-way through this method. If this signal wants an
4247 idle_visual_changer we must schedule another one after this one, so
4248 mark the idle_handler_id as -1 here to allow that. Also make a note
4249 that we are doing the visual change, so that changes in response to
4250 super-rapid-screen-update can be dropped if we are still processing
4254 pending_visual_change.idle_handler_id = -1;
4255 pending_visual_change.being_handled = true;
4257 VisualChange::Type p = pending_visual_change.pending;
4258 pending_visual_change.pending = (VisualChange::Type) 0;
4260 double const last_time_origin = horizontal_position ();
4262 if (p & VisualChange::ZoomLevel) {
4263 set_frames_per_unit (pending_visual_change.frames_per_unit);
4265 compute_fixed_ruler_scale ();
4267 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4268 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4270 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4271 current_bbt_points_begin, current_bbt_points_end);
4272 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4273 current_bbt_points_begin, current_bbt_points_end);
4274 update_tempo_based_rulers (current_bbt_points_end, current_bbt_points_begin);
4276 if (p & VisualChange::TimeOrigin) {
4277 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4279 if (p & VisualChange::YOrigin) {
4280 vertical_adjustment.set_value (pending_visual_change.y_origin);
4283 if (last_time_origin == horizontal_position ()) {
4284 /* changed signal not emitted */
4285 update_fixed_rulers ();
4286 redisplay_tempo (true);
4289 _summary->set_overlays_dirty ();
4291 pending_visual_change.being_handled = false;
4292 return 0; /* this is always a one-shot call */
4295 struct EditorOrderTimeAxisSorter {
4296 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4297 return a->order () < b->order ();
4302 Editor::sort_track_selection (TrackViewList& sel)
4304 EditorOrderTimeAxisSorter cmp;
4309 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4312 framepos_t where = 0;
4313 EditPoint ep = _edit_point;
4315 if (from_context_menu && (ep == EditAtMouse)) {
4316 return event_frame (&context_click_event, 0, 0);
4319 if (entered_marker) {
4320 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4321 return entered_marker->position();
4324 if (ignore_playhead && ep == EditAtPlayhead) {
4325 ep = EditAtSelectedMarker;
4329 case EditAtPlayhead:
4330 where = _session->audible_frame();
4331 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4334 case EditAtSelectedMarker:
4335 if (!selection->markers.empty()) {
4337 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4340 where = loc->start();
4344 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4352 if (!mouse_frame (where, ignored)) {
4353 /* XXX not right but what can we do ? */
4357 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4365 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4367 if (!_session) return;
4369 begin_reversible_command (cmd);
4373 if ((tll = transport_loop_location()) == 0) {
4374 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4375 XMLNode &before = _session->locations()->get_state();
4376 _session->locations()->add (loc, true);
4377 _session->set_auto_loop_location (loc);
4378 XMLNode &after = _session->locations()->get_state();
4379 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4381 XMLNode &before = tll->get_state();
4382 tll->set_hidden (false, this);
4383 tll->set (start, end);
4384 XMLNode &after = tll->get_state();
4385 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4388 commit_reversible_command ();
4392 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4394 if (!_session) return;
4396 begin_reversible_command (cmd);
4400 if ((tpl = transport_punch_location()) == 0) {
4401 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4402 XMLNode &before = _session->locations()->get_state();
4403 _session->locations()->add (loc, true);
4404 _session->set_auto_loop_location (loc);
4405 XMLNode &after = _session->locations()->get_state();
4406 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4409 XMLNode &before = tpl->get_state();
4410 tpl->set_hidden (false, this);
4411 tpl->set (start, end);
4412 XMLNode &after = tpl->get_state();
4413 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4416 commit_reversible_command ();
4419 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4420 * @param rs List to which found regions are added.
4421 * @param where Time to look at.
4422 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4425 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4427 const TrackViewList* tracks;
4430 tracks = &track_views;
4435 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4437 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4440 boost::shared_ptr<Track> tr;
4441 boost::shared_ptr<Playlist> pl;
4443 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4445 boost::shared_ptr<RegionList> regions = pl->regions_at (
4446 (framepos_t) floor ( (double) where * tr->speed()));
4448 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4449 RegionView* rv = rtv->view()->find_view (*i);
4460 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4462 const TrackViewList* tracks;
4465 tracks = &track_views;
4470 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4471 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4473 boost::shared_ptr<Track> tr;
4474 boost::shared_ptr<Playlist> pl;
4476 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4478 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4479 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4481 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4483 RegionView* rv = rtv->view()->find_view (*i);
4494 /** Start with regions that are selected. Then add equivalent regions
4495 * on tracks in the same active edit-enabled route group as any of
4496 * the regions that we started with.
4500 Editor::get_regions_from_selection ()
4502 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4505 /** Get regions using the following method:
4507 * Make an initial region list using the selected regions, unless
4508 * the edit point is `mouse' and the mouse is over an unselected
4509 * region. In this case, start with just that region.
4511 * Then, add equivalent regions in active edit groups to the region list.
4513 * Then, search the list of selected tracks to find any selected tracks which
4514 * do not contain regions already in the region list. If there are no selected
4515 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4516 * than just the selected.
4518 * Add any regions that are under the edit point on these tracks to get the
4519 * returned region list.
4521 * The rationale here is that the mouse edit point is special in that
4522 * its position describes both a time and a track; the other edit
4523 * modes only describe a time. Hence if the edit point is `mouse' we
4524 * ignore selected tracks, as we assume the user means something by
4525 * pointing at a particular track. Also in this case we take note of
4526 * the region directly under the edit point, as there is always just one
4527 * (rather than possibly several with non-mouse edit points).
4531 Editor::get_regions_from_selection_and_edit_point ()
4533 RegionSelection regions;
4535 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4536 regions.add (entered_regionview);
4538 regions = selection->regions;
4541 TrackViewList tracks;
4543 if (_edit_point != EditAtMouse) {
4544 tracks = selection->tracks;
4547 /* Add any other regions that are in the same
4548 edit-activated route group as one of our regions.
4550 regions = get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4551 framepos_t const where = get_preferred_edit_position ();
4553 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4554 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4555 * is enabled, so consider all tracks
4557 tracks = track_views;
4560 if (!tracks.empty()) {
4561 /* now search the selected tracks for tracks which don't
4562 already contain regions to be acted upon, and get regions at
4563 the edit point on those tracks too.
4565 TrackViewList tracks_without_relevant_regions;
4567 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4568 if (!regions.involves (**t)) {
4569 /* there are no equivalent regions on this track */
4570 tracks_without_relevant_regions.push_back (*t);
4574 if (!tracks_without_relevant_regions.empty()) {
4575 /* there are some selected tracks with neither selected
4576 * regions or their equivalents: act upon all regions in
4579 get_regions_at (regions, where, tracks_without_relevant_regions);
4586 /** Start with regions that are selected, or the entered regionview if none are selected.
4587 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4588 * of the regions that we started with.
4592 Editor::get_regions_from_selection_and_entered ()
4594 RegionSelection regions = selection->regions;
4596 if (regions.empty() && entered_regionview) {
4597 regions.add (entered_regionview);
4600 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4604 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4606 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4608 RouteTimeAxisView* tatv;
4610 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4612 boost::shared_ptr<Playlist> pl;
4613 vector<boost::shared_ptr<Region> > results;
4615 boost::shared_ptr<Track> tr;
4617 if ((tr = tatv->track()) == 0) {
4622 if ((pl = (tr->playlist())) != 0) {
4623 pl->get_region_list_equivalent_regions (region, results);
4626 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4627 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4628 regions.push_back (marv);
4637 Editor::show_rhythm_ferret ()
4639 if (rhythm_ferret == 0) {
4640 rhythm_ferret = new RhythmFerret(*this);
4643 rhythm_ferret->set_session (_session);
4644 rhythm_ferret->show ();
4645 rhythm_ferret->present ();
4649 Editor::first_idle ()
4651 MessageDialog* dialog = 0;
4653 if (track_views.size() > 1) {
4654 dialog = new MessageDialog (
4656 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4660 ARDOUR_UI::instance()->flush_pending ();
4663 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4667 // first idle adds route children (automation tracks), so we need to redisplay here
4668 _routes->redisplay ();
4675 Editor::_idle_resize (gpointer arg)
4677 return ((Editor*)arg)->idle_resize ();
4681 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4683 if (resize_idle_id < 0) {
4684 resize_idle_id = g_idle_add (_idle_resize, this);
4685 _pending_resize_amount = 0;
4688 /* make a note of the smallest resulting height, so that we can clamp the
4689 lower limit at TimeAxisView::hSmall */
4691 int32_t min_resulting = INT32_MAX;
4693 _pending_resize_amount += h;
4694 _pending_resize_view = view;
4696 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4698 if (selection->tracks.contains (_pending_resize_view)) {
4699 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4700 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4704 if (min_resulting < 0) {
4709 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4710 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4714 /** Handle pending resizing of tracks */
4716 Editor::idle_resize ()
4718 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4720 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4721 selection->tracks.contains (_pending_resize_view)) {
4723 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4724 if (*i != _pending_resize_view) {
4725 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4730 _pending_resize_amount = 0;
4732 _group_tabs->set_dirty ();
4733 resize_idle_id = -1;
4741 ENSURE_GUI_THREAD (*this, &Editor::located);
4744 playhead_cursor->set_position (_session->audible_frame ());
4745 if (_follow_playhead && !_pending_initial_locate) {
4746 reset_x_origin_to_follow_playhead ();
4750 _pending_locate_request = false;
4751 _pending_initial_locate = false;
4755 Editor::region_view_added (RegionView *)
4757 _summary->set_dirty ();
4761 Editor::region_view_removed ()
4763 _summary->set_dirty ();
4767 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4769 TrackViewList::const_iterator j = track_views.begin ();
4770 while (j != track_views.end()) {
4771 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4772 if (rtv && rtv->route() == r) {
4783 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4787 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4788 TimeAxisView* tv = axis_view_from_route (*i);
4798 Editor::add_routes (RouteList& routes)
4800 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4802 RouteTimeAxisView *rtv;
4803 list<RouteTimeAxisView*> new_views;
4805 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4806 boost::shared_ptr<Route> route = (*x);
4808 if (route->is_hidden() || route->is_monitor()) {
4812 DataType dt = route->input()->default_type();
4814 if (dt == ARDOUR::DataType::AUDIO) {
4815 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4816 rtv->set_route (route);
4817 } else if (dt == ARDOUR::DataType::MIDI) {
4818 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4819 rtv->set_route (route);
4821 throw unknown_type();
4824 new_views.push_back (rtv);
4825 track_views.push_back (rtv);
4827 rtv->effective_gain_display ();
4829 if (internal_editing()) {
4830 rtv->enter_internal_edit_mode ();
4832 rtv->leave_internal_edit_mode ();
4835 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4836 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4839 _routes->routes_added (new_views);
4840 _summary->routes_added (new_views);
4842 if (show_editor_mixer_when_tracks_arrive) {
4843 show_editor_mixer (true);
4846 editor_list_button.set_sensitive (true);
4850 Editor::timeaxisview_deleted (TimeAxisView *tv)
4852 if (_session && _session->deletion_in_progress()) {
4853 /* the situation is under control */
4857 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4859 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4861 _routes->route_removed (tv);
4863 if (tv == entered_track) {
4867 TimeAxisView::Children c = tv->get_child_list ();
4868 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4869 if (entered_track == i->get()) {
4874 /* remove it from the list of track views */
4876 TrackViewList::iterator i;
4878 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4879 i = track_views.erase (i);
4882 /* update whatever the current mixer strip is displaying, if revelant */
4884 boost::shared_ptr<Route> route;
4887 route = rtav->route ();
4890 if (current_mixer_strip && current_mixer_strip->route() == route) {
4892 TimeAxisView* next_tv;
4894 if (track_views.empty()) {
4896 } else if (i == track_views.end()) {
4897 next_tv = track_views.front();
4904 set_selected_mixer_strip (*next_tv);
4906 /* make the editor mixer strip go away setting the
4907 * button to inactive (which also unticks the menu option)
4910 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4916 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4918 if (apply_to_selection) {
4919 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4921 TrackSelection::iterator j = i;
4924 hide_track_in_display (*i, false);
4929 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4931 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4932 // this will hide the mixer strip
4933 set_selected_mixer_strip (*tv);
4936 _routes->hide_track_in_display (*tv);
4941 Editor::sync_track_view_list_and_routes ()
4943 track_views = TrackViewList (_routes->views ());
4945 _summary->set_dirty ();
4946 _group_tabs->set_dirty ();
4948 return false; // do not call again (until needed)
4952 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4954 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4959 /** Find a RouteTimeAxisView by the ID of its route */
4961 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4963 RouteTimeAxisView* v;
4965 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4966 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4967 if(v->route()->id() == id) {
4977 Editor::fit_route_group (RouteGroup *g)
4979 TrackViewList ts = axis_views_from_routes (g->route_list ());
4984 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4986 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4989 _session->cancel_audition ();
4993 if (_session->is_auditioning()) {
4994 _session->cancel_audition ();
4995 if (r == last_audition_region) {
5000 _session->audition_region (r);
5001 last_audition_region = r;
5006 Editor::hide_a_region (boost::shared_ptr<Region> r)
5008 r->set_hidden (true);
5012 Editor::show_a_region (boost::shared_ptr<Region> r)
5014 r->set_hidden (false);
5018 Editor::audition_region_from_region_list ()
5020 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5024 Editor::hide_region_from_region_list ()
5026 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5030 Editor::show_region_in_region_list ()
5032 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5036 Editor::step_edit_status_change (bool yn)
5039 start_step_editing ();
5041 stop_step_editing ();
5046 Editor::start_step_editing ()
5048 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5052 Editor::stop_step_editing ()
5054 step_edit_connection.disconnect ();
5058 Editor::check_step_edit ()
5060 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5061 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5063 mtv->check_step_edit ();
5067 return true; // do it again, till we stop
5071 Editor::scroll_press (Direction dir)
5073 ++_scroll_callbacks;
5075 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5076 /* delay the first auto-repeat */
5082 scroll_backward (1);
5090 scroll_tracks_up_line ();
5094 scroll_tracks_down_line ();
5098 /* do hacky auto-repeat */
5099 if (!_scroll_connection.connected ()) {
5101 _scroll_connection = Glib::signal_timeout().connect (
5102 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5105 _scroll_callbacks = 0;
5112 Editor::scroll_release ()
5114 _scroll_connection.disconnect ();
5117 /** Queue a change for the Editor viewport x origin to follow the playhead */
5119 Editor::reset_x_origin_to_follow_playhead ()
5121 framepos_t const frame = playhead_cursor->current_frame;
5123 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5125 if (_session->transport_speed() < 0) {
5127 if (frame > (current_page_frames() / 2)) {
5128 center_screen (frame-(current_page_frames()/2));
5130 center_screen (current_page_frames()/2);
5137 if (frame < leftmost_frame) {
5139 if (_session->transport_rolling()) {
5140 /* rolling; end up with the playhead at the right of the page */
5141 l = frame - current_page_frames ();
5143 /* not rolling: end up with the playhead 1/4 of the way along the page */
5144 l = frame - current_page_frames() / 4;
5148 if (_session->transport_rolling()) {
5149 /* rolling: end up with the playhead on the left of the page */
5152 /* not rolling: end up with the playhead 3/4 of the way along the page */
5153 l = frame - 3 * current_page_frames() / 4;
5161 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5167 Editor::super_rapid_screen_update ()
5169 if (!_session || !_session->engine().running()) {
5173 /* METERING / MIXER STRIPS */
5175 /* update track meters, if required */
5176 if (is_mapped() && meters_running) {
5177 RouteTimeAxisView* rtv;
5178 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5179 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5180 rtv->fast_update ();
5185 /* and any current mixer strip */
5186 if (current_mixer_strip) {
5187 current_mixer_strip->fast_update ();
5190 /* PLAYHEAD AND VIEWPORT */
5192 framepos_t const frame = _session->audible_frame();
5194 /* There are a few reasons why we might not update the playhead / viewport stuff:
5196 * 1. we don't update things when there's a pending locate request, otherwise
5197 * when the editor requests a locate there is a chance that this method
5198 * will move the playhead before the locate request is processed, causing
5200 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5201 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5204 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5206 last_update_frame = frame;
5208 if (!_dragging_playhead) {
5209 playhead_cursor->set_position (frame);
5212 if (!_stationary_playhead) {
5214 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5215 /* We only do this if we aren't already
5216 handling a visual change (ie if
5217 pending_visual_change.being_handled is
5218 false) so that these requests don't stack
5219 up there are too many of them to handle in
5222 reset_x_origin_to_follow_playhead ();
5227 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5231 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5232 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5233 if (target <= 0.0) {
5236 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5237 target = (target * 0.15) + (current * 0.85);
5243 set_horizontal_position (current);
5252 Editor::session_going_away ()
5254 _have_idled = false;
5256 _session_connections.drop_connections ();
5258 super_rapid_screen_update_connection.disconnect ();
5260 selection->clear ();
5261 cut_buffer->clear ();
5263 clicked_regionview = 0;
5264 clicked_axisview = 0;
5265 clicked_routeview = 0;
5266 entered_regionview = 0;
5268 last_update_frame = 0;
5271 playhead_cursor->canvas_item.hide ();
5273 /* rip everything out of the list displays */
5277 _route_groups->clear ();
5279 /* do this first so that deleting a track doesn't reset cms to null
5280 and thus cause a leak.
5283 if (current_mixer_strip) {
5284 if (current_mixer_strip->get_parent() != 0) {
5285 global_hpacker.remove (*current_mixer_strip);
5287 delete current_mixer_strip;
5288 current_mixer_strip = 0;
5291 /* delete all trackviews */
5293 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5296 track_views.clear ();
5298 zoom_range_clock->set_session (0);
5299 nudge_clock->set_session (0);
5301 editor_list_button.set_active(false);
5302 editor_list_button.set_sensitive(false);
5304 /* clear tempo/meter rulers */
5305 remove_metric_marks ();
5307 clear_marker_display ();
5309 stop_step_editing ();
5311 /* get rid of any existing editor mixer strip */
5313 WindowTitle title(Glib::get_application_name());
5314 title += _("Editor");
5316 set_title (title.get_string());
5318 SessionHandlePtr::session_going_away ();
5323 Editor::show_editor_list (bool yn)
5326 _the_notebook.show ();
5328 _the_notebook.hide ();
5333 Editor::change_region_layering_order (bool from_context_menu)
5335 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5337 if (!clicked_routeview) {
5338 if (layering_order_editor) {
5339 layering_order_editor->hide ();
5344 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5350 boost::shared_ptr<Playlist> pl = track->playlist();
5356 if (layering_order_editor == 0) {
5357 layering_order_editor = new RegionLayeringOrderEditor (*this);
5358 layering_order_editor->set_position (WIN_POS_MOUSE);
5361 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5362 layering_order_editor->maybe_present ();
5366 Editor::update_region_layering_order_editor ()
5368 if (layering_order_editor && layering_order_editor->is_visible ()) {
5369 change_region_layering_order (true);
5374 Editor::setup_fade_images ()
5376 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5377 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5378 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5379 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5380 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5382 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5383 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5384 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5385 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5386 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5388 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5389 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5390 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5391 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5392 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5394 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5395 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5396 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5397 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5398 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5402 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5404 Editor::action_menu_item (std::string const & name)
5406 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5409 return *manage (a->create_menu_item ());
5413 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5415 EventBox* b = manage (new EventBox);
5416 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5417 Label* l = manage (new Label (name));
5421 _the_notebook.append_page (widget, *b);
5425 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5427 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5428 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5431 if (ev->type == GDK_2BUTTON_PRESS) {
5433 /* double-click on a notebook tab shrinks or expands the notebook */
5435 if (_notebook_shrunk) {
5436 if (pre_notebook_shrink_pane_width) {
5437 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5439 _notebook_shrunk = false;
5441 pre_notebook_shrink_pane_width = edit_pane.get_position();
5443 /* this expands the LHS of the edit pane to cover the notebook
5444 PAGE but leaves the tabs visible.
5446 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5447 _notebook_shrunk = true;
5455 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5457 using namespace Menu_Helpers;
5459 MenuList& items = _control_point_context_menu.items ();
5462 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5463 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5464 if (!can_remove_control_point (item)) {
5465 items.back().set_sensitive (false);
5468 _control_point_context_menu.popup (event->button.button, event->button.time);
5472 Editor::shift_key_released ()
5474 _stepping_axis_view = 0;