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"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "control_protocol/control_protocol.h"
77 #include "analysis_window.h"
78 #include "audio_clock.h"
79 #include "audio_region_view.h"
80 #include "audio_streamview.h"
81 #include "audio_time_axis.h"
82 #include "automation_time_axis.h"
83 #include "bundle_manager.h"
84 #include "canvas-noevent-text.h"
85 #include "canvas_impl.h"
86 #include "crossfade_edit.h"
90 #include "editor_cursors.h"
91 #include "editor_drag.h"
92 #include "editor_group_tabs.h"
93 #include "editor_locations.h"
94 #include "editor_regions.h"
95 #include "editor_route_groups.h"
96 #include "editor_routes.h"
97 #include "editor_snapshots.h"
98 #include "editor_summary.h"
99 #include "global_port_matrix.h"
100 #include "gui_object.h"
101 #include "gui_thread.h"
102 #include "keyboard.h"
104 #include "midi_time_axis.h"
105 #include "mixer_strip.h"
106 #include "mixer_ui.h"
107 #include "mouse_cursors.h"
108 #include "playlist_selector.h"
109 #include "public_editor.h"
110 #include "region_layering_order_editor.h"
111 #include "rgb_macros.h"
112 #include "rhythm_ferret.h"
113 #include "selection.h"
115 #include "simpleline.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 , edit_packer (4, 4, true)
251 /* the values here don't matter: layout widgets
252 reset them as needed.
255 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
257 /* tool bar related */
259 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
261 , toolbar_selection_clock_table (2,3)
263 , automation_mode_button (_("mode"))
265 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
268 , image_socket_listener(0)
273 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
274 , meters_running(false)
275 , _pending_locate_request (false)
276 , _pending_initial_locate (false)
277 , _last_cut_copy_source_track (0)
279 , _region_selection_change_updates_region_list (true)
280 , _following_mixer_selection (false)
281 , _control_point_toggled_on_press (false)
282 , _stepping_axis_view (0)
286 /* we are a singleton */
288 PublicEditor::_instance = this;
292 selection = new Selection (this);
293 cut_buffer = new Selection (this);
295 clicked_regionview = 0;
296 clicked_axisview = 0;
297 clicked_routeview = 0;
298 clicked_control_point = 0;
299 last_update_frame = 0;
300 pre_press_cursor = 0;
301 _drags = new DragManager (this);
302 current_mixer_strip = 0;
305 snap_type_strings = I18N (_snap_type_strings);
306 snap_mode_strings = I18N (_snap_mode_strings);
307 zoom_focus_strings = I18N (_zoom_focus_strings);
308 edit_point_strings = I18N (_edit_point_strings);
309 #ifdef USE_RUBBERBAND
310 rb_opt_strings = I18N (_rb_opt_strings);
314 snap_threshold = 5.0;
315 bbt_beat_subdivision = 4;
318 last_autoscroll_x = 0;
319 last_autoscroll_y = 0;
320 autoscroll_active = false;
321 autoscroll_timeout_tag = -1;
326 current_interthread_info = 0;
327 _show_measures = true;
329 show_gain_after_trim = false;
331 have_pending_keyboard_selection = false;
332 _follow_playhead = true;
333 _stationary_playhead = false;
334 editor_ruler_menu = 0;
335 no_ruler_shown_update = false;
337 range_marker_menu = 0;
338 marker_menu_item = 0;
339 tempo_or_meter_marker_menu = 0;
340 transport_marker_menu = 0;
341 new_transport_marker_menu = 0;
342 editor_mixer_strip_width = Wide;
343 show_editor_mixer_when_tracks_arrive = false;
344 region_edit_menu_split_multichannel_item = 0;
345 region_edit_menu_split_item = 0;
348 current_stepping_trackview = 0;
350 entered_regionview = 0;
352 clear_entered_track = false;
355 button_release_can_deselect = true;
356 _dragging_playhead = false;
357 _dragging_edit_point = false;
358 select_new_marker = false;
360 layering_order_editor = 0;
361 no_save_visual = false;
363 within_track_canvas = false;
365 scrubbing_direction = 0;
369 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
370 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
371 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
372 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
373 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
375 _edit_point = EditAtMouse;
376 _internal_editing = false;
377 current_canvas_cursor = 0;
379 frames_per_unit = 2048; /* too early to use reset_zoom () */
381 _scroll_callbacks = 0;
383 zoom_focus = ZoomFocusLeft;
384 set_zoom_focus (ZoomFocusLeft);
385 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
387 bbt_label.set_name ("EditorTimeButton");
388 bbt_label.set_size_request (-1, (int)timebar_height);
389 bbt_label.set_alignment (1.0, 0.5);
390 bbt_label.set_padding (5,0);
392 bbt_label.set_no_show_all();
393 minsec_label.set_name ("EditorTimeButton");
394 minsec_label.set_size_request (-1, (int)timebar_height);
395 minsec_label.set_alignment (1.0, 0.5);
396 minsec_label.set_padding (5,0);
397 minsec_label.hide ();
398 minsec_label.set_no_show_all();
399 timecode_label.set_name ("EditorTimeButton");
400 timecode_label.set_size_request (-1, (int)timebar_height);
401 timecode_label.set_alignment (1.0, 0.5);
402 timecode_label.set_padding (5,0);
403 timecode_label.hide ();
404 timecode_label.set_no_show_all();
405 samples_label.set_name ("EditorTimeButton");
406 samples_label.set_size_request (-1, (int)timebar_height);
407 samples_label.set_alignment (1.0, 0.5);
408 samples_label.set_padding (5,0);
409 samples_label.hide ();
410 samples_label.set_no_show_all();
412 tempo_label.set_name ("EditorTimeButton");
413 tempo_label.set_size_request (-1, (int)timebar_height);
414 tempo_label.set_alignment (1.0, 0.5);
415 tempo_label.set_padding (5,0);
417 tempo_label.set_no_show_all();
419 meter_label.set_name ("EditorTimeButton");
420 meter_label.set_size_request (-1, (int)timebar_height);
421 meter_label.set_alignment (1.0, 0.5);
422 meter_label.set_padding (5,0);
424 meter_label.set_no_show_all();
426 mark_label.set_name ("EditorTimeButton");
427 mark_label.set_size_request (-1, (int)timebar_height);
428 mark_label.set_alignment (1.0, 0.5);
429 mark_label.set_padding (5,0);
431 mark_label.set_no_show_all();
433 cd_mark_label.set_name ("EditorTimeButton");
434 cd_mark_label.set_size_request (-1, (int)timebar_height);
435 cd_mark_label.set_alignment (1.0, 0.5);
436 cd_mark_label.set_padding (5,0);
437 cd_mark_label.hide();
438 cd_mark_label.set_no_show_all();
440 range_mark_label.set_name ("EditorTimeButton");
441 range_mark_label.set_size_request (-1, (int)timebar_height);
442 range_mark_label.set_alignment (1.0, 0.5);
443 range_mark_label.set_padding (5,0);
444 range_mark_label.hide();
445 range_mark_label.set_no_show_all();
447 transport_mark_label.set_name ("EditorTimeButton");
448 transport_mark_label.set_size_request (-1, (int)timebar_height);
449 transport_mark_label.set_alignment (1.0, 0.5);
450 transport_mark_label.set_padding (5,0);
451 transport_mark_label.hide();
452 transport_mark_label.set_no_show_all();
454 initialize_rulers ();
455 initialize_canvas ();
457 _summary = new EditorSummary (this);
459 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
460 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
462 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
464 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
465 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
467 edit_controls_vbox.set_spacing (0);
468 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
469 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
471 HBox* h = manage (new HBox);
472 _group_tabs = new EditorGroupTabs (this);
473 h->pack_start (*_group_tabs, PACK_SHRINK);
474 h->pack_start (edit_controls_vbox);
475 controls_layout.add (*h);
477 controls_layout.set_name ("EditControlsBase");
478 controls_layout.add_events (Gdk::SCROLL_MASK);
479 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
481 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
482 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
484 _cursors = new MouseCursors;
486 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
487 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
488 0.0, 1.0, 100.0, 1.0));
490 pad_line_1->property_color_rgba() = 0xFF0000FF;
495 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
496 time_canvas_vbox.set_size_request (-1, -1);
498 ruler_label_event_box.add (ruler_label_vbox);
499 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
500 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
502 time_button_event_box.add (time_button_vbox);
503 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
504 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
506 /* these enable us to have a dedicated window (for cursor setting, etc.)
507 for the canvas areas.
510 track_canvas_event_box.add (*track_canvas);
512 time_canvas_event_box.add (time_canvas_vbox);
513 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
515 edit_packer.set_col_spacings (0);
516 edit_packer.set_row_spacings (0);
517 edit_packer.set_homogeneous (false);
518 edit_packer.set_border_width (0);
519 edit_packer.set_name ("EditorWindow");
521 /* labels for the rulers */
522 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
523 /* labels for the marker "tracks" */
524 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
526 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
528 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
530 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
532 bottom_hbox.set_border_width (2);
533 bottom_hbox.set_spacing (3);
535 _route_groups = new EditorRouteGroups (this);
536 _routes = new EditorRoutes (this);
537 _regions = new EditorRegions (this);
538 _snapshots = new EditorSnapshots (this);
539 _locations = new EditorLocations (this);
541 add_notebook_page (_("Regions"), _regions->widget ());
542 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
543 add_notebook_page (_("Snapshots"), _snapshots->widget ());
544 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
545 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
547 _the_notebook.set_show_tabs (true);
548 _the_notebook.set_scrollable (true);
549 _the_notebook.popup_disable ();
550 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
551 _the_notebook.show_all ();
553 _notebook_shrunk = false;
555 editor_summary_pane.pack1(edit_packer);
557 Button* summary_arrows_left_left = manage (new Button);
558 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
559 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
560 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
562 Button* summary_arrows_left_right = manage (new Button);
563 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
564 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
565 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
567 VBox* summary_arrows_left = manage (new VBox);
568 summary_arrows_left->pack_start (*summary_arrows_left_left);
569 summary_arrows_left->pack_start (*summary_arrows_left_right);
571 Button* summary_arrows_right_up = manage (new Button);
572 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
573 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
574 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 Button* summary_arrows_right_down = manage (new Button);
577 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
578 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
579 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
581 VBox* summary_arrows_right = manage (new VBox);
582 summary_arrows_right->pack_start (*summary_arrows_right_up);
583 summary_arrows_right->pack_start (*summary_arrows_right_down);
585 Frame* summary_frame = manage (new Frame);
586 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
588 summary_frame->add (*_summary);
589 summary_frame->show ();
591 _summary_hbox.pack_start (*summary_arrows_left, false, false);
592 _summary_hbox.pack_start (*summary_frame, true, true);
593 _summary_hbox.pack_start (*summary_arrows_right, false, false);
595 editor_summary_pane.pack2 (_summary_hbox);
597 edit_pane.pack1 (editor_summary_pane, true, true);
598 edit_pane.pack2 (_the_notebook, false, true);
600 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
602 /* XXX: editor_summary_pane might need similar to the edit_pane */
604 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
606 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
607 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
609 top_hbox.pack_start (toolbar_frame);
611 HBox *hbox = manage (new HBox);
612 hbox->pack_start (edit_pane, true, true);
614 global_vpacker.pack_start (top_hbox, false, false);
615 global_vpacker.pack_start (*hbox, true, true);
617 global_hpacker.pack_start (global_vpacker, true, true);
619 set_name ("EditorWindow");
620 add_accel_group (ActionManager::ui_manager->get_accel_group());
622 status_bar_hpacker.show ();
624 vpacker.pack_end (status_bar_hpacker, false, false);
625 vpacker.pack_end (global_hpacker, true, true);
627 /* register actions now so that set_state() can find them and set toggles/checks etc */
630 /* when we start using our own keybinding system for the editor, this
631 * will be uncommented
637 _snap_type = SnapToBeat;
638 set_snap_to (_snap_type);
639 _snap_mode = SnapOff;
640 set_snap_mode (_snap_mode);
641 set_mouse_mode (MouseObject, true);
642 pre_internal_mouse_mode = MouseObject;
643 pre_internal_snap_type = _snap_type;
644 pre_internal_snap_mode = _snap_mode;
645 internal_snap_type = _snap_type;
646 internal_snap_mode = _snap_mode;
647 set_edit_point_preference (EditAtMouse, true);
649 _playlist_selector = new PlaylistSelector();
650 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
652 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
656 nudge_forward_button.set_name ("zoom button");
657 nudge_forward_button.add_elements (ArdourButton::FlatFace);
658 nudge_forward_button.set_image(::get_icon("nudge_right"));
660 nudge_backward_button.set_name ("zoom button");
661 nudge_backward_button.add_elements (ArdourButton::FlatFace);
662 nudge_backward_button.set_image(::get_icon("nudge_left"));
664 fade_context_menu.set_name ("ArdourContextMenu");
666 /* icons, titles, WM stuff */
668 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
669 Glib::RefPtr<Gdk::Pixbuf> icon;
671 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
672 window_icons.push_back (icon);
674 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
681 window_icons.push_back (icon);
683 if (!window_icons.empty()) {
684 // set_icon_list (window_icons);
685 set_default_icon_list (window_icons);
688 WindowTitle title(Glib::get_application_name());
689 title += _("Editor");
690 set_title (title.get_string());
691 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
694 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
696 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
697 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
699 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
701 /* allow external control surfaces/protocols to do various things */
703 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
704 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
705 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
706 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
707 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
708 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
709 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
710 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
711 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
712 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
713 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
714 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
715 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
716 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
718 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
719 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
720 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
721 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
722 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
724 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
726 /* problematic: has to return a value and thus cannot be x-thread */
728 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
730 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
732 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
734 _ignore_region_action = false;
735 _last_region_menu_was_main = false;
736 _popup_region_menu_item = 0;
738 _show_marker_lines = false;
739 _over_region_trim_target = false;
741 /* Button bindings */
743 button_bindings = new Bindings;
745 XMLNode* node = button_settings();
747 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
748 button_bindings->load (**i);
755 setup_fade_images ();
761 if(image_socket_listener) {
762 if(image_socket_listener->is_connected())
764 image_socket_listener->close_connection() ;
767 delete image_socket_listener ;
768 image_socket_listener = 0 ;
772 delete button_bindings;
774 delete _route_groups;
780 Editor::button_settings () const
782 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
783 XMLNode* node = find_named_node (*settings, X_("Buttons"));
786 node = new XMLNode (X_("Buttons"));
793 Editor::add_toplevel_controls (Container& cont)
795 vpacker.pack_start (cont, false, false);
800 Editor::get_smart_mode () const
802 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
806 Editor::catch_vanishing_regionview (RegionView *rv)
808 /* note: the selection will take care of the vanishing
809 audioregionview by itself.
812 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
816 if (clicked_regionview == rv) {
817 clicked_regionview = 0;
820 if (entered_regionview == rv) {
821 set_entered_regionview (0);
824 if (!_all_region_actions_sensitized) {
825 sensitize_all_region_actions (true);
828 _over_region_trim_target = false;
832 Editor::set_entered_regionview (RegionView* rv)
834 if (rv == entered_regionview) {
838 if (entered_regionview) {
839 entered_regionview->exited ();
842 if ((entered_regionview = rv) != 0) {
843 entered_regionview->entered (internal_editing ());
846 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
847 /* This RegionView entry might have changed what region actions
848 are allowed, so sensitize them all in case a key is pressed.
850 sensitize_all_region_actions (true);
855 Editor::set_entered_track (TimeAxisView* tav)
858 entered_track->exited ();
861 if ((entered_track = tav) != 0) {
862 entered_track->entered ();
867 Editor::show_window ()
869 if (!is_visible ()) {
872 /* XXX: this is a bit unfortunate; it would probably
873 be nicer if we could just call show () above rather
874 than needing the show_all ()
877 /* re-hide stuff if necessary */
878 editor_list_button_toggled ();
879 parameter_changed ("show-summary");
880 parameter_changed ("show-group-tabs");
881 parameter_changed ("show-zoom-tools");
883 /* now reset all audio_time_axis heights, because widgets might need
889 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
890 tv = (static_cast<TimeAxisView*>(*i));
894 if (current_mixer_strip) {
895 current_mixer_strip->hide_things ();
896 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
904 Editor::instant_save ()
906 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
911 _session->add_instant_xml(get_state());
913 Config->add_instant_xml(get_state());
918 Editor::zoom_adjustment_changed ()
924 double fpu = zoom_range_clock->current_duration() / _canvas_width;
925 bool clamped = clamp_frames_per_unit (fpu);
928 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
935 Editor::control_vertical_zoom_in_all ()
937 tav_zoom_smooth (false, true);
941 Editor::control_vertical_zoom_out_all ()
943 tav_zoom_smooth (true, true);
947 Editor::control_vertical_zoom_in_selected ()
949 tav_zoom_smooth (false, false);
953 Editor::control_vertical_zoom_out_selected ()
955 tav_zoom_smooth (true, false);
959 Editor::control_view (uint32_t view)
961 goto_visual_state (view);
965 Editor::control_unselect ()
967 selection->clear_tracks ();
971 Editor::control_select (uint32_t rid, Selection::Operation op)
973 /* handles the (static) signal from the ControlProtocol class that
974 * requests setting the selected track to a given RID
981 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
987 TimeAxisView* tav = axis_view_from_route (r);
992 selection->add (tav);
994 case Selection::Toggle:
995 selection->toggle (tav);
997 case Selection::Extend:
1000 selection->set (tav);
1004 selection->clear_tracks ();
1009 Editor::control_step_tracks_up ()
1011 scroll_tracks_up_line ();
1015 Editor::control_step_tracks_down ()
1017 scroll_tracks_down_line ();
1021 Editor::control_scroll (float fraction)
1023 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1029 double step = fraction * current_page_frames();
1032 _control_scroll_target is an optional<T>
1034 it acts like a pointer to an framepos_t, with
1035 a operator conversion to boolean to check
1036 that it has a value could possibly use
1037 playhead_cursor->current_frame to store the
1038 value and a boolean in the class to know
1039 when it's out of date
1042 if (!_control_scroll_target) {
1043 _control_scroll_target = _session->transport_frame();
1044 _dragging_playhead = true;
1047 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1048 *_control_scroll_target = 0;
1049 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1050 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1052 *_control_scroll_target += (framepos_t) floor (step);
1055 /* move visuals, we'll catch up with it later */
1057 playhead_cursor->set_position (*_control_scroll_target);
1058 UpdateAllTransportClocks (*_control_scroll_target);
1060 if (*_control_scroll_target > (current_page_frames() / 2)) {
1061 /* try to center PH in window */
1062 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1068 Now we do a timeout to actually bring the session to the right place
1069 according to the playhead. This is to avoid reading disk buffers on every
1070 call to control_scroll, which is driven by ScrollTimeline and therefore
1071 probably by a control surface wheel which can generate lots of events.
1073 /* cancel the existing timeout */
1075 control_scroll_connection.disconnect ();
1077 /* add the next timeout */
1079 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1083 Editor::deferred_control_scroll (framepos_t /*target*/)
1085 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1086 // reset for next stream
1087 _control_scroll_target = boost::none;
1088 _dragging_playhead = false;
1093 Editor::access_action (std::string action_group, std::string action_item)
1099 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1102 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1110 Editor::on_realize ()
1112 Window::on_realize ();
1117 Editor::map_position_change (framepos_t frame)
1119 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1121 if (_session == 0) {
1125 if (_follow_playhead) {
1126 center_screen (frame);
1129 playhead_cursor->set_position (frame);
1133 Editor::center_screen (framepos_t frame)
1135 double page = _canvas_width * frames_per_unit;
1137 /* if we're off the page, then scroll.
1140 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1141 center_screen_internal (frame, page);
1146 Editor::center_screen_internal (framepos_t frame, float page)
1151 frame -= (framepos_t) page;
1156 reset_x_origin (frame);
1161 Editor::update_title ()
1163 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1166 bool dirty = _session->dirty();
1168 string session_name;
1170 if (_session->snap_name() != _session->name()) {
1171 session_name = _session->snap_name();
1173 session_name = _session->name();
1177 session_name = "*" + session_name;
1180 WindowTitle title(session_name);
1181 title += Glib::get_application_name();
1182 set_title (title.get_string());
1184 /* ::session_going_away() will have taken care of it */
1189 Editor::set_session (Session *t)
1191 SessionHandlePtr::set_session (t);
1197 zoom_range_clock->set_session (_session);
1198 _playlist_selector->set_session (_session);
1199 nudge_clock->set_session (_session);
1200 _summary->set_session (_session);
1201 _group_tabs->set_session (_session);
1202 _route_groups->set_session (_session);
1203 _regions->set_session (_session);
1204 _snapshots->set_session (_session);
1205 _routes->set_session (_session);
1206 _locations->set_session (_session);
1208 if (rhythm_ferret) {
1209 rhythm_ferret->set_session (_session);
1212 if (analysis_window) {
1213 analysis_window->set_session (_session);
1217 sfbrowser->set_session (_session);
1220 compute_fixed_ruler_scale ();
1222 /* Make sure we have auto loop and auto punch ranges */
1224 Location* loc = _session->locations()->auto_loop_location();
1226 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1228 if (loc->start() == loc->end()) {
1229 loc->set_end (loc->start() + 1);
1232 _session->locations()->add (loc, false);
1233 _session->set_auto_loop_location (loc);
1236 loc->set_name (_("Loop"));
1239 loc = _session->locations()->auto_punch_location();
1242 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1244 if (loc->start() == loc->end()) {
1245 loc->set_end (loc->start() + 1);
1248 _session->locations()->add (loc, false);
1249 _session->set_auto_punch_location (loc);
1252 loc->set_name (_("Punch"));
1255 refresh_location_display ();
1257 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1258 the selected Marker; this needs the LocationMarker list to be available.
1260 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1261 set_state (*node, Stateful::loading_state_version);
1263 /* catch up with the playhead */
1265 _session->request_locate (playhead_cursor->current_frame);
1266 _pending_initial_locate = true;
1270 /* These signals can all be emitted by a non-GUI thread. Therefore the
1271 handlers for them must not attempt to directly interact with the GUI,
1272 but use Gtkmm2ext::UI::instance()->call_slot();
1275 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1276 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1277 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1278 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1279 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1280 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1281 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1282 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1283 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1284 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1285 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1286 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1287 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1288 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1290 playhead_cursor->canvas_item.show ();
1292 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1293 Config->map_parameters (pc);
1294 _session->config.map_parameters (pc);
1296 restore_ruler_visibility ();
1297 //tempo_map_changed (PropertyChange (0));
1298 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1300 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1301 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1304 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1305 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1308 switch (_snap_type) {
1309 case SnapToRegionStart:
1310 case SnapToRegionEnd:
1311 case SnapToRegionSync:
1312 case SnapToRegionBoundary:
1313 build_region_boundary_cache ();
1320 /* register for undo history */
1321 _session->register_with_memento_command_factory(id(), this);
1323 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1325 start_updating_meters ();
1329 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1331 if (a->get_name() == "RegionMenu") {
1332 /* When the main menu's region menu is opened, we setup the actions so that they look right
1333 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1334 so we resensitize all region actions when the entered regionview or the region selection
1335 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1336 happens after the region context menu is opened. So we set a flag here, too.
1340 sensitize_the_right_region_actions ();
1341 _last_region_menu_was_main = true;
1346 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1348 using namespace Menu_Helpers;
1350 void (Editor::*emf)(FadeShape);
1351 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1354 images = &_xfade_in_images;
1355 emf = &Editor::set_fade_in_shape;
1357 images = &_xfade_out_images;
1358 emf = &Editor::set_fade_out_shape;
1363 _("Linear (for highly correlated material)"),
1364 *(*images)[FadeLinear],
1365 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1369 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1373 _("Constant power"),
1374 *(*images)[FadeConstantPower],
1375 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1378 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1383 *(*images)[FadeSymmetric],
1384 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1388 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1393 *(*images)[FadeSlow],
1394 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1397 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1402 *(*images)[FadeFast],
1403 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1406 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1409 /** Pop up a context menu for when the user clicks on a start crossfade */
1411 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1413 using namespace Menu_Helpers;
1415 MenuList& items (xfade_in_context_menu.items());
1417 if (items.empty()) {
1418 fill_xfade_menu (items, true);
1421 xfade_in_context_menu.popup (button, time);
1424 /** Pop up a context menu for when the user clicks on an end crossfade */
1426 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1428 using namespace Menu_Helpers;
1430 MenuList& items (xfade_out_context_menu.items());
1432 if (items.empty()) {
1433 fill_xfade_menu (items, false);
1436 xfade_out_context_menu.popup (button, time);
1440 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1442 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1444 using namespace Menu_Helpers;
1445 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1448 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1452 MenuList& items (fade_context_menu.items());
1455 switch (item_type) {
1457 case FadeInHandleItem:
1458 if (arv->audio_region()->fade_in_active()) {
1459 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1461 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1464 items.push_back (SeparatorElem());
1466 if (Profile->get_sae()) {
1468 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1469 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1476 *_fade_in_images[FadeLinear],
1477 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 *_fade_in_images[FadeSlow],
1487 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 *_fade_in_images[FadeFast],
1496 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1499 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1504 *_fade_in_images[FadeSymmetric],
1505 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1510 _("Constant power"),
1511 *_fade_in_images[FadeConstantPower],
1512 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1515 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1521 case FadeOutHandleItem:
1522 if (arv->audio_region()->fade_out_active()) {
1523 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1525 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1528 items.push_back (SeparatorElem());
1530 if (Profile->get_sae()) {
1531 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1532 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1538 *_fade_out_images[FadeLinear],
1539 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1543 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1548 *_fade_out_images[FadeSlow],
1549 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1552 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1557 *_fade_out_images[FadeFast],
1558 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1561 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1566 *_fade_out_images[FadeSymmetric],
1567 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1572 _("Constant power"),
1573 *_fade_out_images[FadeConstantPower],
1574 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1577 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1583 fatal << _("programming error: ")
1584 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1589 fade_context_menu.popup (button, time);
1593 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1595 using namespace Menu_Helpers;
1596 Menu* (Editor::*build_menu_function)();
1599 switch (item_type) {
1601 case RegionViewName:
1602 case RegionViewNameHighlight:
1603 case LeftFrameHandle:
1604 case RightFrameHandle:
1605 if (with_selection) {
1606 build_menu_function = &Editor::build_track_selection_context_menu;
1608 build_menu_function = &Editor::build_track_region_context_menu;
1613 if (with_selection) {
1614 build_menu_function = &Editor::build_track_selection_context_menu;
1616 build_menu_function = &Editor::build_track_context_menu;
1621 if (clicked_routeview->track()) {
1622 build_menu_function = &Editor::build_track_context_menu;
1624 build_menu_function = &Editor::build_track_bus_context_menu;
1629 /* probably shouldn't happen but if it does, we don't care */
1633 menu = (this->*build_menu_function)();
1634 menu->set_name ("ArdourContextMenu");
1636 /* now handle specific situations */
1638 switch (item_type) {
1640 case RegionViewName:
1641 case RegionViewNameHighlight:
1642 case LeftFrameHandle:
1643 case RightFrameHandle:
1644 if (!with_selection) {
1645 if (region_edit_menu_split_item) {
1646 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1647 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1649 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1652 if (region_edit_menu_split_multichannel_item) {
1653 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1654 region_edit_menu_split_multichannel_item->set_sensitive (true);
1656 region_edit_menu_split_multichannel_item->set_sensitive (false);
1669 /* probably shouldn't happen but if it does, we don't care */
1673 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1675 /* Bounce to disk */
1677 using namespace Menu_Helpers;
1678 MenuList& edit_items = menu->items();
1680 edit_items.push_back (SeparatorElem());
1682 switch (clicked_routeview->audio_track()->freeze_state()) {
1683 case AudioTrack::NoFreeze:
1684 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1687 case AudioTrack::Frozen:
1688 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1691 case AudioTrack::UnFrozen:
1692 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1698 if (item_type == StreamItem && clicked_routeview) {
1699 clicked_routeview->build_underlay_menu(menu);
1702 /* When the region menu is opened, we setup the actions so that they look right
1705 sensitize_the_right_region_actions ();
1706 _last_region_menu_was_main = false;
1708 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1709 menu->popup (button, time);
1713 Editor::build_track_context_menu ()
1715 using namespace Menu_Helpers;
1717 MenuList& edit_items = track_context_menu.items();
1720 add_dstream_context_items (edit_items);
1721 return &track_context_menu;
1725 Editor::build_track_bus_context_menu ()
1727 using namespace Menu_Helpers;
1729 MenuList& edit_items = track_context_menu.items();
1732 add_bus_context_items (edit_items);
1733 return &track_context_menu;
1737 Editor::build_track_region_context_menu ()
1739 using namespace Menu_Helpers;
1740 MenuList& edit_items = track_region_context_menu.items();
1743 /* we've just cleared the track region context menu, so the menu that these
1744 two items were on will have disappeared; stop them dangling.
1746 region_edit_menu_split_item = 0;
1747 region_edit_menu_split_multichannel_item = 0;
1749 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1752 boost::shared_ptr<Track> tr;
1753 boost::shared_ptr<Playlist> pl;
1755 if ((tr = rtv->track())) {
1756 add_region_context_items (edit_items, tr);
1760 add_dstream_context_items (edit_items);
1762 return &track_region_context_menu;
1766 Editor::analyze_region_selection ()
1768 if (analysis_window == 0) {
1769 analysis_window = new AnalysisWindow();
1772 analysis_window->set_session(_session);
1774 analysis_window->show_all();
1777 analysis_window->set_regionmode();
1778 analysis_window->analyze();
1780 analysis_window->present();
1784 Editor::analyze_range_selection()
1786 if (analysis_window == 0) {
1787 analysis_window = new AnalysisWindow();
1790 analysis_window->set_session(_session);
1792 analysis_window->show_all();
1795 analysis_window->set_rangemode();
1796 analysis_window->analyze();
1798 analysis_window->present();
1802 Editor::build_track_selection_context_menu ()
1804 using namespace Menu_Helpers;
1805 MenuList& edit_items = track_selection_context_menu.items();
1806 edit_items.clear ();
1808 add_selection_context_items (edit_items);
1809 // edit_items.push_back (SeparatorElem());
1810 // add_dstream_context_items (edit_items);
1812 return &track_selection_context_menu;
1816 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1818 using namespace Menu_Helpers;
1820 /* OK, stick the region submenu at the top of the list, and then add
1824 RegionSelection rs = get_regions_from_selection_and_entered ();
1826 string::size_type pos = 0;
1827 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1829 /* we have to hack up the region name because "_" has a special
1830 meaning for menu titles.
1833 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1834 menu_item_name.replace (pos, 1, "__");
1838 if (_popup_region_menu_item == 0) {
1839 _popup_region_menu_item = new MenuItem (menu_item_name);
1840 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1841 _popup_region_menu_item->show ();
1843 _popup_region_menu_item->set_label (menu_item_name);
1846 const framepos_t position = get_preferred_edit_position (false, true);
1848 edit_items.push_back (*_popup_region_menu_item);
1849 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1850 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1852 edit_items.push_back (SeparatorElem());
1855 /** Add context menu items relevant to selection ranges.
1856 * @param edit_items List to add the items to.
1859 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1861 using namespace Menu_Helpers;
1863 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1864 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1866 edit_items.push_back (SeparatorElem());
1867 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1869 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (
1873 _("Move Range Start to Previous Region Boundary"),
1874 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1878 edit_items.push_back (
1880 _("Move Range Start to Next Region Boundary"),
1881 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1885 edit_items.push_back (
1887 _("Move Range End to Previous Region Boundary"),
1888 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1892 edit_items.push_back (
1894 _("Move Range End to Next Region Boundary"),
1895 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1899 edit_items.push_back (SeparatorElem());
1900 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1901 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1906 edit_items.push_back (SeparatorElem());
1907 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1908 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1910 edit_items.push_back (SeparatorElem());
1911 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1913 edit_items.push_back (SeparatorElem());
1914 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1915 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1916 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1918 edit_items.push_back (SeparatorElem());
1919 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1920 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1921 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1922 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1923 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1928 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1930 using namespace Menu_Helpers;
1934 Menu *play_menu = manage (new Menu);
1935 MenuList& play_items = play_menu->items();
1936 play_menu->set_name ("ArdourContextMenu");
1938 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1939 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1940 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1941 play_items.push_back (SeparatorElem());
1942 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1944 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1948 Menu *select_menu = manage (new Menu);
1949 MenuList& select_items = select_menu->items();
1950 select_menu->set_name ("ArdourContextMenu");
1952 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1953 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1954 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1955 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1956 select_items.push_back (SeparatorElem());
1957 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1958 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1959 select_items.push_back (SeparatorElem());
1960 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1961 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1962 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1963 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1964 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1965 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1966 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1968 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1972 Menu *cutnpaste_menu = manage (new Menu);
1973 MenuList& cutnpaste_items = cutnpaste_menu->items();
1974 cutnpaste_menu->set_name ("ArdourContextMenu");
1976 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1977 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1978 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1980 cutnpaste_items.push_back (SeparatorElem());
1982 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1983 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1985 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1987 /* Adding new material */
1989 edit_items.push_back (SeparatorElem());
1990 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1991 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1995 Menu *nudge_menu = manage (new Menu());
1996 MenuList& nudge_items = nudge_menu->items();
1997 nudge_menu->set_name ("ArdourContextMenu");
1999 edit_items.push_back (SeparatorElem());
2000 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2001 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2002 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2003 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2005 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2009 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2011 using namespace Menu_Helpers;
2015 Menu *play_menu = manage (new Menu);
2016 MenuList& play_items = play_menu->items();
2017 play_menu->set_name ("ArdourContextMenu");
2019 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2020 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2021 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2025 Menu *select_menu = manage (new Menu);
2026 MenuList& select_items = select_menu->items();
2027 select_menu->set_name ("ArdourContextMenu");
2029 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2030 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2031 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2032 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2033 select_items.push_back (SeparatorElem());
2034 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2035 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2036 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2037 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2039 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2043 Menu *cutnpaste_menu = manage (new Menu);
2044 MenuList& cutnpaste_items = cutnpaste_menu->items();
2045 cutnpaste_menu->set_name ("ArdourContextMenu");
2047 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2048 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2049 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2051 Menu *nudge_menu = manage (new Menu());
2052 MenuList& nudge_items = nudge_menu->items();
2053 nudge_menu->set_name ("ArdourContextMenu");
2055 edit_items.push_back (SeparatorElem());
2056 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2057 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2058 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2059 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2061 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2065 Editor::snap_type() const
2071 Editor::snap_mode() const
2077 Editor::set_snap_to (SnapType st)
2079 unsigned int snap_ind = (unsigned int)st;
2083 if (snap_ind > snap_type_strings.size() - 1) {
2085 _snap_type = (SnapType)snap_ind;
2088 string str = snap_type_strings[snap_ind];
2090 if (str != snap_type_selector.get_active_text()) {
2091 snap_type_selector.set_active_text (str);
2096 switch (_snap_type) {
2097 case SnapToBeatDiv128:
2098 case SnapToBeatDiv64:
2099 case SnapToBeatDiv32:
2100 case SnapToBeatDiv28:
2101 case SnapToBeatDiv24:
2102 case SnapToBeatDiv20:
2103 case SnapToBeatDiv16:
2104 case SnapToBeatDiv14:
2105 case SnapToBeatDiv12:
2106 case SnapToBeatDiv10:
2107 case SnapToBeatDiv8:
2108 case SnapToBeatDiv7:
2109 case SnapToBeatDiv6:
2110 case SnapToBeatDiv5:
2111 case SnapToBeatDiv4:
2112 case SnapToBeatDiv3:
2113 case SnapToBeatDiv2: {
2114 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2115 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2117 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2118 current_bbt_points_begin, current_bbt_points_end);
2119 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2120 current_bbt_points_begin, current_bbt_points_end);
2121 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2125 case SnapToRegionStart:
2126 case SnapToRegionEnd:
2127 case SnapToRegionSync:
2128 case SnapToRegionBoundary:
2129 build_region_boundary_cache ();
2137 SnapChanged (); /* EMIT SIGNAL */
2141 Editor::set_snap_mode (SnapMode mode)
2143 string str = snap_mode_strings[(int)mode];
2145 if (_internal_editing) {
2146 internal_snap_mode = mode;
2148 pre_internal_snap_mode = mode;
2153 if (str != snap_mode_selector.get_active_text ()) {
2154 snap_mode_selector.set_active_text (str);
2160 Editor::set_edit_point_preference (EditPoint ep, bool force)
2162 bool changed = (_edit_point != ep);
2165 string str = edit_point_strings[(int)ep];
2167 if (str != edit_point_selector.get_active_text ()) {
2168 edit_point_selector.set_active_text (str);
2171 set_canvas_cursor ();
2173 if (!force && !changed) {
2177 const char* action=NULL;
2179 switch (_edit_point) {
2180 case EditAtPlayhead:
2181 action = "edit-at-playhead";
2183 case EditAtSelectedMarker:
2184 action = "edit-at-marker";
2187 action = "edit-at-mouse";
2191 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2193 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2197 bool in_track_canvas;
2199 if (!mouse_frame (foo, in_track_canvas)) {
2200 in_track_canvas = false;
2203 reset_canvas_action_sensitivity (in_track_canvas);
2209 Editor::set_state (const XMLNode& node, int /*version*/)
2211 const XMLProperty* prop;
2218 g.base_width = default_width;
2219 g.base_height = default_height;
2223 if ((geometry = find_named_node (node, "geometry")) != 0) {
2227 if ((prop = geometry->property("x_size")) == 0) {
2228 prop = geometry->property ("x-size");
2231 g.base_width = atoi(prop->value());
2233 if ((prop = geometry->property("y_size")) == 0) {
2234 prop = geometry->property ("y-size");
2237 g.base_height = atoi(prop->value());
2240 if ((prop = geometry->property ("x_pos")) == 0) {
2241 prop = geometry->property ("x-pos");
2244 x = atoi (prop->value());
2247 if ((prop = geometry->property ("y_pos")) == 0) {
2248 prop = geometry->property ("y-pos");
2251 y = atoi (prop->value());
2255 set_default_size (g.base_width, g.base_height);
2258 if (_session && (prop = node.property ("playhead"))) {
2260 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2261 playhead_cursor->set_position (pos);
2263 playhead_cursor->set_position (0);
2266 if ((prop = node.property ("mixer-width"))) {
2267 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2270 if ((prop = node.property ("zoom-focus"))) {
2271 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2274 if ((prop = node.property ("zoom"))) {
2275 reset_zoom (PBD::atof (prop->value()));
2277 reset_zoom (frames_per_unit);
2280 if ((prop = node.property ("snap-to"))) {
2281 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2284 if ((prop = node.property ("snap-mode"))) {
2285 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2288 if ((prop = node.property ("internal-snap-to"))) {
2289 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2292 if ((prop = node.property ("internal-snap-mode"))) {
2293 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2296 if ((prop = node.property ("pre-internal-snap-to"))) {
2297 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2301 if ((prop = node.property ("pre-internal-snap-mode"))) {
2302 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2305 if ((prop = node.property ("mouse-mode"))) {
2306 MouseMode m = str2mousemode(prop->value());
2307 set_mouse_mode (m, true);
2309 set_mouse_mode (MouseObject, true);
2312 if ((prop = node.property ("left-frame")) != 0) {
2314 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2318 reset_x_origin (pos);
2322 if ((prop = node.property ("y-origin")) != 0) {
2323 reset_y_origin (atof (prop->value ()));
2326 if ((prop = node.property ("internal-edit"))) {
2327 bool yn = string_is_affirmative (prop->value());
2328 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2330 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2331 tact->set_active (!yn);
2332 tact->set_active (yn);
2336 if ((prop = node.property ("join-object-range"))) {
2337 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2338 bool yn = string_is_affirmative (prop->value());
2340 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2341 tact->set_active (!yn);
2342 tact->set_active (yn);
2344 set_mouse_mode(mouse_mode, true);
2347 if ((prop = node.property ("edit-point"))) {
2348 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2351 if ((prop = node.property ("show-measures"))) {
2352 bool yn = string_is_affirmative (prop->value());
2353 _show_measures = yn;
2354 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2356 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2357 /* do it twice to force the change */
2358 tact->set_active (!yn);
2359 tact->set_active (yn);
2363 if ((prop = node.property ("follow-playhead"))) {
2364 bool yn = string_is_affirmative (prop->value());
2365 set_follow_playhead (yn);
2366 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2368 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2369 if (tact->get_active() != yn) {
2370 tact->set_active (yn);
2375 if ((prop = node.property ("stationary-playhead"))) {
2376 bool yn = string_is_affirmative (prop->value());
2377 set_stationary_playhead (yn);
2378 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2380 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2381 if (tact->get_active() != yn) {
2382 tact->set_active (yn);
2387 if ((prop = node.property ("region-list-sort-type"))) {
2388 RegionListSortType st;
2389 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2392 if ((prop = node.property ("show-editor-mixer"))) {
2394 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2397 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2398 bool yn = string_is_affirmative (prop->value());
2400 /* do it twice to force the change */
2402 tact->set_active (!yn);
2403 tact->set_active (yn);
2406 if ((prop = node.property ("show-editor-list"))) {
2408 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2411 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2412 bool yn = string_is_affirmative (prop->value());
2414 /* do it twice to force the change */
2416 tact->set_active (!yn);
2417 tact->set_active (yn);
2420 if ((prop = node.property (X_("editor-list-page")))) {
2421 _the_notebook.set_current_page (atoi (prop->value ()));
2424 if ((prop = node.property (X_("show-marker-lines")))) {
2425 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2427 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2428 bool yn = string_is_affirmative (prop->value ());
2430 tact->set_active (!yn);
2431 tact->set_active (yn);
2434 XMLNodeList children = node.children ();
2435 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2436 selection->set_state (**i, Stateful::current_state_version);
2437 _regions->set_state (**i);
2440 if ((prop = node.property ("maximised"))) {
2441 bool yn = string_is_affirmative (prop->value());
2443 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2447 if ((prop = node.property ("nudge-clock-value"))) {
2449 sscanf (prop->value().c_str(), "%" PRId64, &f);
2450 nudge_clock->set (f);
2452 nudge_clock->set_mode (AudioClock::Timecode);
2453 nudge_clock->set (_session->frame_rate() * 5, true);
2460 Editor::get_state ()
2462 XMLNode* node = new XMLNode ("Editor");
2465 id().print (buf, sizeof (buf));
2466 node->add_property ("id", buf);
2468 if (is_realized()) {
2469 Glib::RefPtr<Gdk::Window> win = get_window();
2471 int x, y, width, height;
2472 win->get_root_origin(x, y);
2473 win->get_size(width, height);
2475 XMLNode* geometry = new XMLNode ("geometry");
2477 snprintf(buf, sizeof(buf), "%d", width);
2478 geometry->add_property("x-size", string(buf));
2479 snprintf(buf, sizeof(buf), "%d", height);
2480 geometry->add_property("y-size", string(buf));
2481 snprintf(buf, sizeof(buf), "%d", x);
2482 geometry->add_property("x-pos", string(buf));
2483 snprintf(buf, sizeof(buf), "%d", y);
2484 geometry->add_property("y-pos", string(buf));
2485 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2486 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2487 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2488 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2489 geometry->add_property("edit-vertical-pane-pos", string(buf));
2491 node->add_child_nocopy (*geometry);
2494 maybe_add_mixer_strip_width (*node);
2496 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2497 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2498 node->add_property ("zoom", buf);
2499 node->add_property ("snap-to", enum_2_string (_snap_type));
2500 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2501 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2502 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2503 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2504 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2505 node->add_property ("edit-point", enum_2_string (_edit_point));
2507 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2508 node->add_property ("playhead", buf);
2509 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2510 node->add_property ("left-frame", buf);
2511 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2512 node->add_property ("y-origin", buf);
2514 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2515 node->add_property ("maximised", _maximised ? "yes" : "no");
2516 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2517 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2518 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2519 node->add_property ("mouse-mode", enum2str(mouse_mode));
2520 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2521 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2523 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2525 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2526 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2529 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2531 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2532 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2535 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2536 node->add_property (X_("editor-list-page"), buf);
2538 if (button_bindings) {
2539 XMLNode* bb = new XMLNode (X_("Buttons"));
2540 button_bindings->save (*bb);
2541 node->add_child_nocopy (*bb);
2544 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2546 node->add_child_nocopy (selection->get_state ());
2547 node->add_child_nocopy (_regions->get_state ());
2549 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2550 node->add_property ("nudge-clock-value", buf);
2557 /** @param y y offset from the top of all trackviews.
2558 * @return pair: TimeAxisView that y is over, layer index.
2559 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2560 * in stacked or expanded region display mode, otherwise 0.
2562 std::pair<TimeAxisView *, double>
2563 Editor::trackview_by_y_position (double y)
2565 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2567 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2573 return std::make_pair ( (TimeAxisView *) 0, 0);
2576 /** Snap a position to the grid, if appropriate, taking into account current
2577 * grid settings and also the state of any snap modifier keys that may be pressed.
2578 * @param start Position to snap.
2579 * @param event Event to get current key modifier information from, or 0.
2582 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2584 if (!_session || !event) {
2588 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2589 if (_snap_mode == SnapOff) {
2590 snap_to_internal (start, direction, for_mark);
2593 if (_snap_mode != SnapOff) {
2594 snap_to_internal (start, direction, for_mark);
2600 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2602 if (!_session || _snap_mode == SnapOff) {
2606 snap_to_internal (start, direction, for_mark);
2610 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2612 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2613 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2615 switch (_snap_type) {
2616 case SnapToTimecodeFrame:
2617 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2618 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2620 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2624 case SnapToTimecodeSeconds:
2625 if (_session->config.get_timecode_offset_negative()) {
2626 start += _session->config.get_timecode_offset ();
2628 start -= _session->config.get_timecode_offset ();
2630 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2631 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2633 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2636 if (_session->config.get_timecode_offset_negative()) {
2637 start -= _session->config.get_timecode_offset ();
2639 start += _session->config.get_timecode_offset ();
2643 case SnapToTimecodeMinutes:
2644 if (_session->config.get_timecode_offset_negative()) {
2645 start += _session->config.get_timecode_offset ();
2647 start -= _session->config.get_timecode_offset ();
2649 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2650 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2652 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2654 if (_session->config.get_timecode_offset_negative()) {
2655 start -= _session->config.get_timecode_offset ();
2657 start += _session->config.get_timecode_offset ();
2661 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2667 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2669 const framepos_t one_second = _session->frame_rate();
2670 const framepos_t one_minute = _session->frame_rate() * 60;
2671 framepos_t presnap = start;
2675 switch (_snap_type) {
2676 case SnapToTimecodeFrame:
2677 case SnapToTimecodeSeconds:
2678 case SnapToTimecodeMinutes:
2679 return timecode_snap_to_internal (start, direction, for_mark);
2682 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2683 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2685 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2690 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2691 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2693 start = (framepos_t) floor ((double) start / one_second) * one_second;
2698 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2699 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2701 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2706 start = _session->tempo_map().round_to_bar (start, direction);
2710 start = _session->tempo_map().round_to_beat (start, direction);
2713 case SnapToBeatDiv128:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2716 case SnapToBeatDiv64:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2719 case SnapToBeatDiv32:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2722 case SnapToBeatDiv28:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2725 case SnapToBeatDiv24:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2728 case SnapToBeatDiv20:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2731 case SnapToBeatDiv16:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2734 case SnapToBeatDiv14:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2737 case SnapToBeatDiv12:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2740 case SnapToBeatDiv10:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2743 case SnapToBeatDiv8:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2746 case SnapToBeatDiv7:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2749 case SnapToBeatDiv6:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2752 case SnapToBeatDiv5:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2755 case SnapToBeatDiv4:
2756 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2758 case SnapToBeatDiv3:
2759 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2761 case SnapToBeatDiv2:
2762 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2770 _session->locations()->marks_either_side (start, before, after);
2772 if (before == max_framepos && after == max_framepos) {
2773 /* No marks to snap to, so just don't snap */
2775 } else if (before == max_framepos) {
2777 } else if (after == max_framepos) {
2779 } else if (before != max_framepos && after != max_framepos) {
2780 /* have before and after */
2781 if ((start - before) < (after - start)) {
2790 case SnapToRegionStart:
2791 case SnapToRegionEnd:
2792 case SnapToRegionSync:
2793 case SnapToRegionBoundary:
2794 if (!region_boundary_cache.empty()) {
2796 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2797 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2799 if (direction > 0) {
2800 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2802 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2805 if (next != region_boundary_cache.begin ()) {
2810 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2811 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2813 if (start > (p + n) / 2) {
2822 switch (_snap_mode) {
2828 if (presnap > start) {
2829 if (presnap > (start + unit_to_frame(snap_threshold))) {
2833 } else if (presnap < start) {
2834 if (presnap < (start - unit_to_frame(snap_threshold))) {
2840 /* handled at entry */
2848 Editor::setup_toolbar ()
2850 HBox* mode_box = manage(new HBox);
2851 mode_box->set_border_width (2);
2852 mode_box->set_spacing(4);
2854 HBox* mouse_mode_box = manage (new HBox);
2855 HBox* mouse_mode_hbox = manage (new HBox);
2856 VBox* mouse_mode_vbox = manage (new VBox);
2857 Alignment* mouse_mode_align = manage (new Alignment);
2859 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2860 // mouse_mode_size_group->add_widget (smart_mode_button);
2861 mouse_mode_size_group->add_widget (mouse_move_button);
2862 mouse_mode_size_group->add_widget (mouse_select_button);
2863 mouse_mode_size_group->add_widget (mouse_zoom_button);
2864 mouse_mode_size_group->add_widget (mouse_gain_button);
2865 mouse_mode_size_group->add_widget (mouse_timefx_button);
2866 mouse_mode_size_group->add_widget (mouse_audition_button);
2867 mouse_mode_size_group->add_widget (mouse_draw_button);
2868 mouse_mode_size_group->add_widget (internal_edit_button);
2870 /* make them just a bit bigger */
2871 mouse_move_button.set_size_request (-1, 30);
2873 mouse_mode_hbox->set_spacing (2);
2875 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2876 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2877 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2878 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2879 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2880 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2881 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2882 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2883 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2885 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2887 mouse_mode_align->add (*mouse_mode_vbox);
2888 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2890 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2892 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2893 if (!Profile->get_sae()) {
2894 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2896 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2898 edit_mode_selector.set_name ("EditModeSelector");
2899 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2900 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2902 mode_box->pack_start (edit_mode_selector, false, false);
2903 mode_box->pack_start (*mouse_mode_box, false, false);
2905 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2906 _mouse_mode_tearoff->set_name ("MouseModeBase");
2907 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2909 if (Profile->get_sae()) {
2910 _mouse_mode_tearoff->set_can_be_torn_off (false);
2913 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2914 &_mouse_mode_tearoff->tearoff_window()));
2915 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2916 &_mouse_mode_tearoff->tearoff_window(), 1));
2917 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2918 &_mouse_mode_tearoff->tearoff_window()));
2919 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2920 &_mouse_mode_tearoff->tearoff_window(), 1));
2924 _zoom_box.set_spacing (2);
2925 _zoom_box.set_border_width (2);
2929 zoom_in_button.set_name ("zoom button");
2930 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2931 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2932 zoom_in_button.set_image(::get_icon ("zoom_in"));
2933 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2934 zoom_in_button.set_related_action (act);
2936 zoom_out_button.set_name ("zoom button");
2937 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2938 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2939 zoom_out_button.set_image(::get_icon ("zoom_out"));
2940 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2941 zoom_out_button.set_related_action (act);
2943 zoom_out_full_button.set_name ("zoom button");
2944 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2945 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2946 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2947 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2948 zoom_out_full_button.set_related_action (act);
2950 zoom_focus_selector.set_name ("ZoomFocusSelector");
2951 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2952 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2954 _zoom_box.pack_start (zoom_out_button, false, false);
2955 _zoom_box.pack_start (zoom_in_button, false, false);
2956 _zoom_box.pack_start (zoom_out_full_button, false, false);
2958 _zoom_box.pack_start (zoom_focus_selector, false, false);
2960 /* Track zoom buttons */
2961 tav_expand_button.set_name ("zoom button");
2962 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2963 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2964 tav_expand_button.set_size_request (-1, 20);
2965 tav_expand_button.set_image(::get_icon ("tav_exp"));
2966 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2967 tav_expand_button.set_related_action (act);
2969 tav_shrink_button.set_name ("zoom button");
2970 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2971 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2972 tav_shrink_button.set_size_request (-1, 20);
2973 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2974 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2975 tav_shrink_button.set_related_action (act);
2977 _zoom_box.pack_start (tav_shrink_button);
2978 _zoom_box.pack_start (tav_expand_button);
2980 _zoom_tearoff = manage (new TearOff (_zoom_box));
2982 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2983 &_zoom_tearoff->tearoff_window()));
2984 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2985 &_zoom_tearoff->tearoff_window(), 0));
2986 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2987 &_zoom_tearoff->tearoff_window()));
2988 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2989 &_zoom_tearoff->tearoff_window(), 0));
2991 snap_box.set_spacing (2);
2992 snap_box.set_border_width (2);
2994 snap_type_selector.set_name ("SnapTypeSelector");
2995 set_popdown_strings (snap_type_selector, snap_type_strings);
2996 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2998 snap_mode_selector.set_name ("SnapModeSelector");
2999 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3000 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3002 edit_point_selector.set_name ("EditPointSelector");
3003 set_popdown_strings (edit_point_selector, edit_point_strings);
3004 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3006 snap_box.pack_start (snap_mode_selector, false, false);
3007 snap_box.pack_start (snap_type_selector, false, false);
3008 snap_box.pack_start (edit_point_selector, false, false);
3012 HBox *nudge_box = manage (new HBox);
3013 nudge_box->set_spacing (2);
3014 nudge_box->set_border_width (2);
3016 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3017 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3019 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3020 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3022 nudge_box->pack_start (nudge_backward_button, false, false);
3023 nudge_box->pack_start (nudge_forward_button, false, false);
3024 nudge_box->pack_start (*nudge_clock, false, false);
3027 /* Pack everything in... */
3029 HBox* hbox = manage (new HBox);
3030 hbox->set_spacing(10);
3032 _tools_tearoff = manage (new TearOff (*hbox));
3033 _tools_tearoff->set_name ("MouseModeBase");
3034 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3036 if (Profile->get_sae()) {
3037 _tools_tearoff->set_can_be_torn_off (false);
3040 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3041 &_tools_tearoff->tearoff_window()));
3042 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3043 &_tools_tearoff->tearoff_window(), 0));
3044 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3045 &_tools_tearoff->tearoff_window()));
3046 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3047 &_tools_tearoff->tearoff_window(), 0));
3049 toolbar_hbox.set_spacing (10);
3050 toolbar_hbox.set_border_width (1);
3052 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3053 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3054 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3056 hbox->pack_start (snap_box, false, false);
3057 if (!Profile->get_small_screen()) {
3058 hbox->pack_start (*nudge_box, false, false);
3060 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3062 hbox->pack_start (panic_box, false, false);
3066 toolbar_base.set_name ("ToolBarBase");
3067 toolbar_base.add (toolbar_hbox);
3069 _toolbar_viewport.add (toolbar_base);
3070 /* stick to the required height but allow width to vary if there's not enough room */
3071 _toolbar_viewport.set_size_request (1, -1);
3073 toolbar_frame.set_shadow_type (SHADOW_OUT);
3074 toolbar_frame.set_name ("BaseFrame");
3075 toolbar_frame.add (_toolbar_viewport);
3079 Editor::setup_tooltips ()
3081 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3082 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3083 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3084 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3085 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3086 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3087 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3088 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3089 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3090 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3091 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3092 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3093 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3094 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3095 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3096 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3097 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3098 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3099 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3100 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3101 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3102 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3103 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3107 Editor::convert_drop_to_paths (
3108 vector<string>& paths,
3109 const RefPtr<Gdk::DragContext>& /*context*/,
3112 const SelectionData& data,
3116 if (_session == 0) {
3120 vector<string> uris = data.get_uris();
3124 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3125 are actually URI lists. So do it by hand.
3128 if (data.get_target() != "text/plain") {
3132 /* Parse the "uri-list" format that Nautilus provides,
3133 where each pathname is delimited by \r\n.
3135 THERE MAY BE NO NULL TERMINATING CHAR!!!
3138 string txt = data.get_text();
3142 p = (const char *) malloc (txt.length() + 1);
3143 txt.copy (const_cast<char *> (p), txt.length(), 0);
3144 const_cast<char*>(p)[txt.length()] = '\0';
3150 while (g_ascii_isspace (*p))
3154 while (*q && (*q != '\n') && (*q != '\r')) {
3161 while (q > p && g_ascii_isspace (*q))
3166 uris.push_back (string (p, q - p + 1));
3170 p = strchr (p, '\n');
3182 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3184 if ((*i).substr (0,7) == "file://") {
3186 string const p = PBD::url_decode (*i);
3188 // scan forward past three slashes
3190 string::size_type slashcnt = 0;
3191 string::size_type n = 0;
3192 string::const_iterator x = p.begin();
3194 while (slashcnt < 3 && x != p.end()) {
3197 } else if (slashcnt == 3) {
3204 if (slashcnt != 3 || x == p.end()) {
3205 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3209 paths.push_back (p.substr (n - 1));
3217 Editor::new_tempo_section ()
3223 Editor::map_transport_state ()
3225 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3227 if (_session && _session->transport_stopped()) {
3228 have_pending_keyboard_selection = false;
3231 update_loop_range_view (true);
3237 Editor::begin_reversible_command (string name)
3240 _session->begin_reversible_command (name);
3245 Editor::begin_reversible_command (GQuark q)
3248 _session->begin_reversible_command (q);
3253 Editor::commit_reversible_command ()
3256 _session->commit_reversible_command ();
3261 Editor::history_changed ()
3265 if (undo_action && _session) {
3266 if (_session->undo_depth() == 0) {
3267 label = S_("Command|Undo");
3269 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3271 undo_action->property_label() = label;
3274 if (redo_action && _session) {
3275 if (_session->redo_depth() == 0) {
3278 label = string_compose(_("Redo (%1)"), _session->next_redo());
3280 redo_action->property_label() = label;
3285 Editor::duplicate_range (bool with_dialog)
3289 RegionSelection rs = get_regions_from_selection_and_entered ();
3291 if ( selection->time.length() == 0 && rs.empty()) {
3297 ArdourDialog win (_("Duplicate"));
3298 Label label (_("Number of duplications:"));
3299 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3300 SpinButton spinner (adjustment, 0.0, 1);
3303 win.get_vbox()->set_spacing (12);
3304 win.get_vbox()->pack_start (hbox);
3305 hbox.set_border_width (6);
3306 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3308 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3309 place, visually. so do this by hand.
3312 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3313 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3314 spinner.grab_focus();
3320 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3321 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3322 win.set_default_response (RESPONSE_ACCEPT);
3324 win.set_position (WIN_POS_MOUSE);
3326 spinner.grab_focus ();
3328 switch (win.run ()) {
3329 case RESPONSE_ACCEPT:
3335 times = adjustment.get_value();
3338 if ((current_mouse_mode() == Editing::MouseRange)) {
3339 if (selection->time.length()) {
3340 duplicate_selection (times);
3342 } else if (get_smart_mode()) {
3343 if (selection->time.length()) {
3344 duplicate_selection (times);
3346 duplicate_some_regions (rs, times);
3348 duplicate_some_regions (rs, times);
3353 Editor::set_edit_mode (EditMode m)
3355 Config->set_edit_mode (m);
3359 Editor::cycle_edit_mode ()
3361 switch (Config->get_edit_mode()) {
3363 if (Profile->get_sae()) {
3364 Config->set_edit_mode (Lock);
3366 Config->set_edit_mode (Splice);
3370 Config->set_edit_mode (Lock);
3373 Config->set_edit_mode (Slide);
3379 Editor::edit_mode_selection_done ()
3381 string s = edit_mode_selector.get_active_text ();
3384 Config->set_edit_mode (string_to_edit_mode (s));
3389 Editor::snap_type_selection_done ()
3391 string choice = snap_type_selector.get_active_text();
3392 SnapType snaptype = SnapToBeat;
3394 if (choice == _("Beats/2")) {
3395 snaptype = SnapToBeatDiv2;
3396 } else if (choice == _("Beats/3")) {
3397 snaptype = SnapToBeatDiv3;
3398 } else if (choice == _("Beats/4")) {
3399 snaptype = SnapToBeatDiv4;
3400 } else if (choice == _("Beats/5")) {
3401 snaptype = SnapToBeatDiv5;
3402 } else if (choice == _("Beats/6")) {
3403 snaptype = SnapToBeatDiv6;
3404 } else if (choice == _("Beats/7")) {
3405 snaptype = SnapToBeatDiv7;
3406 } else if (choice == _("Beats/8")) {
3407 snaptype = SnapToBeatDiv8;
3408 } else if (choice == _("Beats/10")) {
3409 snaptype = SnapToBeatDiv10;
3410 } else if (choice == _("Beats/12")) {
3411 snaptype = SnapToBeatDiv12;
3412 } else if (choice == _("Beats/14")) {
3413 snaptype = SnapToBeatDiv14;
3414 } else if (choice == _("Beats/16")) {
3415 snaptype = SnapToBeatDiv16;
3416 } else if (choice == _("Beats/20")) {
3417 snaptype = SnapToBeatDiv20;
3418 } else if (choice == _("Beats/24")) {
3419 snaptype = SnapToBeatDiv24;
3420 } else if (choice == _("Beats/28")) {
3421 snaptype = SnapToBeatDiv28;
3422 } else if (choice == _("Beats/32")) {
3423 snaptype = SnapToBeatDiv32;
3424 } else if (choice == _("Beats/64")) {
3425 snaptype = SnapToBeatDiv64;
3426 } else if (choice == _("Beats/128")) {
3427 snaptype = SnapToBeatDiv128;
3428 } else if (choice == _("Beats")) {
3429 snaptype = SnapToBeat;
3430 } else if (choice == _("Bars")) {
3431 snaptype = SnapToBar;
3432 } else if (choice == _("Marks")) {
3433 snaptype = SnapToMark;
3434 } else if (choice == _("Region starts")) {
3435 snaptype = SnapToRegionStart;
3436 } else if (choice == _("Region ends")) {
3437 snaptype = SnapToRegionEnd;
3438 } else if (choice == _("Region bounds")) {
3439 snaptype = SnapToRegionBoundary;
3440 } else if (choice == _("Region syncs")) {
3441 snaptype = SnapToRegionSync;
3442 } else if (choice == _("CD Frames")) {
3443 snaptype = SnapToCDFrame;
3444 } else if (choice == _("Timecode Frames")) {
3445 snaptype = SnapToTimecodeFrame;
3446 } else if (choice == _("Timecode Seconds")) {
3447 snaptype = SnapToTimecodeSeconds;
3448 } else if (choice == _("Timecode Minutes")) {
3449 snaptype = SnapToTimecodeMinutes;
3450 } else if (choice == _("Seconds")) {
3451 snaptype = SnapToSeconds;
3452 } else if (choice == _("Minutes")) {
3453 snaptype = SnapToMinutes;
3456 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3458 ract->set_active ();
3463 Editor::snap_mode_selection_done ()
3465 string choice = snap_mode_selector.get_active_text();
3466 SnapMode mode = SnapNormal;
3468 if (choice == _("No Grid")) {
3470 } else if (choice == _("Grid")) {
3472 } else if (choice == _("Magnetic")) {
3473 mode = SnapMagnetic;
3476 RefPtr<RadioAction> ract = snap_mode_action (mode);
3479 ract->set_active (true);
3484 Editor::cycle_edit_point (bool with_marker)
3486 switch (_edit_point) {
3488 set_edit_point_preference (EditAtPlayhead);
3490 case EditAtPlayhead:
3492 set_edit_point_preference (EditAtSelectedMarker);
3494 set_edit_point_preference (EditAtMouse);
3497 case EditAtSelectedMarker:
3498 set_edit_point_preference (EditAtMouse);
3504 Editor::edit_point_selection_done ()
3506 string choice = edit_point_selector.get_active_text();
3507 EditPoint ep = EditAtSelectedMarker;
3509 if (choice == _("Marker")) {
3510 set_edit_point_preference (EditAtSelectedMarker);
3511 } else if (choice == _("Playhead")) {
3512 set_edit_point_preference (EditAtPlayhead);
3514 set_edit_point_preference (EditAtMouse);
3517 RefPtr<RadioAction> ract = edit_point_action (ep);
3520 ract->set_active (true);
3525 Editor::zoom_focus_selection_done ()
3527 string choice = zoom_focus_selector.get_active_text();
3528 ZoomFocus focus_type = ZoomFocusLeft;
3530 if (choice == _("Left")) {
3531 focus_type = ZoomFocusLeft;
3532 } else if (choice == _("Right")) {
3533 focus_type = ZoomFocusRight;
3534 } else if (choice == _("Center")) {
3535 focus_type = ZoomFocusCenter;
3536 } else if (choice == _("Playhead")) {
3537 focus_type = ZoomFocusPlayhead;
3538 } else if (choice == _("Mouse")) {
3539 focus_type = ZoomFocusMouse;
3540 } else if (choice == _("Edit point")) {
3541 focus_type = ZoomFocusEdit;
3544 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3547 ract->set_active ();
3552 Editor::edit_controls_button_release (GdkEventButton* ev)
3554 if (Keyboard::is_context_menu_event (ev)) {
3555 ARDOUR_UI::instance()->add_route (this);
3556 } else if (ev->button == 1) {
3557 selection->clear_tracks ();
3564 Editor::mouse_select_button_release (GdkEventButton* ev)
3566 /* this handles just right-clicks */
3568 if (ev->button != 3) {
3576 Editor::set_zoom_focus (ZoomFocus f)
3578 string str = zoom_focus_strings[(int)f];
3580 if (str != zoom_focus_selector.get_active_text()) {
3581 zoom_focus_selector.set_active_text (str);
3584 if (zoom_focus != f) {
3591 Editor::cycle_zoom_focus ()
3593 switch (zoom_focus) {
3595 set_zoom_focus (ZoomFocusRight);
3597 case ZoomFocusRight:
3598 set_zoom_focus (ZoomFocusCenter);
3600 case ZoomFocusCenter:
3601 set_zoom_focus (ZoomFocusPlayhead);
3603 case ZoomFocusPlayhead:
3604 set_zoom_focus (ZoomFocusMouse);
3606 case ZoomFocusMouse:
3607 set_zoom_focus (ZoomFocusEdit);
3610 set_zoom_focus (ZoomFocusLeft);
3616 Editor::ensure_float (Window& win)
3618 win.set_transient_for (*this);
3622 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3624 /* recover or initialize pane positions. do this here rather than earlier because
3625 we don't want the positions to change the child allocations, which they seem to do.
3631 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3640 XMLNode* geometry = find_named_node (*node, "geometry");
3642 if (which == static_cast<Paned*> (&edit_pane)) {
3644 if (done & Horizontal) {
3648 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3649 _notebook_shrunk = string_is_affirmative (prop->value ());
3652 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3653 /* initial allocation is 90% to canvas, 10% to notebook */
3654 pos = (int) floor (alloc.get_width() * 0.90f);
3655 snprintf (buf, sizeof(buf), "%d", pos);
3657 pos = atoi (prop->value());
3660 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3661 edit_pane.set_position (pos);
3664 done = (Pane) (done | Horizontal);
3666 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3668 if (done & Vertical) {
3672 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3673 /* initial allocation is 90% to canvas, 10% to summary */
3674 pos = (int) floor (alloc.get_height() * 0.90f);
3675 snprintf (buf, sizeof(buf), "%d", pos);
3678 pos = atoi (prop->value());
3681 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3682 editor_summary_pane.set_position (pos);
3685 done = (Pane) (done | Vertical);
3690 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3692 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3693 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3694 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3695 top_hbox.remove (toolbar_frame);
3700 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3702 if (toolbar_frame.get_parent() == 0) {
3703 top_hbox.pack_end (toolbar_frame);
3708 Editor::set_show_measures (bool yn)
3710 if (_show_measures != yn) {
3713 if ((_show_measures = yn) == true) {
3715 tempo_lines->show();
3717 (void) redraw_measures ();
3724 Editor::toggle_follow_playhead ()
3726 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3728 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3729 set_follow_playhead (tact->get_active());
3733 /** @param yn true to follow playhead, otherwise false.
3734 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3737 Editor::set_follow_playhead (bool yn, bool catch_up)
3739 if (_follow_playhead != yn) {
3740 if ((_follow_playhead = yn) == true && catch_up) {
3742 reset_x_origin_to_follow_playhead ();
3749 Editor::toggle_stationary_playhead ()
3751 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3753 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3754 set_stationary_playhead (tact->get_active());
3759 Editor::set_stationary_playhead (bool yn)
3761 if (_stationary_playhead != yn) {
3762 if ((_stationary_playhead = yn) == true) {
3764 // FIXME need a 3.0 equivalent of this 2.X call
3765 // update_current_screen ();
3772 Editor::playlist_selector () const
3774 return *_playlist_selector;
3778 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3782 switch (_snap_type) {
3787 case SnapToBeatDiv128:
3790 case SnapToBeatDiv64:
3793 case SnapToBeatDiv32:
3796 case SnapToBeatDiv28:
3799 case SnapToBeatDiv24:
3802 case SnapToBeatDiv20:
3805 case SnapToBeatDiv16:
3808 case SnapToBeatDiv14:
3811 case SnapToBeatDiv12:
3814 case SnapToBeatDiv10:
3817 case SnapToBeatDiv8:
3820 case SnapToBeatDiv7:
3823 case SnapToBeatDiv6:
3826 case SnapToBeatDiv5:
3829 case SnapToBeatDiv4:
3832 case SnapToBeatDiv3:
3835 case SnapToBeatDiv2:
3841 return _session->tempo_map().meter_at (position).divisions_per_bar();
3846 case SnapToTimecodeFrame:
3847 case SnapToTimecodeSeconds:
3848 case SnapToTimecodeMinutes:
3851 case SnapToRegionStart:
3852 case SnapToRegionEnd:
3853 case SnapToRegionSync:
3854 case SnapToRegionBoundary:
3864 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3868 ret = nudge_clock->current_duration (pos);
3869 next = ret + 1; /* XXXX fix me */
3875 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3877 ArdourDialog dialog (_("Playlist Deletion"));
3878 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3879 "If it is kept, its audio files will not be cleaned.\n"
3880 "If it is deleted, audio files used by it alone will be cleaned."),
3883 dialog.set_position (WIN_POS_CENTER);
3884 dialog.get_vbox()->pack_start (label);
3888 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3889 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3890 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3892 switch (dialog.run ()) {
3893 case RESPONSE_ACCEPT:
3894 /* delete the playlist */
3898 case RESPONSE_REJECT:
3899 /* keep the playlist */
3911 Editor::audio_region_selection_covers (framepos_t where)
3913 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3914 if ((*a)->region()->covers (where)) {
3923 Editor::prepare_for_cleanup ()
3925 cut_buffer->clear_regions ();
3926 cut_buffer->clear_playlists ();
3928 selection->clear_regions ();
3929 selection->clear_playlists ();
3931 _regions->suspend_redisplay ();
3935 Editor::finish_cleanup ()
3937 _regions->resume_redisplay ();
3941 Editor::transport_loop_location()
3944 return _session->locations()->auto_loop_location();
3951 Editor::transport_punch_location()
3954 return _session->locations()->auto_punch_location();
3961 Editor::control_layout_scroll (GdkEventScroll* ev)
3963 if (Keyboard::some_magic_widget_has_focus()) {
3967 switch (ev->direction) {
3969 scroll_tracks_up_line ();
3973 case GDK_SCROLL_DOWN:
3974 scroll_tracks_down_line ();
3978 /* no left/right handling yet */
3986 Editor::session_state_saved (string)
3989 _snapshots->redisplay ();
3993 Editor::update_tearoff_visibility()
3995 bool visible = Config->get_keep_tearoffs();
3996 _mouse_mode_tearoff->set_visible (visible);
3997 _tools_tearoff->set_visible (visible);
3998 _zoom_tearoff->set_visible (visible);
4002 Editor::maximise_editing_space ()
4014 Editor::restore_editing_space ()
4026 * Make new playlists for a given track and also any others that belong
4027 * to the same active route group with the `edit' property.
4032 Editor::new_playlists (TimeAxisView* v)
4034 begin_reversible_command (_("new playlists"));
4035 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4036 _session->playlists->get (playlists);
4037 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4038 commit_reversible_command ();
4042 * Use a copy of the current playlist for a given track and also any others that belong
4043 * to the same active route group with the `edit' property.
4048 Editor::copy_playlists (TimeAxisView* v)
4050 begin_reversible_command (_("copy playlists"));
4051 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4052 _session->playlists->get (playlists);
4053 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4054 commit_reversible_command ();
4057 /** Clear the current playlist for a given track and also any others that belong
4058 * to the same active route group with the `edit' property.
4063 Editor::clear_playlists (TimeAxisView* v)
4065 begin_reversible_command (_("clear playlists"));
4066 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4067 _session->playlists->get (playlists);
4068 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4069 commit_reversible_command ();
4073 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4075 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4079 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4081 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4085 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4087 atv.clear_playlist ();
4091 Editor::on_key_press_event (GdkEventKey* ev)
4093 return key_press_focus_accelerator_handler (*this, ev);
4097 Editor::on_key_release_event (GdkEventKey* ev)
4099 return Gtk::Window::on_key_release_event (ev);
4100 // return key_press_focus_accelerator_handler (*this, ev);
4103 /** Queue up a change to the viewport x origin.
4104 * @param frame New x origin.
4107 Editor::reset_x_origin (framepos_t frame)
4109 pending_visual_change.add (VisualChange::TimeOrigin);
4110 pending_visual_change.time_origin = frame;
4111 ensure_visual_change_idle_handler ();
4115 Editor::reset_y_origin (double y)
4117 pending_visual_change.add (VisualChange::YOrigin);
4118 pending_visual_change.y_origin = y;
4119 ensure_visual_change_idle_handler ();
4123 Editor::reset_zoom (double fpu)
4125 clamp_frames_per_unit (fpu);
4127 if (fpu == frames_per_unit) {
4131 pending_visual_change.add (VisualChange::ZoomLevel);
4132 pending_visual_change.frames_per_unit = fpu;
4133 ensure_visual_change_idle_handler ();
4137 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4139 reset_x_origin (frame);
4142 if (!no_save_visual) {
4143 undo_visual_stack.push_back (current_visual_state(false));
4147 Editor::VisualState::VisualState (bool with_tracks)
4148 : gui_state (with_tracks ? new GUIObjectState : 0)
4152 Editor::VisualState::~VisualState ()
4157 Editor::VisualState*
4158 Editor::current_visual_state (bool with_tracks)
4160 VisualState* vs = new VisualState (with_tracks);
4161 vs->y_position = vertical_adjustment.get_value();
4162 vs->frames_per_unit = frames_per_unit;
4163 vs->leftmost_frame = leftmost_frame;
4164 vs->zoom_focus = zoom_focus;
4167 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4174 Editor::undo_visual_state ()
4176 if (undo_visual_stack.empty()) {
4180 VisualState* vs = undo_visual_stack.back();
4181 undo_visual_stack.pop_back();
4184 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4186 use_visual_state (*vs);
4190 Editor::redo_visual_state ()
4192 if (redo_visual_stack.empty()) {
4196 VisualState* vs = redo_visual_stack.back();
4197 redo_visual_stack.pop_back();
4199 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4201 use_visual_state (*vs);
4205 Editor::swap_visual_state ()
4207 if (undo_visual_stack.empty()) {
4208 redo_visual_state ();
4210 undo_visual_state ();
4215 Editor::use_visual_state (VisualState& vs)
4217 PBD::Unwinder<bool> nsv (no_save_visual, true);
4219 _routes->suspend_redisplay ();
4221 vertical_adjustment.set_value (vs.y_position);
4223 set_zoom_focus (vs.zoom_focus);
4224 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4227 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4229 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4230 (*i)->reset_visual_state ();
4234 _routes->update_visibility ();
4235 _routes->resume_redisplay ();
4238 /** This is the core function that controls the zoom level of the canvas. It is called
4239 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4240 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4243 Editor::set_frames_per_unit (double fpu)
4246 tempo_lines->tempo_map_changed();
4249 frames_per_unit = fpu;
4251 /* convert fpu to frame count */
4253 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4255 if (frames_per_unit != zoom_range_clock->current_duration()) {
4256 zoom_range_clock->set (frames);
4259 bool const showing_time_selection = selection->time.length() > 0;
4261 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4262 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4263 (*i)->reshow_selection (selection->time);
4267 ZoomChanged (); /* EMIT_SIGNAL */
4269 //reset_scrolling_region ();
4271 if (playhead_cursor) {
4272 playhead_cursor->set_position (playhead_cursor->current_frame);
4275 refresh_location_display();
4276 _summary->set_overlays_dirty ();
4278 update_marker_labels ();
4284 Editor::ensure_visual_change_idle_handler ()
4286 if (pending_visual_change.idle_handler_id < 0) {
4287 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4292 Editor::_idle_visual_changer (void* arg)
4294 return static_cast<Editor*>(arg)->idle_visual_changer ();
4298 Editor::idle_visual_changer ()
4300 /* set_horizontal_position() below (and maybe other calls) call
4301 gtk_main_iteration(), so it's possible that a signal will be handled
4302 half-way through this method. If this signal wants an
4303 idle_visual_changer we must schedule another one after this one, so
4304 mark the idle_handler_id as -1 here to allow that. Also make a note
4305 that we are doing the visual change, so that changes in response to
4306 super-rapid-screen-update can be dropped if we are still processing
4310 pending_visual_change.idle_handler_id = -1;
4311 pending_visual_change.being_handled = true;
4313 VisualChange::Type p = pending_visual_change.pending;
4314 pending_visual_change.pending = (VisualChange::Type) 0;
4316 double const last_time_origin = horizontal_position ();
4318 if (p & VisualChange::ZoomLevel) {
4319 set_frames_per_unit (pending_visual_change.frames_per_unit);
4321 compute_fixed_ruler_scale ();
4323 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4324 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4326 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4327 current_bbt_points_begin, current_bbt_points_end);
4328 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4329 current_bbt_points_begin, current_bbt_points_end);
4330 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4332 if (p & VisualChange::TimeOrigin) {
4333 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4335 if (p & VisualChange::YOrigin) {
4336 vertical_adjustment.set_value (pending_visual_change.y_origin);
4339 if (last_time_origin == horizontal_position ()) {
4340 /* changed signal not emitted */
4341 update_fixed_rulers ();
4342 redisplay_tempo (true);
4345 _summary->set_overlays_dirty ();
4347 pending_visual_change.being_handled = false;
4348 return 0; /* this is always a one-shot call */
4351 struct EditorOrderTimeAxisSorter {
4352 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4353 return a->order () < b->order ();
4358 Editor::sort_track_selection (TrackViewList& sel)
4360 EditorOrderTimeAxisSorter cmp;
4365 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4368 framepos_t where = 0;
4369 EditPoint ep = _edit_point;
4371 if (from_context_menu && (ep == EditAtMouse)) {
4372 return event_frame (&context_click_event, 0, 0);
4375 if (entered_marker) {
4376 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4377 return entered_marker->position();
4380 if (ignore_playhead && ep == EditAtPlayhead) {
4381 ep = EditAtSelectedMarker;
4385 case EditAtPlayhead:
4386 where = _session->audible_frame();
4387 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4390 case EditAtSelectedMarker:
4391 if (!selection->markers.empty()) {
4393 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4396 where = loc->start();
4400 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4408 if (!mouse_frame (where, ignored)) {
4409 /* XXX not right but what can we do ? */
4413 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4421 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4423 if (!_session) return;
4425 begin_reversible_command (cmd);
4429 if ((tll = transport_loop_location()) == 0) {
4430 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4431 XMLNode &before = _session->locations()->get_state();
4432 _session->locations()->add (loc, true);
4433 _session->set_auto_loop_location (loc);
4434 XMLNode &after = _session->locations()->get_state();
4435 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4437 XMLNode &before = tll->get_state();
4438 tll->set_hidden (false, this);
4439 tll->set (start, end);
4440 XMLNode &after = tll->get_state();
4441 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4444 commit_reversible_command ();
4448 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4450 if (!_session) return;
4452 begin_reversible_command (cmd);
4456 if ((tpl = transport_punch_location()) == 0) {
4457 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4458 XMLNode &before = _session->locations()->get_state();
4459 _session->locations()->add (loc, true);
4460 _session->set_auto_loop_location (loc);
4461 XMLNode &after = _session->locations()->get_state();
4462 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4465 XMLNode &before = tpl->get_state();
4466 tpl->set_hidden (false, this);
4467 tpl->set (start, end);
4468 XMLNode &after = tpl->get_state();
4469 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4472 commit_reversible_command ();
4475 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4476 * @param rs List to which found regions are added.
4477 * @param where Time to look at.
4478 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4481 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4483 const TrackViewList* tracks;
4486 tracks = &track_views;
4491 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4493 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4496 boost::shared_ptr<Track> tr;
4497 boost::shared_ptr<Playlist> pl;
4499 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4501 boost::shared_ptr<RegionList> regions = pl->regions_at (
4502 (framepos_t) floor ( (double) where * tr->speed()));
4504 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4505 RegionView* rv = rtv->view()->find_view (*i);
4516 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4518 const TrackViewList* tracks;
4521 tracks = &track_views;
4526 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4527 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4529 boost::shared_ptr<Track> tr;
4530 boost::shared_ptr<Playlist> pl;
4532 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4534 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4535 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4537 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4539 RegionView* rv = rtv->view()->find_view (*i);
4550 /** Start with regions that are selected. Then add equivalent regions
4551 * on tracks in the same active edit-enabled route group as any of
4552 * the regions that we started with.
4556 Editor::get_regions_from_selection ()
4558 return get_equivalent_regions (selection->regions, ARDOUR::Properties::select.property_id);
4561 /** Get regions using the following method:
4563 * Make an initial region list using the selected regions, unless
4564 * the edit point is `mouse' and the mouse is over an unselected
4565 * region. In this case, start with just that region.
4567 * Then, add equivalent regions in active edit groups to the region list.
4569 * Then, search the list of selected tracks to find any selected tracks which
4570 * do not contain regions already in the region list. If there are no selected
4571 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4572 * than just the selected.
4574 * Add any regions that are under the edit point on these tracks to get the
4575 * returned region list.
4577 * The rationale here is that the mouse edit point is special in that
4578 * its position describes both a time and a track; the other edit
4579 * modes only describe a time. Hence if the edit point is `mouse' we
4580 * ignore selected tracks, as we assume the user means something by
4581 * pointing at a particular track. Also in this case we take note of
4582 * the region directly under the edit point, as there is always just one
4583 * (rather than possibly several with non-mouse edit points).
4587 Editor::get_regions_from_selection_and_edit_point ()
4589 RegionSelection regions;
4591 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4592 regions.add (entered_regionview);
4594 regions = selection->regions;
4597 TrackViewList tracks;
4599 if (_edit_point != EditAtMouse) {
4600 tracks = selection->tracks;
4603 /* Add any other regions that are in the same
4604 edit-activated route group as one of our regions.
4606 regions = get_equivalent_regions (regions, ARDOUR::Properties::select.property_id);
4607 framepos_t const where = get_preferred_edit_position ();
4609 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4610 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4611 * is enabled, so consider all tracks
4613 tracks = track_views;
4616 if (!tracks.empty()) {
4617 /* now search the selected tracks for tracks which don't
4618 already contain regions to be acted upon, and get regions at
4619 the edit point on those tracks too.
4621 TrackViewList tracks_without_relevant_regions;
4623 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4624 if (!regions.involves (**t)) {
4625 /* there are no equivalent regions on this track */
4626 tracks_without_relevant_regions.push_back (*t);
4630 if (!tracks_without_relevant_regions.empty()) {
4631 /* there are some selected tracks with neither selected
4632 * regions or their equivalents: act upon all regions in
4635 get_regions_at (regions, where, tracks_without_relevant_regions);
4642 /** Start with regions that are selected, or the entered regionview if none are selected.
4643 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4644 * of the regions that we started with.
4648 Editor::get_regions_from_selection_and_entered ()
4650 RegionSelection regions = selection->regions;
4652 if (regions.empty() && entered_regionview) {
4653 regions.add (entered_regionview);
4656 return get_equivalent_regions (regions, ARDOUR::Properties::select.property_id);
4660 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4662 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4664 RouteTimeAxisView* tatv;
4666 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4668 boost::shared_ptr<Playlist> pl;
4669 vector<boost::shared_ptr<Region> > results;
4671 boost::shared_ptr<Track> tr;
4673 if ((tr = tatv->track()) == 0) {
4678 if ((pl = (tr->playlist())) != 0) {
4679 if (src_comparison) {
4680 pl->get_source_equivalent_regions (region, results);
4682 pl->get_region_list_equivalent_regions (region, results);
4686 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4687 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4688 regions.push_back (marv);
4697 Editor::show_rhythm_ferret ()
4699 if (rhythm_ferret == 0) {
4700 rhythm_ferret = new RhythmFerret(*this);
4703 rhythm_ferret->set_session (_session);
4704 rhythm_ferret->show ();
4705 rhythm_ferret->present ();
4709 Editor::first_idle ()
4711 MessageDialog* dialog = 0;
4713 if (track_views.size() > 1) {
4714 dialog = new MessageDialog (
4716 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4720 ARDOUR_UI::instance()->flush_pending ();
4723 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4727 // first idle adds route children (automation tracks), so we need to redisplay here
4728 _routes->redisplay ();
4735 Editor::_idle_resize (gpointer arg)
4737 return ((Editor*)arg)->idle_resize ();
4741 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4743 if (resize_idle_id < 0) {
4744 resize_idle_id = g_idle_add (_idle_resize, this);
4745 _pending_resize_amount = 0;
4748 /* make a note of the smallest resulting height, so that we can clamp the
4749 lower limit at TimeAxisView::hSmall */
4751 int32_t min_resulting = INT32_MAX;
4753 _pending_resize_amount += h;
4754 _pending_resize_view = view;
4756 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4758 if (selection->tracks.contains (_pending_resize_view)) {
4759 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4760 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4764 if (min_resulting < 0) {
4769 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4770 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4774 /** Handle pending resizing of tracks */
4776 Editor::idle_resize ()
4778 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4780 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4781 selection->tracks.contains (_pending_resize_view)) {
4783 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4784 if (*i != _pending_resize_view) {
4785 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4790 _pending_resize_amount = 0;
4792 _group_tabs->set_dirty ();
4793 resize_idle_id = -1;
4801 ENSURE_GUI_THREAD (*this, &Editor::located);
4804 playhead_cursor->set_position (_session->audible_frame ());
4805 if (_follow_playhead && !_pending_initial_locate) {
4806 reset_x_origin_to_follow_playhead ();
4810 _pending_locate_request = false;
4811 _pending_initial_locate = false;
4815 Editor::region_view_added (RegionView *)
4817 _summary->set_dirty ();
4821 Editor::region_view_removed ()
4823 _summary->set_dirty ();
4827 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4829 TrackViewList::const_iterator j = track_views.begin ();
4830 while (j != track_views.end()) {
4831 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4832 if (rtv && rtv->route() == r) {
4843 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4847 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4848 TimeAxisView* tv = axis_view_from_route (*i);
4858 Editor::add_routes (RouteList& routes)
4860 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4862 RouteTimeAxisView *rtv;
4863 list<RouteTimeAxisView*> new_views;
4865 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4866 boost::shared_ptr<Route> route = (*x);
4868 if (route->is_hidden() || route->is_monitor()) {
4872 DataType dt = route->input()->default_type();
4874 if (dt == ARDOUR::DataType::AUDIO) {
4875 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4876 rtv->set_route (route);
4877 } else if (dt == ARDOUR::DataType::MIDI) {
4878 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4879 rtv->set_route (route);
4881 throw unknown_type();
4884 new_views.push_back (rtv);
4885 track_views.push_back (rtv);
4887 rtv->effective_gain_display ();
4889 if (internal_editing()) {
4890 rtv->enter_internal_edit_mode ();
4892 rtv->leave_internal_edit_mode ();
4895 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4896 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4899 _routes->routes_added (new_views);
4900 _summary->routes_added (new_views);
4902 if (show_editor_mixer_when_tracks_arrive) {
4903 show_editor_mixer (true);
4906 editor_list_button.set_sensitive (true);
4910 Editor::timeaxisview_deleted (TimeAxisView *tv)
4912 if (_session && _session->deletion_in_progress()) {
4913 /* the situation is under control */
4917 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4919 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4921 _routes->route_removed (tv);
4923 if (tv == entered_track) {
4927 TimeAxisView::Children c = tv->get_child_list ();
4928 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4929 if (entered_track == i->get()) {
4934 /* remove it from the list of track views */
4936 TrackViewList::iterator i;
4938 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4939 i = track_views.erase (i);
4942 /* update whatever the current mixer strip is displaying, if revelant */
4944 boost::shared_ptr<Route> route;
4947 route = rtav->route ();
4950 if (current_mixer_strip && current_mixer_strip->route() == route) {
4952 TimeAxisView* next_tv;
4954 if (track_views.empty()) {
4956 } else if (i == track_views.end()) {
4957 next_tv = track_views.front();
4964 set_selected_mixer_strip (*next_tv);
4966 /* make the editor mixer strip go away setting the
4967 * button to inactive (which also unticks the menu option)
4970 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4976 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4978 if (apply_to_selection) {
4979 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4981 TrackSelection::iterator j = i;
4984 hide_track_in_display (*i, false);
4989 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4991 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4992 // this will hide the mixer strip
4993 set_selected_mixer_strip (*tv);
4996 _routes->hide_track_in_display (*tv);
5001 Editor::sync_track_view_list_and_routes ()
5003 track_views = TrackViewList (_routes->views ());
5005 _summary->set_dirty ();
5006 _group_tabs->set_dirty ();
5008 return false; // do not call again (until needed)
5012 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5014 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5019 /** Find a RouteTimeAxisView by the ID of its route */
5021 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5023 RouteTimeAxisView* v;
5025 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5026 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5027 if(v->route()->id() == id) {
5037 Editor::fit_route_group (RouteGroup *g)
5039 TrackViewList ts = axis_views_from_routes (g->route_list ());
5044 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5046 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5049 _session->cancel_audition ();
5053 if (_session->is_auditioning()) {
5054 _session->cancel_audition ();
5055 if (r == last_audition_region) {
5060 _session->audition_region (r);
5061 last_audition_region = r;
5066 Editor::hide_a_region (boost::shared_ptr<Region> r)
5068 r->set_hidden (true);
5072 Editor::show_a_region (boost::shared_ptr<Region> r)
5074 r->set_hidden (false);
5078 Editor::audition_region_from_region_list ()
5080 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5084 Editor::hide_region_from_region_list ()
5086 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5090 Editor::show_region_in_region_list ()
5092 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5096 Editor::step_edit_status_change (bool yn)
5099 start_step_editing ();
5101 stop_step_editing ();
5106 Editor::start_step_editing ()
5108 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5112 Editor::stop_step_editing ()
5114 step_edit_connection.disconnect ();
5118 Editor::check_step_edit ()
5120 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5121 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5123 mtv->check_step_edit ();
5127 return true; // do it again, till we stop
5131 Editor::scroll_press (Direction dir)
5133 ++_scroll_callbacks;
5135 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5136 /* delay the first auto-repeat */
5142 scroll_backward (1);
5150 scroll_tracks_up_line ();
5154 scroll_tracks_down_line ();
5158 /* do hacky auto-repeat */
5159 if (!_scroll_connection.connected ()) {
5161 _scroll_connection = Glib::signal_timeout().connect (
5162 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5165 _scroll_callbacks = 0;
5172 Editor::scroll_release ()
5174 _scroll_connection.disconnect ();
5177 /** Queue a change for the Editor viewport x origin to follow the playhead */
5179 Editor::reset_x_origin_to_follow_playhead ()
5181 framepos_t const frame = playhead_cursor->current_frame;
5183 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5185 if (_session->transport_speed() < 0) {
5187 if (frame > (current_page_frames() / 2)) {
5188 center_screen (frame-(current_page_frames()/2));
5190 center_screen (current_page_frames()/2);
5197 if (frame < leftmost_frame) {
5199 if (_session->transport_rolling()) {
5200 /* rolling; end up with the playhead at the right of the page */
5201 l = frame - current_page_frames ();
5203 /* not rolling: end up with the playhead 1/4 of the way along the page */
5204 l = frame - current_page_frames() / 4;
5208 if (_session->transport_rolling()) {
5209 /* rolling: end up with the playhead on the left of the page */
5212 /* not rolling: end up with the playhead 3/4 of the way along the page */
5213 l = frame - 3 * current_page_frames() / 4;
5221 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5227 Editor::super_rapid_screen_update ()
5229 if (!_session || !_session->engine().running()) {
5233 /* METERING / MIXER STRIPS */
5235 /* update track meters, if required */
5236 if (is_mapped() && meters_running) {
5237 RouteTimeAxisView* rtv;
5238 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5239 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5240 rtv->fast_update ();
5245 /* and any current mixer strip */
5246 if (current_mixer_strip) {
5247 current_mixer_strip->fast_update ();
5250 /* PLAYHEAD AND VIEWPORT */
5252 framepos_t const frame = _session->audible_frame();
5254 /* There are a few reasons why we might not update the playhead / viewport stuff:
5256 * 1. we don't update things when there's a pending locate request, otherwise
5257 * when the editor requests a locate there is a chance that this method
5258 * will move the playhead before the locate request is processed, causing
5260 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5261 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5264 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5266 last_update_frame = frame;
5268 if (!_dragging_playhead) {
5269 playhead_cursor->set_position (frame);
5272 if (!_stationary_playhead) {
5274 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5275 /* We only do this if we aren't already
5276 handling a visual change (ie if
5277 pending_visual_change.being_handled is
5278 false) so that these requests don't stack
5279 up there are too many of them to handle in
5282 reset_x_origin_to_follow_playhead ();
5287 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5291 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5292 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5293 if (target <= 0.0) {
5296 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5297 target = (target * 0.15) + (current * 0.85);
5303 set_horizontal_position (current);
5312 Editor::session_going_away ()
5314 _have_idled = false;
5316 _session_connections.drop_connections ();
5318 super_rapid_screen_update_connection.disconnect ();
5320 selection->clear ();
5321 cut_buffer->clear ();
5323 clicked_regionview = 0;
5324 clicked_axisview = 0;
5325 clicked_routeview = 0;
5326 entered_regionview = 0;
5328 last_update_frame = 0;
5331 playhead_cursor->canvas_item.hide ();
5333 /* rip everything out of the list displays */
5337 _route_groups->clear ();
5339 /* do this first so that deleting a track doesn't reset cms to null
5340 and thus cause a leak.
5343 if (current_mixer_strip) {
5344 if (current_mixer_strip->get_parent() != 0) {
5345 global_hpacker.remove (*current_mixer_strip);
5347 delete current_mixer_strip;
5348 current_mixer_strip = 0;
5351 /* delete all trackviews */
5353 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5356 track_views.clear ();
5358 zoom_range_clock->set_session (0);
5359 nudge_clock->set_session (0);
5361 editor_list_button.set_active(false);
5362 editor_list_button.set_sensitive(false);
5364 /* clear tempo/meter rulers */
5365 remove_metric_marks ();
5367 clear_marker_display ();
5369 stop_step_editing ();
5371 /* get rid of any existing editor mixer strip */
5373 WindowTitle title(Glib::get_application_name());
5374 title += _("Editor");
5376 set_title (title.get_string());
5378 SessionHandlePtr::session_going_away ();
5383 Editor::show_editor_list (bool yn)
5386 _the_notebook.show ();
5388 _the_notebook.hide ();
5393 Editor::change_region_layering_order (bool from_context_menu)
5395 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5397 if (!clicked_routeview) {
5398 if (layering_order_editor) {
5399 layering_order_editor->hide ();
5404 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5410 boost::shared_ptr<Playlist> pl = track->playlist();
5416 if (layering_order_editor == 0) {
5417 layering_order_editor = new RegionLayeringOrderEditor (*this);
5418 layering_order_editor->set_position (WIN_POS_MOUSE);
5421 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5422 layering_order_editor->maybe_present ();
5426 Editor::update_region_layering_order_editor ()
5428 if (layering_order_editor && layering_order_editor->is_visible ()) {
5429 change_region_layering_order (true);
5434 Editor::setup_fade_images ()
5436 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5437 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5438 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5439 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5440 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5442 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5443 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5444 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5445 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5446 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5448 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5449 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5450 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5451 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5452 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5454 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5455 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5456 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5457 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5458 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5462 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5464 Editor::action_menu_item (std::string const & name)
5466 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5469 return *manage (a->create_menu_item ());
5473 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5475 EventBox* b = manage (new EventBox);
5476 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5477 Label* l = manage (new Label (name));
5481 _the_notebook.append_page (widget, *b);
5485 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5487 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5488 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5491 if (ev->type == GDK_2BUTTON_PRESS) {
5493 /* double-click on a notebook tab shrinks or expands the notebook */
5495 if (_notebook_shrunk) {
5496 if (pre_notebook_shrink_pane_width) {
5497 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5499 _notebook_shrunk = false;
5501 pre_notebook_shrink_pane_width = edit_pane.get_position();
5503 /* this expands the LHS of the edit pane to cover the notebook
5504 PAGE but leaves the tabs visible.
5506 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5507 _notebook_shrunk = true;
5515 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5517 using namespace Menu_Helpers;
5519 MenuList& items = _control_point_context_menu.items ();
5522 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5523 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5524 if (!can_remove_control_point (item)) {
5525 items.back().set_sensitive (false);
5528 _control_point_context_menu.popup (event->button.button, event->button.time);
5532 Editor::shift_key_released ()
5534 _stepping_axis_view = 0;