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 #ifdef WITH_VIDEOTIMELINE
250 , videotl_label (_("Video Timeline"))
252 , edit_packer (4, 4, true)
254 /* the values here don't matter: layout widgets
255 reset them as needed.
258 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260 /* tool bar related */
262 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
264 , toolbar_selection_clock_table (2,3)
266 , automation_mode_button (_("mode"))
268 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271 , image_socket_listener(0)
276 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
277 , meters_running(false)
278 , _pending_locate_request (false)
279 , _pending_initial_locate (false)
280 , _last_cut_copy_source_track (0)
282 , _region_selection_change_updates_region_list (true)
283 , _following_mixer_selection (false)
284 , _control_point_toggled_on_press (false)
285 , _stepping_axis_view (0)
289 /* we are a singleton */
291 PublicEditor::_instance = this;
295 selection = new Selection (this);
296 cut_buffer = new Selection (this);
298 clicked_regionview = 0;
299 clicked_axisview = 0;
300 clicked_routeview = 0;
301 clicked_control_point = 0;
302 last_update_frame = 0;
303 pre_press_cursor = 0;
304 _drags = new DragManager (this);
305 current_mixer_strip = 0;
308 snap_type_strings = I18N (_snap_type_strings);
309 snap_mode_strings = I18N (_snap_mode_strings);
310 zoom_focus_strings = I18N (_zoom_focus_strings);
311 edit_point_strings = I18N (_edit_point_strings);
312 #ifdef USE_RUBBERBAND
313 rb_opt_strings = I18N (_rb_opt_strings);
317 snap_threshold = 5.0;
318 bbt_beat_subdivision = 4;
321 last_autoscroll_x = 0;
322 last_autoscroll_y = 0;
323 autoscroll_active = false;
324 autoscroll_timeout_tag = -1;
329 current_interthread_info = 0;
330 _show_measures = true;
332 show_gain_after_trim = false;
334 have_pending_keyboard_selection = false;
335 _follow_playhead = true;
336 _stationary_playhead = false;
337 editor_ruler_menu = 0;
338 no_ruler_shown_update = false;
340 range_marker_menu = 0;
341 marker_menu_item = 0;
342 tempo_or_meter_marker_menu = 0;
343 transport_marker_menu = 0;
344 new_transport_marker_menu = 0;
345 editor_mixer_strip_width = Wide;
346 show_editor_mixer_when_tracks_arrive = false;
347 region_edit_menu_split_multichannel_item = 0;
348 region_edit_menu_split_item = 0;
351 current_stepping_trackview = 0;
353 entered_regionview = 0;
355 clear_entered_track = false;
358 button_release_can_deselect = true;
359 _dragging_playhead = false;
360 _dragging_edit_point = false;
361 select_new_marker = false;
363 layering_order_editor = 0;
364 no_save_visual = false;
366 within_track_canvas = false;
368 scrubbing_direction = 0;
372 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
373 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
374 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
375 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
376 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
378 _edit_point = EditAtMouse;
379 _internal_editing = false;
380 current_canvas_cursor = 0;
382 frames_per_unit = 2048; /* too early to use reset_zoom () */
384 _scroll_callbacks = 0;
386 zoom_focus = ZoomFocusLeft;
387 set_zoom_focus (ZoomFocusLeft);
388 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
390 bbt_label.set_name ("EditorRulerLabel");
391 bbt_label.set_size_request (-1, (int)timebar_height);
392 bbt_label.set_alignment (1.0, 0.5);
393 bbt_label.set_padding (5,0);
395 bbt_label.set_no_show_all();
396 minsec_label.set_name ("EditorRulerLabel");
397 minsec_label.set_size_request (-1, (int)timebar_height);
398 minsec_label.set_alignment (1.0, 0.5);
399 minsec_label.set_padding (5,0);
400 minsec_label.hide ();
401 minsec_label.set_no_show_all();
402 timecode_label.set_name ("EditorRulerLabel");
403 timecode_label.set_size_request (-1, (int)timebar_height);
404 timecode_label.set_alignment (1.0, 0.5);
405 timecode_label.set_padding (5,0);
406 timecode_label.hide ();
407 timecode_label.set_no_show_all();
408 samples_label.set_name ("EditorRulerLabel");
409 samples_label.set_size_request (-1, (int)timebar_height);
410 samples_label.set_alignment (1.0, 0.5);
411 samples_label.set_padding (5,0);
412 samples_label.hide ();
413 samples_label.set_no_show_all();
415 tempo_label.set_name ("EditorRulerLabel");
416 tempo_label.set_size_request (-1, (int)timebar_height);
417 tempo_label.set_alignment (1.0, 0.5);
418 tempo_label.set_padding (5,0);
420 tempo_label.set_no_show_all();
422 meter_label.set_name ("EditorRulerLabel");
423 meter_label.set_size_request (-1, (int)timebar_height);
424 meter_label.set_alignment (1.0, 0.5);
425 meter_label.set_padding (5,0);
427 meter_label.set_no_show_all();
429 mark_label.set_name ("EditorRulerLabel");
430 mark_label.set_size_request (-1, (int)timebar_height);
431 mark_label.set_alignment (1.0, 0.5);
432 mark_label.set_padding (5,0);
434 mark_label.set_no_show_all();
436 cd_mark_label.set_name ("EditorRulerLabel");
437 cd_mark_label.set_size_request (-1, (int)timebar_height);
438 cd_mark_label.set_alignment (1.0, 0.5);
439 cd_mark_label.set_padding (5,0);
440 cd_mark_label.hide();
441 cd_mark_label.set_no_show_all();
443 #ifdef WITH_VIDEOTIMELINE
444 videotl_bar_height = 4;
445 videotl_label.set_name ("EditorRulerLabel");
446 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
447 videotl_label.set_alignment (1.0, 0.5);
448 videotl_label.set_padding (5,0);
449 videotl_label.hide();
450 videotl_label.set_no_show_all();
453 range_mark_label.set_name ("EditorRulerLabel");
454 range_mark_label.set_size_request (-1, (int)timebar_height);
455 range_mark_label.set_alignment (1.0, 0.5);
456 range_mark_label.set_padding (5,0);
457 range_mark_label.hide();
458 range_mark_label.set_no_show_all();
460 transport_mark_label.set_name ("EditorRulerLabel");
461 transport_mark_label.set_size_request (-1, (int)timebar_height);
462 transport_mark_label.set_alignment (1.0, 0.5);
463 transport_mark_label.set_padding (5,0);
464 transport_mark_label.hide();
465 transport_mark_label.set_no_show_all();
467 initialize_rulers ();
468 initialize_canvas ();
470 _summary = new EditorSummary (this);
472 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
473 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
475 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
477 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
478 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
480 edit_controls_vbox.set_spacing (0);
481 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
482 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
484 HBox* h = manage (new HBox);
485 _group_tabs = new EditorGroupTabs (this);
486 h->pack_start (*_group_tabs, PACK_SHRINK);
487 h->pack_start (edit_controls_vbox);
488 controls_layout.add (*h);
490 controls_layout.set_name ("EditControlsBase");
491 controls_layout.add_events (Gdk::SCROLL_MASK);
492 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
494 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
495 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
497 _cursors = new MouseCursors;
499 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
500 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
501 0.0, 1.0, 100.0, 1.0));
503 pad_line_1->property_color_rgba() = 0xFF0000FF;
508 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
509 time_canvas_vbox.set_size_request (-1, -1);
511 ruler_label_event_box.add (ruler_label_vbox);
512 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
513 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
515 time_button_event_box.add (time_button_vbox);
516 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
517 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
519 /* these enable us to have a dedicated window (for cursor setting, etc.)
520 for the canvas areas.
523 track_canvas_event_box.add (*track_canvas);
525 time_canvas_event_box.add (time_canvas_vbox);
526 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
528 edit_packer.set_col_spacings (0);
529 edit_packer.set_row_spacings (0);
530 edit_packer.set_homogeneous (false);
531 edit_packer.set_border_width (0);
532 edit_packer.set_name ("EditorWindow");
534 /* labels for the rulers */
535 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
536 /* labels for the marker "tracks" */
537 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
539 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
541 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
543 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
545 bottom_hbox.set_border_width (2);
546 bottom_hbox.set_spacing (3);
548 _route_groups = new EditorRouteGroups (this);
549 _routes = new EditorRoutes (this);
550 _regions = new EditorRegions (this);
551 _snapshots = new EditorSnapshots (this);
552 _locations = new EditorLocations (this);
554 add_notebook_page (_("Regions"), _regions->widget ());
555 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
556 add_notebook_page (_("Snapshots"), _snapshots->widget ());
557 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
558 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
560 _the_notebook.set_show_tabs (true);
561 _the_notebook.set_scrollable (true);
562 _the_notebook.popup_disable ();
563 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
564 _the_notebook.show_all ();
566 _notebook_shrunk = false;
568 editor_summary_pane.pack1(edit_packer);
570 Button* summary_arrows_left_left = manage (new Button);
571 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
572 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
573 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
575 Button* summary_arrows_left_right = manage (new Button);
576 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
577 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
578 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
580 VBox* summary_arrows_left = manage (new VBox);
581 summary_arrows_left->pack_start (*summary_arrows_left_left);
582 summary_arrows_left->pack_start (*summary_arrows_left_right);
584 Button* summary_arrows_right_up = manage (new Button);
585 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
586 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
587 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
589 Button* summary_arrows_right_down = manage (new Button);
590 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
591 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
592 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
594 VBox* summary_arrows_right = manage (new VBox);
595 summary_arrows_right->pack_start (*summary_arrows_right_up);
596 summary_arrows_right->pack_start (*summary_arrows_right_down);
598 Frame* summary_frame = manage (new Frame);
599 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
601 summary_frame->add (*_summary);
602 summary_frame->show ();
604 _summary_hbox.pack_start (*summary_arrows_left, false, false);
605 _summary_hbox.pack_start (*summary_frame, true, true);
606 _summary_hbox.pack_start (*summary_arrows_right, false, false);
608 editor_summary_pane.pack2 (_summary_hbox);
610 edit_pane.pack1 (editor_summary_pane, true, true);
611 edit_pane.pack2 (_the_notebook, false, true);
613 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
615 /* XXX: editor_summary_pane might need similar to the edit_pane */
617 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
619 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
620 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
622 top_hbox.pack_start (toolbar_frame);
624 HBox *hbox = manage (new HBox);
625 hbox->pack_start (edit_pane, true, true);
627 global_vpacker.pack_start (top_hbox, false, false);
628 global_vpacker.pack_start (*hbox, true, true);
630 global_hpacker.pack_start (global_vpacker, true, true);
632 set_name ("EditorWindow");
633 add_accel_group (ActionManager::ui_manager->get_accel_group());
635 status_bar_hpacker.show ();
637 vpacker.pack_end (status_bar_hpacker, false, false);
638 vpacker.pack_end (global_hpacker, true, true);
640 /* register actions now so that set_state() can find them and set toggles/checks etc */
643 /* when we start using our own keybinding system for the editor, this
644 * will be uncommented
650 _snap_type = SnapToBeat;
651 set_snap_to (_snap_type);
652 _snap_mode = SnapOff;
653 set_snap_mode (_snap_mode);
654 set_mouse_mode (MouseObject, true);
655 pre_internal_mouse_mode = MouseObject;
656 pre_internal_snap_type = _snap_type;
657 pre_internal_snap_mode = _snap_mode;
658 internal_snap_type = _snap_type;
659 internal_snap_mode = _snap_mode;
660 set_edit_point_preference (EditAtMouse, true);
662 _playlist_selector = new PlaylistSelector();
663 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
665 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
669 nudge_forward_button.set_name ("zoom button");
670 nudge_forward_button.add_elements (ArdourButton::FlatFace);
671 nudge_forward_button.set_image(::get_icon("nudge_right"));
673 nudge_backward_button.set_name ("zoom button");
674 nudge_backward_button.add_elements (ArdourButton::FlatFace);
675 nudge_backward_button.set_image(::get_icon("nudge_left"));
677 fade_context_menu.set_name ("ArdourContextMenu");
679 /* icons, titles, WM stuff */
681 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
682 Glib::RefPtr<Gdk::Pixbuf> icon;
684 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
685 window_icons.push_back (icon);
687 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
688 window_icons.push_back (icon);
690 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
691 window_icons.push_back (icon);
693 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
694 window_icons.push_back (icon);
696 if (!window_icons.empty()) {
697 // set_icon_list (window_icons);
698 set_default_icon_list (window_icons);
701 WindowTitle title(Glib::get_application_name());
702 title += _("Editor");
703 set_title (title.get_string());
704 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
707 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
709 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
710 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
712 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
714 /* allow external control surfaces/protocols to do various things */
716 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
717 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
718 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
719 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
720 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
721 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
722 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
723 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
724 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
725 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
726 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
727 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
728 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
729 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
731 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
732 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
733 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
734 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
735 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
737 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
739 /* problematic: has to return a value and thus cannot be x-thread */
741 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
743 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
745 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
747 _ignore_region_action = false;
748 _last_region_menu_was_main = false;
749 _popup_region_menu_item = 0;
751 _show_marker_lines = false;
752 _over_region_trim_target = false;
754 /* Button bindings */
756 button_bindings = new Bindings;
758 XMLNode* node = button_settings();
760 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
761 button_bindings->load (**i);
768 setup_fade_images ();
774 if(image_socket_listener) {
775 if(image_socket_listener->is_connected())
777 image_socket_listener->close_connection() ;
780 delete image_socket_listener ;
781 image_socket_listener = 0 ;
785 delete button_bindings;
787 delete _route_groups;
793 Editor::button_settings () const
795 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
796 XMLNode* node = find_named_node (*settings, X_("Buttons"));
799 node = new XMLNode (X_("Buttons"));
806 Editor::add_toplevel_controls (Container& cont)
808 vpacker.pack_start (cont, false, false);
813 Editor::get_smart_mode () const
815 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
819 Editor::catch_vanishing_regionview (RegionView *rv)
821 /* note: the selection will take care of the vanishing
822 audioregionview by itself.
825 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
829 if (clicked_regionview == rv) {
830 clicked_regionview = 0;
833 if (entered_regionview == rv) {
834 set_entered_regionview (0);
837 if (!_all_region_actions_sensitized) {
838 sensitize_all_region_actions (true);
841 _over_region_trim_target = false;
845 Editor::set_entered_regionview (RegionView* rv)
847 if (rv == entered_regionview) {
851 if (entered_regionview) {
852 entered_regionview->exited ();
855 if ((entered_regionview = rv) != 0) {
856 entered_regionview->entered (internal_editing ());
859 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
860 /* This RegionView entry might have changed what region actions
861 are allowed, so sensitize them all in case a key is pressed.
863 sensitize_all_region_actions (true);
868 Editor::set_entered_track (TimeAxisView* tav)
871 entered_track->exited ();
874 if ((entered_track = tav) != 0) {
875 entered_track->entered ();
880 Editor::show_window ()
882 if (!is_visible ()) {
885 /* XXX: this is a bit unfortunate; it would probably
886 be nicer if we could just call show () above rather
887 than needing the show_all ()
890 /* re-hide stuff if necessary */
891 editor_list_button_toggled ();
892 parameter_changed ("show-summary");
893 parameter_changed ("show-group-tabs");
894 parameter_changed ("show-zoom-tools");
896 /* now reset all audio_time_axis heights, because widgets might need
902 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
903 tv = (static_cast<TimeAxisView*>(*i));
907 if (current_mixer_strip) {
908 current_mixer_strip->hide_things ();
909 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
917 Editor::instant_save ()
919 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
924 _session->add_instant_xml(get_state());
926 Config->add_instant_xml(get_state());
931 Editor::zoom_adjustment_changed ()
937 double fpu = zoom_range_clock->current_duration() / _canvas_width;
938 bool clamped = clamp_frames_per_unit (fpu);
941 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
948 Editor::control_vertical_zoom_in_all ()
950 tav_zoom_smooth (false, true);
954 Editor::control_vertical_zoom_out_all ()
956 tav_zoom_smooth (true, true);
960 Editor::control_vertical_zoom_in_selected ()
962 tav_zoom_smooth (false, false);
966 Editor::control_vertical_zoom_out_selected ()
968 tav_zoom_smooth (true, false);
972 Editor::control_view (uint32_t view)
974 goto_visual_state (view);
978 Editor::control_unselect ()
980 selection->clear_tracks ();
984 Editor::control_select (uint32_t rid, Selection::Operation op)
986 /* handles the (static) signal from the ControlProtocol class that
987 * requests setting the selected track to a given RID
994 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1000 TimeAxisView* tav = axis_view_from_route (r);
1004 case Selection::Add:
1005 selection->add (tav);
1007 case Selection::Toggle:
1008 selection->toggle (tav);
1010 case Selection::Extend:
1012 case Selection::Set:
1013 selection->set (tav);
1017 selection->clear_tracks ();
1022 Editor::control_step_tracks_up ()
1024 scroll_tracks_up_line ();
1028 Editor::control_step_tracks_down ()
1030 scroll_tracks_down_line ();
1034 Editor::control_scroll (float fraction)
1036 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1042 double step = fraction * current_page_frames();
1045 _control_scroll_target is an optional<T>
1047 it acts like a pointer to an framepos_t, with
1048 a operator conversion to boolean to check
1049 that it has a value could possibly use
1050 playhead_cursor->current_frame to store the
1051 value and a boolean in the class to know
1052 when it's out of date
1055 if (!_control_scroll_target) {
1056 _control_scroll_target = _session->transport_frame();
1057 _dragging_playhead = true;
1060 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1061 *_control_scroll_target = 0;
1062 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1063 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1065 *_control_scroll_target += (framepos_t) floor (step);
1068 /* move visuals, we'll catch up with it later */
1070 playhead_cursor->set_position (*_control_scroll_target);
1071 UpdateAllTransportClocks (*_control_scroll_target);
1073 if (*_control_scroll_target > (current_page_frames() / 2)) {
1074 /* try to center PH in window */
1075 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1081 Now we do a timeout to actually bring the session to the right place
1082 according to the playhead. This is to avoid reading disk buffers on every
1083 call to control_scroll, which is driven by ScrollTimeline and therefore
1084 probably by a control surface wheel which can generate lots of events.
1086 /* cancel the existing timeout */
1088 control_scroll_connection.disconnect ();
1090 /* add the next timeout */
1092 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1096 Editor::deferred_control_scroll (framepos_t /*target*/)
1098 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1099 // reset for next stream
1100 _control_scroll_target = boost::none;
1101 _dragging_playhead = false;
1106 Editor::access_action (std::string action_group, std::string action_item)
1112 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1115 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1123 Editor::on_realize ()
1125 Window::on_realize ();
1130 Editor::map_position_change (framepos_t frame)
1132 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1134 if (_session == 0) {
1138 if (_follow_playhead) {
1139 center_screen (frame);
1142 playhead_cursor->set_position (frame);
1146 Editor::center_screen (framepos_t frame)
1148 double page = _canvas_width * frames_per_unit;
1150 /* if we're off the page, then scroll.
1153 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1154 center_screen_internal (frame, page);
1159 Editor::center_screen_internal (framepos_t frame, float page)
1164 frame -= (framepos_t) page;
1169 reset_x_origin (frame);
1174 Editor::update_title ()
1176 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1179 bool dirty = _session->dirty();
1181 string session_name;
1183 if (_session->snap_name() != _session->name()) {
1184 session_name = _session->snap_name();
1186 session_name = _session->name();
1190 session_name = "*" + session_name;
1193 WindowTitle title(session_name);
1194 title += Glib::get_application_name();
1195 set_title (title.get_string());
1197 /* ::session_going_away() will have taken care of it */
1202 Editor::set_session (Session *t)
1204 SessionHandlePtr::set_session (t);
1210 zoom_range_clock->set_session (_session);
1211 _playlist_selector->set_session (_session);
1212 nudge_clock->set_session (_session);
1213 _summary->set_session (_session);
1214 _group_tabs->set_session (_session);
1215 _route_groups->set_session (_session);
1216 _regions->set_session (_session);
1217 _snapshots->set_session (_session);
1218 _routes->set_session (_session);
1219 _locations->set_session (_session);
1221 if (rhythm_ferret) {
1222 rhythm_ferret->set_session (_session);
1225 if (analysis_window) {
1226 analysis_window->set_session (_session);
1230 sfbrowser->set_session (_session);
1233 compute_fixed_ruler_scale ();
1235 /* Make sure we have auto loop and auto punch ranges */
1237 Location* loc = _session->locations()->auto_loop_location();
1239 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1241 if (loc->start() == loc->end()) {
1242 loc->set_end (loc->start() + 1);
1245 _session->locations()->add (loc, false);
1246 _session->set_auto_loop_location (loc);
1249 loc->set_name (_("Loop"));
1252 loc = _session->locations()->auto_punch_location();
1255 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1257 if (loc->start() == loc->end()) {
1258 loc->set_end (loc->start() + 1);
1261 _session->locations()->add (loc, false);
1262 _session->set_auto_punch_location (loc);
1265 loc->set_name (_("Punch"));
1268 refresh_location_display ();
1270 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1271 the selected Marker; this needs the LocationMarker list to be available.
1273 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1274 set_state (*node, Stateful::loading_state_version);
1276 /* catch up with the playhead */
1278 _session->request_locate (playhead_cursor->current_frame);
1279 _pending_initial_locate = true;
1283 /* These signals can all be emitted by a non-GUI thread. Therefore the
1284 handlers for them must not attempt to directly interact with the GUI,
1285 but use Gtkmm2ext::UI::instance()->call_slot();
1288 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1289 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1290 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1291 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1292 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1293 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1294 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1295 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1296 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1297 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1298 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1299 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1300 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1301 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1303 playhead_cursor->canvas_item.show ();
1305 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1306 Config->map_parameters (pc);
1307 _session->config.map_parameters (pc);
1309 restore_ruler_visibility ();
1310 //tempo_map_changed (PropertyChange (0));
1311 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1313 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1314 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1317 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1318 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1321 switch (_snap_type) {
1322 case SnapToRegionStart:
1323 case SnapToRegionEnd:
1324 case SnapToRegionSync:
1325 case SnapToRegionBoundary:
1326 build_region_boundary_cache ();
1333 /* register for undo history */
1334 _session->register_with_memento_command_factory(id(), this);
1336 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1338 start_updating_meters ();
1342 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1344 if (a->get_name() == "RegionMenu") {
1345 /* When the main menu's region menu is opened, we setup the actions so that they look right
1346 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1347 so we resensitize all region actions when the entered regionview or the region selection
1348 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1349 happens after the region context menu is opened. So we set a flag here, too.
1353 sensitize_the_right_region_actions ();
1354 _last_region_menu_was_main = true;
1359 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1361 using namespace Menu_Helpers;
1363 void (Editor::*emf)(FadeShape);
1364 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1367 images = &_xfade_in_images;
1368 emf = &Editor::set_fade_in_shape;
1370 images = &_xfade_out_images;
1371 emf = &Editor::set_fade_out_shape;
1376 _("Linear (for highly correlated material)"),
1377 *(*images)[FadeLinear],
1378 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1382 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1386 _("Constant power"),
1387 *(*images)[FadeConstantPower],
1388 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1391 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1396 *(*images)[FadeSymmetric],
1397 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1401 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1406 *(*images)[FadeSlow],
1407 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1410 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1415 *(*images)[FadeFast],
1416 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1419 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1422 /** Pop up a context menu for when the user clicks on a start crossfade */
1424 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1426 using namespace Menu_Helpers;
1428 MenuList& items (xfade_in_context_menu.items());
1430 if (items.empty()) {
1431 fill_xfade_menu (items, true);
1434 xfade_in_context_menu.popup (button, time);
1437 /** Pop up a context menu for when the user clicks on an end crossfade */
1439 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1441 using namespace Menu_Helpers;
1443 MenuList& items (xfade_out_context_menu.items());
1445 if (items.empty()) {
1446 fill_xfade_menu (items, false);
1449 xfade_out_context_menu.popup (button, time);
1453 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1455 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1457 using namespace Menu_Helpers;
1458 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1461 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1465 MenuList& items (fade_context_menu.items());
1468 switch (item_type) {
1470 case FadeInHandleItem:
1471 if (arv->audio_region()->fade_in_active()) {
1472 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1474 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1477 items.push_back (SeparatorElem());
1479 if (Profile->get_sae()) {
1481 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1482 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1489 *_fade_in_images[FadeLinear],
1490 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1494 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 *_fade_in_images[FadeSlow],
1500 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1503 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1508 *_fade_in_images[FadeFast],
1509 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1512 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1517 *_fade_in_images[FadeSymmetric],
1518 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1523 _("Constant power"),
1524 *_fade_in_images[FadeConstantPower],
1525 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1528 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1534 case FadeOutHandleItem:
1535 if (arv->audio_region()->fade_out_active()) {
1536 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1538 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1541 items.push_back (SeparatorElem());
1543 if (Profile->get_sae()) {
1544 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1545 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1551 *_fade_out_images[FadeLinear],
1552 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1556 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1561 *_fade_out_images[FadeSlow],
1562 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1565 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1570 *_fade_out_images[FadeFast],
1571 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1574 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1579 *_fade_out_images[FadeSymmetric],
1580 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1585 _("Constant power"),
1586 *_fade_out_images[FadeConstantPower],
1587 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1590 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1596 fatal << _("programming error: ")
1597 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1602 fade_context_menu.popup (button, time);
1606 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1608 using namespace Menu_Helpers;
1609 Menu* (Editor::*build_menu_function)();
1612 switch (item_type) {
1614 case RegionViewName:
1615 case RegionViewNameHighlight:
1616 case LeftFrameHandle:
1617 case RightFrameHandle:
1618 if (with_selection) {
1619 build_menu_function = &Editor::build_track_selection_context_menu;
1621 build_menu_function = &Editor::build_track_region_context_menu;
1626 if (with_selection) {
1627 build_menu_function = &Editor::build_track_selection_context_menu;
1629 build_menu_function = &Editor::build_track_context_menu;
1634 if (clicked_routeview->track()) {
1635 build_menu_function = &Editor::build_track_context_menu;
1637 build_menu_function = &Editor::build_track_bus_context_menu;
1642 /* probably shouldn't happen but if it does, we don't care */
1646 menu = (this->*build_menu_function)();
1647 menu->set_name ("ArdourContextMenu");
1649 /* now handle specific situations */
1651 switch (item_type) {
1653 case RegionViewName:
1654 case RegionViewNameHighlight:
1655 case LeftFrameHandle:
1656 case RightFrameHandle:
1657 if (!with_selection) {
1658 if (region_edit_menu_split_item) {
1659 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1660 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1662 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1665 if (region_edit_menu_split_multichannel_item) {
1666 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1667 region_edit_menu_split_multichannel_item->set_sensitive (true);
1669 region_edit_menu_split_multichannel_item->set_sensitive (false);
1682 /* probably shouldn't happen but if it does, we don't care */
1686 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1688 /* Bounce to disk */
1690 using namespace Menu_Helpers;
1691 MenuList& edit_items = menu->items();
1693 edit_items.push_back (SeparatorElem());
1695 switch (clicked_routeview->audio_track()->freeze_state()) {
1696 case AudioTrack::NoFreeze:
1697 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1700 case AudioTrack::Frozen:
1701 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1704 case AudioTrack::UnFrozen:
1705 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1711 if (item_type == StreamItem && clicked_routeview) {
1712 clicked_routeview->build_underlay_menu(menu);
1715 /* When the region menu is opened, we setup the actions so that they look right
1718 sensitize_the_right_region_actions ();
1719 _last_region_menu_was_main = false;
1721 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1722 menu->popup (button, time);
1726 Editor::build_track_context_menu ()
1728 using namespace Menu_Helpers;
1730 MenuList& edit_items = track_context_menu.items();
1733 add_dstream_context_items (edit_items);
1734 return &track_context_menu;
1738 Editor::build_track_bus_context_menu ()
1740 using namespace Menu_Helpers;
1742 MenuList& edit_items = track_context_menu.items();
1745 add_bus_context_items (edit_items);
1746 return &track_context_menu;
1750 Editor::build_track_region_context_menu ()
1752 using namespace Menu_Helpers;
1753 MenuList& edit_items = track_region_context_menu.items();
1756 /* we've just cleared the track region context menu, so the menu that these
1757 two items were on will have disappeared; stop them dangling.
1759 region_edit_menu_split_item = 0;
1760 region_edit_menu_split_multichannel_item = 0;
1762 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1765 boost::shared_ptr<Track> tr;
1766 boost::shared_ptr<Playlist> pl;
1768 if ((tr = rtv->track())) {
1769 add_region_context_items (edit_items, tr);
1773 add_dstream_context_items (edit_items);
1775 return &track_region_context_menu;
1779 Editor::analyze_region_selection ()
1781 if (analysis_window == 0) {
1782 analysis_window = new AnalysisWindow();
1785 analysis_window->set_session(_session);
1787 analysis_window->show_all();
1790 analysis_window->set_regionmode();
1791 analysis_window->analyze();
1793 analysis_window->present();
1797 Editor::analyze_range_selection()
1799 if (analysis_window == 0) {
1800 analysis_window = new AnalysisWindow();
1803 analysis_window->set_session(_session);
1805 analysis_window->show_all();
1808 analysis_window->set_rangemode();
1809 analysis_window->analyze();
1811 analysis_window->present();
1815 Editor::build_track_selection_context_menu ()
1817 using namespace Menu_Helpers;
1818 MenuList& edit_items = track_selection_context_menu.items();
1819 edit_items.clear ();
1821 add_selection_context_items (edit_items);
1822 // edit_items.push_back (SeparatorElem());
1823 // add_dstream_context_items (edit_items);
1825 return &track_selection_context_menu;
1829 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1831 using namespace Menu_Helpers;
1833 /* OK, stick the region submenu at the top of the list, and then add
1837 RegionSelection rs = get_regions_from_selection_and_entered ();
1839 string::size_type pos = 0;
1840 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1842 /* we have to hack up the region name because "_" has a special
1843 meaning for menu titles.
1846 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1847 menu_item_name.replace (pos, 1, "__");
1851 if (_popup_region_menu_item == 0) {
1852 _popup_region_menu_item = new MenuItem (menu_item_name);
1853 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1854 _popup_region_menu_item->show ();
1856 _popup_region_menu_item->set_label (menu_item_name);
1859 const framepos_t position = get_preferred_edit_position (false, true);
1861 edit_items.push_back (*_popup_region_menu_item);
1862 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1863 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1865 edit_items.push_back (SeparatorElem());
1868 /** Add context menu items relevant to selection ranges.
1869 * @param edit_items List to add the items to.
1872 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1874 using namespace Menu_Helpers;
1876 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1877 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1879 edit_items.push_back (SeparatorElem());
1880 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1882 edit_items.push_back (SeparatorElem());
1884 edit_items.push_back (
1886 _("Move Range Start to Previous Region Boundary"),
1887 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1891 edit_items.push_back (
1893 _("Move Range Start to Next Region Boundary"),
1894 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1898 edit_items.push_back (
1900 _("Move Range End to Previous Region Boundary"),
1901 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1905 edit_items.push_back (
1907 _("Move Range End to Next Region Boundary"),
1908 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1912 edit_items.push_back (SeparatorElem());
1913 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1914 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1916 edit_items.push_back (SeparatorElem());
1917 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1919 edit_items.push_back (SeparatorElem());
1920 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1921 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1923 edit_items.push_back (SeparatorElem());
1924 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1926 edit_items.push_back (SeparatorElem());
1927 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1928 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1929 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1931 edit_items.push_back (SeparatorElem());
1932 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1933 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1934 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1935 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1936 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1941 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1943 using namespace Menu_Helpers;
1947 Menu *play_menu = manage (new Menu);
1948 MenuList& play_items = play_menu->items();
1949 play_menu->set_name ("ArdourContextMenu");
1951 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1952 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1953 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1954 play_items.push_back (SeparatorElem());
1955 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1957 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1961 Menu *select_menu = manage (new Menu);
1962 MenuList& select_items = select_menu->items();
1963 select_menu->set_name ("ArdourContextMenu");
1965 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1966 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1967 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1968 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1969 select_items.push_back (SeparatorElem());
1970 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1971 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1972 select_items.push_back (SeparatorElem());
1973 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1974 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1975 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1976 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1977 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1978 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1979 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1981 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1985 Menu *cutnpaste_menu = manage (new Menu);
1986 MenuList& cutnpaste_items = cutnpaste_menu->items();
1987 cutnpaste_menu->set_name ("ArdourContextMenu");
1989 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1990 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1991 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1993 cutnpaste_items.push_back (SeparatorElem());
1995 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1996 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1998 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2000 /* Adding new material */
2002 edit_items.push_back (SeparatorElem());
2003 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2004 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2008 Menu *nudge_menu = manage (new Menu());
2009 MenuList& nudge_items = nudge_menu->items();
2010 nudge_menu->set_name ("ArdourContextMenu");
2012 edit_items.push_back (SeparatorElem());
2013 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2014 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2015 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2016 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2018 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2022 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2024 using namespace Menu_Helpers;
2028 Menu *play_menu = manage (new Menu);
2029 MenuList& play_items = play_menu->items();
2030 play_menu->set_name ("ArdourContextMenu");
2032 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2033 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2034 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2038 Menu *select_menu = manage (new Menu);
2039 MenuList& select_items = select_menu->items();
2040 select_menu->set_name ("ArdourContextMenu");
2042 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2043 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2044 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2045 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2046 select_items.push_back (SeparatorElem());
2047 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2048 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2049 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2050 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2052 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2056 Menu *cutnpaste_menu = manage (new Menu);
2057 MenuList& cutnpaste_items = cutnpaste_menu->items();
2058 cutnpaste_menu->set_name ("ArdourContextMenu");
2060 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2061 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2062 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2064 Menu *nudge_menu = manage (new Menu());
2065 MenuList& nudge_items = nudge_menu->items();
2066 nudge_menu->set_name ("ArdourContextMenu");
2068 edit_items.push_back (SeparatorElem());
2069 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2070 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2071 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2072 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2074 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2078 Editor::snap_type() const
2084 Editor::snap_mode() const
2090 Editor::set_snap_to (SnapType st)
2092 unsigned int snap_ind = (unsigned int)st;
2096 if (snap_ind > snap_type_strings.size() - 1) {
2098 _snap_type = (SnapType)snap_ind;
2101 string str = snap_type_strings[snap_ind];
2103 if (str != snap_type_selector.get_active_text()) {
2104 snap_type_selector.set_active_text (str);
2109 switch (_snap_type) {
2110 case SnapToBeatDiv128:
2111 case SnapToBeatDiv64:
2112 case SnapToBeatDiv32:
2113 case SnapToBeatDiv28:
2114 case SnapToBeatDiv24:
2115 case SnapToBeatDiv20:
2116 case SnapToBeatDiv16:
2117 case SnapToBeatDiv14:
2118 case SnapToBeatDiv12:
2119 case SnapToBeatDiv10:
2120 case SnapToBeatDiv8:
2121 case SnapToBeatDiv7:
2122 case SnapToBeatDiv6:
2123 case SnapToBeatDiv5:
2124 case SnapToBeatDiv4:
2125 case SnapToBeatDiv3:
2126 case SnapToBeatDiv2: {
2127 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2128 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2130 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2131 current_bbt_points_begin, current_bbt_points_end);
2132 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2133 current_bbt_points_begin, current_bbt_points_end);
2134 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2138 case SnapToRegionStart:
2139 case SnapToRegionEnd:
2140 case SnapToRegionSync:
2141 case SnapToRegionBoundary:
2142 build_region_boundary_cache ();
2150 SnapChanged (); /* EMIT SIGNAL */
2154 Editor::set_snap_mode (SnapMode mode)
2156 string str = snap_mode_strings[(int)mode];
2158 if (_internal_editing) {
2159 internal_snap_mode = mode;
2161 pre_internal_snap_mode = mode;
2166 if (str != snap_mode_selector.get_active_text ()) {
2167 snap_mode_selector.set_active_text (str);
2173 Editor::set_edit_point_preference (EditPoint ep, bool force)
2175 bool changed = (_edit_point != ep);
2178 string str = edit_point_strings[(int)ep];
2180 if (str != edit_point_selector.get_active_text ()) {
2181 edit_point_selector.set_active_text (str);
2184 set_canvas_cursor ();
2186 if (!force && !changed) {
2190 const char* action=NULL;
2192 switch (_edit_point) {
2193 case EditAtPlayhead:
2194 action = "edit-at-playhead";
2196 case EditAtSelectedMarker:
2197 action = "edit-at-marker";
2200 action = "edit-at-mouse";
2204 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2206 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2210 bool in_track_canvas;
2212 if (!mouse_frame (foo, in_track_canvas)) {
2213 in_track_canvas = false;
2216 reset_canvas_action_sensitivity (in_track_canvas);
2222 Editor::set_state (const XMLNode& node, int /*version*/)
2224 const XMLProperty* prop;
2231 g.base_width = default_width;
2232 g.base_height = default_height;
2236 if ((geometry = find_named_node (node, "geometry")) != 0) {
2240 if ((prop = geometry->property("x_size")) == 0) {
2241 prop = geometry->property ("x-size");
2244 g.base_width = atoi(prop->value());
2246 if ((prop = geometry->property("y_size")) == 0) {
2247 prop = geometry->property ("y-size");
2250 g.base_height = atoi(prop->value());
2253 if ((prop = geometry->property ("x_pos")) == 0) {
2254 prop = geometry->property ("x-pos");
2257 x = atoi (prop->value());
2260 if ((prop = geometry->property ("y_pos")) == 0) {
2261 prop = geometry->property ("y-pos");
2264 y = atoi (prop->value());
2268 set_default_size (g.base_width, g.base_height);
2271 if (_session && (prop = node.property ("playhead"))) {
2273 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2274 playhead_cursor->set_position (pos);
2276 playhead_cursor->set_position (0);
2279 if ((prop = node.property ("mixer-width"))) {
2280 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2283 if ((prop = node.property ("zoom-focus"))) {
2284 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2287 if ((prop = node.property ("zoom"))) {
2288 reset_zoom (PBD::atof (prop->value()));
2290 reset_zoom (frames_per_unit);
2293 if ((prop = node.property ("snap-to"))) {
2294 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2297 if ((prop = node.property ("snap-mode"))) {
2298 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2301 if ((prop = node.property ("internal-snap-to"))) {
2302 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2305 if ((prop = node.property ("internal-snap-mode"))) {
2306 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2309 if ((prop = node.property ("pre-internal-snap-to"))) {
2310 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2314 if ((prop = node.property ("pre-internal-snap-mode"))) {
2315 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2318 if ((prop = node.property ("mouse-mode"))) {
2319 MouseMode m = str2mousemode(prop->value());
2320 set_mouse_mode (m, true);
2322 set_mouse_mode (MouseObject, true);
2325 if ((prop = node.property ("left-frame")) != 0) {
2327 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2331 reset_x_origin (pos);
2335 if ((prop = node.property ("y-origin")) != 0) {
2336 reset_y_origin (atof (prop->value ()));
2339 if ((prop = node.property ("internal-edit"))) {
2340 bool yn = string_is_affirmative (prop->value());
2341 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2343 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2344 tact->set_active (!yn);
2345 tact->set_active (yn);
2349 if ((prop = node.property ("join-object-range"))) {
2350 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2351 bool yn = string_is_affirmative (prop->value());
2353 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2354 tact->set_active (!yn);
2355 tact->set_active (yn);
2357 set_mouse_mode(mouse_mode, true);
2360 if ((prop = node.property ("edit-point"))) {
2361 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2364 if ((prop = node.property ("show-measures"))) {
2365 bool yn = string_is_affirmative (prop->value());
2366 _show_measures = yn;
2367 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2369 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2370 /* do it twice to force the change */
2371 tact->set_active (!yn);
2372 tact->set_active (yn);
2376 if ((prop = node.property ("follow-playhead"))) {
2377 bool yn = string_is_affirmative (prop->value());
2378 set_follow_playhead (yn);
2379 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2381 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2382 if (tact->get_active() != yn) {
2383 tact->set_active (yn);
2388 if ((prop = node.property ("stationary-playhead"))) {
2389 bool yn = string_is_affirmative (prop->value());
2390 set_stationary_playhead (yn);
2391 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2393 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2394 if (tact->get_active() != yn) {
2395 tact->set_active (yn);
2400 if ((prop = node.property ("region-list-sort-type"))) {
2401 RegionListSortType st;
2402 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2405 if ((prop = node.property ("show-editor-mixer"))) {
2407 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2410 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2411 bool yn = string_is_affirmative (prop->value());
2413 /* do it twice to force the change */
2415 tact->set_active (!yn);
2416 tact->set_active (yn);
2419 if ((prop = node.property ("show-editor-list"))) {
2421 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2424 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2425 bool yn = string_is_affirmative (prop->value());
2427 /* do it twice to force the change */
2429 tact->set_active (!yn);
2430 tact->set_active (yn);
2433 if ((prop = node.property (X_("editor-list-page")))) {
2434 _the_notebook.set_current_page (atoi (prop->value ()));
2437 if ((prop = node.property (X_("show-marker-lines")))) {
2438 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2440 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2441 bool yn = string_is_affirmative (prop->value ());
2443 tact->set_active (!yn);
2444 tact->set_active (yn);
2447 XMLNodeList children = node.children ();
2448 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2449 selection->set_state (**i, Stateful::current_state_version);
2450 _regions->set_state (**i);
2453 if ((prop = node.property ("maximised"))) {
2454 bool yn = string_is_affirmative (prop->value());
2456 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2460 if ((prop = node.property ("nudge-clock-value"))) {
2462 sscanf (prop->value().c_str(), "%" PRId64, &f);
2463 nudge_clock->set (f);
2465 nudge_clock->set_mode (AudioClock::Timecode);
2466 nudge_clock->set (_session->frame_rate() * 5, true);
2473 Editor::get_state ()
2475 XMLNode* node = new XMLNode ("Editor");
2478 id().print (buf, sizeof (buf));
2479 node->add_property ("id", buf);
2481 if (is_realized()) {
2482 Glib::RefPtr<Gdk::Window> win = get_window();
2484 int x, y, width, height;
2485 win->get_root_origin(x, y);
2486 win->get_size(width, height);
2488 XMLNode* geometry = new XMLNode ("geometry");
2490 snprintf(buf, sizeof(buf), "%d", width);
2491 geometry->add_property("x-size", string(buf));
2492 snprintf(buf, sizeof(buf), "%d", height);
2493 geometry->add_property("y-size", string(buf));
2494 snprintf(buf, sizeof(buf), "%d", x);
2495 geometry->add_property("x-pos", string(buf));
2496 snprintf(buf, sizeof(buf), "%d", y);
2497 geometry->add_property("y-pos", string(buf));
2498 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2499 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2500 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2501 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2502 geometry->add_property("edit-vertical-pane-pos", string(buf));
2504 node->add_child_nocopy (*geometry);
2507 maybe_add_mixer_strip_width (*node);
2509 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2510 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2511 node->add_property ("zoom", buf);
2512 node->add_property ("snap-to", enum_2_string (_snap_type));
2513 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2514 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2515 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2516 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2517 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2518 node->add_property ("edit-point", enum_2_string (_edit_point));
2520 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2521 node->add_property ("playhead", buf);
2522 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2523 node->add_property ("left-frame", buf);
2524 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2525 node->add_property ("y-origin", buf);
2527 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2528 node->add_property ("maximised", _maximised ? "yes" : "no");
2529 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2530 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2531 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2532 node->add_property ("mouse-mode", enum2str(mouse_mode));
2533 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2534 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2536 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2538 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2539 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2542 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2544 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2545 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2548 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2549 node->add_property (X_("editor-list-page"), buf);
2551 if (button_bindings) {
2552 XMLNode* bb = new XMLNode (X_("Buttons"));
2553 button_bindings->save (*bb);
2554 node->add_child_nocopy (*bb);
2557 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2559 node->add_child_nocopy (selection->get_state ());
2560 node->add_child_nocopy (_regions->get_state ());
2562 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2563 node->add_property ("nudge-clock-value", buf);
2570 /** @param y y offset from the top of all trackviews.
2571 * @return pair: TimeAxisView that y is over, layer index.
2572 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2573 * in stacked or expanded region display mode, otherwise 0.
2575 std::pair<TimeAxisView *, double>
2576 Editor::trackview_by_y_position (double y)
2578 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2580 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2586 return std::make_pair ( (TimeAxisView *) 0, 0);
2589 /** Snap a position to the grid, if appropriate, taking into account current
2590 * grid settings and also the state of any snap modifier keys that may be pressed.
2591 * @param start Position to snap.
2592 * @param event Event to get current key modifier information from, or 0.
2595 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2597 if (!_session || !event) {
2601 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2602 if (_snap_mode == SnapOff) {
2603 snap_to_internal (start, direction, for_mark);
2606 if (_snap_mode != SnapOff) {
2607 snap_to_internal (start, direction, for_mark);
2613 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2615 if (!_session || _snap_mode == SnapOff) {
2619 snap_to_internal (start, direction, for_mark);
2623 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2625 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2626 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2628 switch (_snap_type) {
2629 case SnapToTimecodeFrame:
2630 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2631 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2633 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2637 case SnapToTimecodeSeconds:
2638 if (_session->config.get_timecode_offset_negative()) {
2639 start += _session->config.get_timecode_offset ();
2641 start -= _session->config.get_timecode_offset ();
2643 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2644 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2646 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2649 if (_session->config.get_timecode_offset_negative()) {
2650 start -= _session->config.get_timecode_offset ();
2652 start += _session->config.get_timecode_offset ();
2656 case SnapToTimecodeMinutes:
2657 if (_session->config.get_timecode_offset_negative()) {
2658 start += _session->config.get_timecode_offset ();
2660 start -= _session->config.get_timecode_offset ();
2662 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2663 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2665 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2667 if (_session->config.get_timecode_offset_negative()) {
2668 start -= _session->config.get_timecode_offset ();
2670 start += _session->config.get_timecode_offset ();
2674 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2680 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2682 const framepos_t one_second = _session->frame_rate();
2683 const framepos_t one_minute = _session->frame_rate() * 60;
2684 framepos_t presnap = start;
2688 switch (_snap_type) {
2689 case SnapToTimecodeFrame:
2690 case SnapToTimecodeSeconds:
2691 case SnapToTimecodeMinutes:
2692 return timecode_snap_to_internal (start, direction, for_mark);
2695 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2696 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2698 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2703 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2704 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2706 start = (framepos_t) floor ((double) start / one_second) * one_second;
2711 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2712 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2714 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2719 start = _session->tempo_map().round_to_bar (start, direction);
2723 start = _session->tempo_map().round_to_beat (start, direction);
2726 case SnapToBeatDiv128:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2729 case SnapToBeatDiv64:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2732 case SnapToBeatDiv32:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2735 case SnapToBeatDiv28:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2738 case SnapToBeatDiv24:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2741 case SnapToBeatDiv20:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2744 case SnapToBeatDiv16:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2747 case SnapToBeatDiv14:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2750 case SnapToBeatDiv12:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2753 case SnapToBeatDiv10:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2756 case SnapToBeatDiv8:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2759 case SnapToBeatDiv7:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2762 case SnapToBeatDiv6:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2765 case SnapToBeatDiv5:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2768 case SnapToBeatDiv4:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2771 case SnapToBeatDiv3:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2774 case SnapToBeatDiv2:
2775 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2783 _session->locations()->marks_either_side (start, before, after);
2785 if (before == max_framepos && after == max_framepos) {
2786 /* No marks to snap to, so just don't snap */
2788 } else if (before == max_framepos) {
2790 } else if (after == max_framepos) {
2792 } else if (before != max_framepos && after != max_framepos) {
2793 /* have before and after */
2794 if ((start - before) < (after - start)) {
2803 case SnapToRegionStart:
2804 case SnapToRegionEnd:
2805 case SnapToRegionSync:
2806 case SnapToRegionBoundary:
2807 if (!region_boundary_cache.empty()) {
2809 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2810 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2812 if (direction > 0) {
2813 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2815 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2818 if (next != region_boundary_cache.begin ()) {
2823 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2824 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2826 if (start > (p + n) / 2) {
2835 switch (_snap_mode) {
2841 if (presnap > start) {
2842 if (presnap > (start + unit_to_frame(snap_threshold))) {
2846 } else if (presnap < start) {
2847 if (presnap < (start - unit_to_frame(snap_threshold))) {
2853 /* handled at entry */
2861 Editor::setup_toolbar ()
2863 HBox* mode_box = manage(new HBox);
2864 mode_box->set_border_width (2);
2865 mode_box->set_spacing(4);
2867 HBox* mouse_mode_box = manage (new HBox);
2868 HBox* mouse_mode_hbox = manage (new HBox);
2869 VBox* mouse_mode_vbox = manage (new VBox);
2870 Alignment* mouse_mode_align = manage (new Alignment);
2872 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2873 // mouse_mode_size_group->add_widget (smart_mode_button);
2874 mouse_mode_size_group->add_widget (mouse_move_button);
2875 mouse_mode_size_group->add_widget (mouse_select_button);
2876 mouse_mode_size_group->add_widget (mouse_zoom_button);
2877 mouse_mode_size_group->add_widget (mouse_gain_button);
2878 mouse_mode_size_group->add_widget (mouse_timefx_button);
2879 mouse_mode_size_group->add_widget (mouse_audition_button);
2880 mouse_mode_size_group->add_widget (mouse_draw_button);
2881 mouse_mode_size_group->add_widget (internal_edit_button);
2883 /* make them just a bit bigger */
2884 mouse_move_button.set_size_request (-1, 30);
2886 mouse_mode_hbox->set_spacing (2);
2888 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2890 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2891 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2895 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2896 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2898 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2900 mouse_mode_align->add (*mouse_mode_vbox);
2901 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2903 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2905 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2906 if (!Profile->get_sae()) {
2907 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2909 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2911 edit_mode_selector.set_name ("EditModeSelector");
2912 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2913 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2915 mode_box->pack_start (edit_mode_selector, false, false);
2916 mode_box->pack_start (*mouse_mode_box, false, false);
2918 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2919 _mouse_mode_tearoff->set_name ("MouseModeBase");
2920 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2922 if (Profile->get_sae()) {
2923 _mouse_mode_tearoff->set_can_be_torn_off (false);
2926 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927 &_mouse_mode_tearoff->tearoff_window()));
2928 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929 &_mouse_mode_tearoff->tearoff_window(), 1));
2930 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2931 &_mouse_mode_tearoff->tearoff_window()));
2932 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2933 &_mouse_mode_tearoff->tearoff_window(), 1));
2937 _zoom_box.set_spacing (2);
2938 _zoom_box.set_border_width (2);
2942 zoom_in_button.set_name ("zoom button");
2943 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2944 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2945 zoom_in_button.set_image(::get_icon ("zoom_in"));
2946 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2947 zoom_in_button.set_related_action (act);
2949 zoom_out_button.set_name ("zoom button");
2950 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2951 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2952 zoom_out_button.set_image(::get_icon ("zoom_out"));
2953 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2954 zoom_out_button.set_related_action (act);
2956 zoom_out_full_button.set_name ("zoom button");
2957 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2958 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2959 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2960 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2961 zoom_out_full_button.set_related_action (act);
2963 zoom_focus_selector.set_name ("ZoomFocusSelector");
2964 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2965 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2967 _zoom_box.pack_start (zoom_out_button, false, false);
2968 _zoom_box.pack_start (zoom_in_button, false, false);
2969 _zoom_box.pack_start (zoom_out_full_button, false, false);
2971 _zoom_box.pack_start (zoom_focus_selector, false, false);
2973 /* Track zoom buttons */
2974 tav_expand_button.set_name ("zoom button");
2975 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2976 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2977 tav_expand_button.set_size_request (-1, 20);
2978 tav_expand_button.set_image(::get_icon ("tav_exp"));
2979 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2980 tav_expand_button.set_related_action (act);
2982 tav_shrink_button.set_name ("zoom button");
2983 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2984 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2985 tav_shrink_button.set_size_request (-1, 20);
2986 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2987 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2988 tav_shrink_button.set_related_action (act);
2990 _zoom_box.pack_start (tav_shrink_button);
2991 _zoom_box.pack_start (tav_expand_button);
2993 _zoom_tearoff = manage (new TearOff (_zoom_box));
2995 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2996 &_zoom_tearoff->tearoff_window()));
2997 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2998 &_zoom_tearoff->tearoff_window(), 0));
2999 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3000 &_zoom_tearoff->tearoff_window()));
3001 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3002 &_zoom_tearoff->tearoff_window(), 0));
3004 snap_box.set_spacing (2);
3005 snap_box.set_border_width (2);
3007 snap_type_selector.set_name ("SnapTypeSelector");
3008 set_popdown_strings (snap_type_selector, snap_type_strings);
3009 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3011 snap_mode_selector.set_name ("SnapModeSelector");
3012 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3013 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3015 edit_point_selector.set_name ("EditPointSelector");
3016 set_popdown_strings (edit_point_selector, edit_point_strings);
3017 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3019 snap_box.pack_start (snap_mode_selector, false, false);
3020 snap_box.pack_start (snap_type_selector, false, false);
3021 snap_box.pack_start (edit_point_selector, false, false);
3025 HBox *nudge_box = manage (new HBox);
3026 nudge_box->set_spacing (2);
3027 nudge_box->set_border_width (2);
3029 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3030 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3032 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3033 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3035 nudge_box->pack_start (nudge_backward_button, false, false);
3036 nudge_box->pack_start (nudge_forward_button, false, false);
3037 nudge_box->pack_start (*nudge_clock, false, false);
3040 /* Pack everything in... */
3042 HBox* hbox = manage (new HBox);
3043 hbox->set_spacing(10);
3045 _tools_tearoff = manage (new TearOff (*hbox));
3046 _tools_tearoff->set_name ("MouseModeBase");
3047 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3049 if (Profile->get_sae()) {
3050 _tools_tearoff->set_can_be_torn_off (false);
3053 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3054 &_tools_tearoff->tearoff_window()));
3055 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3056 &_tools_tearoff->tearoff_window(), 0));
3057 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3058 &_tools_tearoff->tearoff_window()));
3059 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3060 &_tools_tearoff->tearoff_window(), 0));
3062 toolbar_hbox.set_spacing (10);
3063 toolbar_hbox.set_border_width (1);
3065 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3066 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3067 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3069 hbox->pack_start (snap_box, false, false);
3070 if (!Profile->get_small_screen()) {
3071 hbox->pack_start (*nudge_box, false, false);
3073 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3075 hbox->pack_start (panic_box, false, false);
3079 toolbar_base.set_name ("ToolBarBase");
3080 toolbar_base.add (toolbar_hbox);
3082 _toolbar_viewport.add (toolbar_base);
3083 /* stick to the required height but allow width to vary if there's not enough room */
3084 _toolbar_viewport.set_size_request (1, -1);
3086 toolbar_frame.set_shadow_type (SHADOW_OUT);
3087 toolbar_frame.set_name ("BaseFrame");
3088 toolbar_frame.add (_toolbar_viewport);
3092 Editor::setup_tooltips ()
3094 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3095 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3096 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3097 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3098 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3099 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3100 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3101 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3102 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3103 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3104 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3105 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3106 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3107 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3108 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3109 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3110 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3111 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3112 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3113 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3114 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3115 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3116 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3120 Editor::convert_drop_to_paths (
3121 vector<string>& paths,
3122 const RefPtr<Gdk::DragContext>& /*context*/,
3125 const SelectionData& data,
3129 if (_session == 0) {
3133 vector<string> uris = data.get_uris();
3137 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3138 are actually URI lists. So do it by hand.
3141 if (data.get_target() != "text/plain") {
3145 /* Parse the "uri-list" format that Nautilus provides,
3146 where each pathname is delimited by \r\n.
3148 THERE MAY BE NO NULL TERMINATING CHAR!!!
3151 string txt = data.get_text();
3155 p = (const char *) malloc (txt.length() + 1);
3156 txt.copy (const_cast<char *> (p), txt.length(), 0);
3157 const_cast<char*>(p)[txt.length()] = '\0';
3163 while (g_ascii_isspace (*p))
3167 while (*q && (*q != '\n') && (*q != '\r')) {
3174 while (q > p && g_ascii_isspace (*q))
3179 uris.push_back (string (p, q - p + 1));
3183 p = strchr (p, '\n');
3195 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3197 if ((*i).substr (0,7) == "file://") {
3199 string const p = PBD::url_decode (*i);
3201 // scan forward past three slashes
3203 string::size_type slashcnt = 0;
3204 string::size_type n = 0;
3205 string::const_iterator x = p.begin();
3207 while (slashcnt < 3 && x != p.end()) {
3210 } else if (slashcnt == 3) {
3217 if (slashcnt != 3 || x == p.end()) {
3218 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3222 paths.push_back (p.substr (n - 1));
3230 Editor::new_tempo_section ()
3236 Editor::map_transport_state ()
3238 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3240 if (_session && _session->transport_stopped()) {
3241 have_pending_keyboard_selection = false;
3244 update_loop_range_view (true);
3250 Editor::begin_reversible_command (string name)
3253 _session->begin_reversible_command (name);
3258 Editor::begin_reversible_command (GQuark q)
3261 _session->begin_reversible_command (q);
3266 Editor::commit_reversible_command ()
3269 _session->commit_reversible_command ();
3274 Editor::history_changed ()
3278 if (undo_action && _session) {
3279 if (_session->undo_depth() == 0) {
3280 label = S_("Command|Undo");
3282 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3284 undo_action->property_label() = label;
3287 if (redo_action && _session) {
3288 if (_session->redo_depth() == 0) {
3291 label = string_compose(_("Redo (%1)"), _session->next_redo());
3293 redo_action->property_label() = label;
3298 Editor::duplicate_range (bool with_dialog)
3302 RegionSelection rs = get_regions_from_selection_and_entered ();
3304 if ( selection->time.length() == 0 && rs.empty()) {
3310 ArdourDialog win (_("Duplicate"));
3311 Label label (_("Number of duplications:"));
3312 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3313 SpinButton spinner (adjustment, 0.0, 1);
3316 win.get_vbox()->set_spacing (12);
3317 win.get_vbox()->pack_start (hbox);
3318 hbox.set_border_width (6);
3319 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3321 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3322 place, visually. so do this by hand.
3325 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3326 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3327 spinner.grab_focus();
3333 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3334 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3335 win.set_default_response (RESPONSE_ACCEPT);
3337 win.set_position (WIN_POS_MOUSE);
3339 spinner.grab_focus ();
3341 switch (win.run ()) {
3342 case RESPONSE_ACCEPT:
3348 times = adjustment.get_value();
3351 if ((current_mouse_mode() == Editing::MouseRange)) {
3352 if (selection->time.length()) {
3353 duplicate_selection (times);
3355 } else if (get_smart_mode()) {
3356 if (selection->time.length()) {
3357 duplicate_selection (times);
3359 duplicate_some_regions (rs, times);
3361 duplicate_some_regions (rs, times);
3366 Editor::set_edit_mode (EditMode m)
3368 Config->set_edit_mode (m);
3372 Editor::cycle_edit_mode ()
3374 switch (Config->get_edit_mode()) {
3376 if (Profile->get_sae()) {
3377 Config->set_edit_mode (Lock);
3379 Config->set_edit_mode (Splice);
3383 Config->set_edit_mode (Lock);
3386 Config->set_edit_mode (Slide);
3392 Editor::edit_mode_selection_done ()
3394 string s = edit_mode_selector.get_active_text ();
3397 Config->set_edit_mode (string_to_edit_mode (s));
3402 Editor::snap_type_selection_done ()
3404 string choice = snap_type_selector.get_active_text();
3405 SnapType snaptype = SnapToBeat;
3407 if (choice == _("Beats/2")) {
3408 snaptype = SnapToBeatDiv2;
3409 } else if (choice == _("Beats/3")) {
3410 snaptype = SnapToBeatDiv3;
3411 } else if (choice == _("Beats/4")) {
3412 snaptype = SnapToBeatDiv4;
3413 } else if (choice == _("Beats/5")) {
3414 snaptype = SnapToBeatDiv5;
3415 } else if (choice == _("Beats/6")) {
3416 snaptype = SnapToBeatDiv6;
3417 } else if (choice == _("Beats/7")) {
3418 snaptype = SnapToBeatDiv7;
3419 } else if (choice == _("Beats/8")) {
3420 snaptype = SnapToBeatDiv8;
3421 } else if (choice == _("Beats/10")) {
3422 snaptype = SnapToBeatDiv10;
3423 } else if (choice == _("Beats/12")) {
3424 snaptype = SnapToBeatDiv12;
3425 } else if (choice == _("Beats/14")) {
3426 snaptype = SnapToBeatDiv14;
3427 } else if (choice == _("Beats/16")) {
3428 snaptype = SnapToBeatDiv16;
3429 } else if (choice == _("Beats/20")) {
3430 snaptype = SnapToBeatDiv20;
3431 } else if (choice == _("Beats/24")) {
3432 snaptype = SnapToBeatDiv24;
3433 } else if (choice == _("Beats/28")) {
3434 snaptype = SnapToBeatDiv28;
3435 } else if (choice == _("Beats/32")) {
3436 snaptype = SnapToBeatDiv32;
3437 } else if (choice == _("Beats/64")) {
3438 snaptype = SnapToBeatDiv64;
3439 } else if (choice == _("Beats/128")) {
3440 snaptype = SnapToBeatDiv128;
3441 } else if (choice == _("Beats")) {
3442 snaptype = SnapToBeat;
3443 } else if (choice == _("Bars")) {
3444 snaptype = SnapToBar;
3445 } else if (choice == _("Marks")) {
3446 snaptype = SnapToMark;
3447 } else if (choice == _("Region starts")) {
3448 snaptype = SnapToRegionStart;
3449 } else if (choice == _("Region ends")) {
3450 snaptype = SnapToRegionEnd;
3451 } else if (choice == _("Region bounds")) {
3452 snaptype = SnapToRegionBoundary;
3453 } else if (choice == _("Region syncs")) {
3454 snaptype = SnapToRegionSync;
3455 } else if (choice == _("CD Frames")) {
3456 snaptype = SnapToCDFrame;
3457 } else if (choice == _("Timecode Frames")) {
3458 snaptype = SnapToTimecodeFrame;
3459 } else if (choice == _("Timecode Seconds")) {
3460 snaptype = SnapToTimecodeSeconds;
3461 } else if (choice == _("Timecode Minutes")) {
3462 snaptype = SnapToTimecodeMinutes;
3463 } else if (choice == _("Seconds")) {
3464 snaptype = SnapToSeconds;
3465 } else if (choice == _("Minutes")) {
3466 snaptype = SnapToMinutes;
3469 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3471 ract->set_active ();
3476 Editor::snap_mode_selection_done ()
3478 string choice = snap_mode_selector.get_active_text();
3479 SnapMode mode = SnapNormal;
3481 if (choice == _("No Grid")) {
3483 } else if (choice == _("Grid")) {
3485 } else if (choice == _("Magnetic")) {
3486 mode = SnapMagnetic;
3489 RefPtr<RadioAction> ract = snap_mode_action (mode);
3492 ract->set_active (true);
3497 Editor::cycle_edit_point (bool with_marker)
3499 switch (_edit_point) {
3501 set_edit_point_preference (EditAtPlayhead);
3503 case EditAtPlayhead:
3505 set_edit_point_preference (EditAtSelectedMarker);
3507 set_edit_point_preference (EditAtMouse);
3510 case EditAtSelectedMarker:
3511 set_edit_point_preference (EditAtMouse);
3517 Editor::edit_point_selection_done ()
3519 string choice = edit_point_selector.get_active_text();
3520 EditPoint ep = EditAtSelectedMarker;
3522 if (choice == _("Marker")) {
3523 set_edit_point_preference (EditAtSelectedMarker);
3524 } else if (choice == _("Playhead")) {
3525 set_edit_point_preference (EditAtPlayhead);
3527 set_edit_point_preference (EditAtMouse);
3530 RefPtr<RadioAction> ract = edit_point_action (ep);
3533 ract->set_active (true);
3538 Editor::zoom_focus_selection_done ()
3540 string choice = zoom_focus_selector.get_active_text();
3541 ZoomFocus focus_type = ZoomFocusLeft;
3543 if (choice == _("Left")) {
3544 focus_type = ZoomFocusLeft;
3545 } else if (choice == _("Right")) {
3546 focus_type = ZoomFocusRight;
3547 } else if (choice == _("Center")) {
3548 focus_type = ZoomFocusCenter;
3549 } else if (choice == _("Playhead")) {
3550 focus_type = ZoomFocusPlayhead;
3551 } else if (choice == _("Mouse")) {
3552 focus_type = ZoomFocusMouse;
3553 } else if (choice == _("Edit point")) {
3554 focus_type = ZoomFocusEdit;
3557 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3560 ract->set_active ();
3565 Editor::edit_controls_button_release (GdkEventButton* ev)
3567 if (Keyboard::is_context_menu_event (ev)) {
3568 ARDOUR_UI::instance()->add_route (this);
3569 } else if (ev->button == 1) {
3570 selection->clear_tracks ();
3577 Editor::mouse_select_button_release (GdkEventButton* ev)
3579 /* this handles just right-clicks */
3581 if (ev->button != 3) {
3589 Editor::set_zoom_focus (ZoomFocus f)
3591 string str = zoom_focus_strings[(int)f];
3593 if (str != zoom_focus_selector.get_active_text()) {
3594 zoom_focus_selector.set_active_text (str);
3597 if (zoom_focus != f) {
3604 Editor::cycle_zoom_focus ()
3606 switch (zoom_focus) {
3608 set_zoom_focus (ZoomFocusRight);
3610 case ZoomFocusRight:
3611 set_zoom_focus (ZoomFocusCenter);
3613 case ZoomFocusCenter:
3614 set_zoom_focus (ZoomFocusPlayhead);
3616 case ZoomFocusPlayhead:
3617 set_zoom_focus (ZoomFocusMouse);
3619 case ZoomFocusMouse:
3620 set_zoom_focus (ZoomFocusEdit);
3623 set_zoom_focus (ZoomFocusLeft);
3629 Editor::ensure_float (Window& win)
3631 win.set_transient_for (*this);
3635 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3637 /* recover or initialize pane positions. do this here rather than earlier because
3638 we don't want the positions to change the child allocations, which they seem to do.
3644 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3653 XMLNode* geometry = find_named_node (*node, "geometry");
3655 if (which == static_cast<Paned*> (&edit_pane)) {
3657 if (done & Horizontal) {
3661 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3662 _notebook_shrunk = string_is_affirmative (prop->value ());
3665 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3666 /* initial allocation is 90% to canvas, 10% to notebook */
3667 pos = (int) floor (alloc.get_width() * 0.90f);
3668 snprintf (buf, sizeof(buf), "%d", pos);
3670 pos = atoi (prop->value());
3673 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3674 edit_pane.set_position (pos);
3677 done = (Pane) (done | Horizontal);
3679 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3681 if (done & Vertical) {
3685 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3686 /* initial allocation is 90% to canvas, 10% to summary */
3687 pos = (int) floor (alloc.get_height() * 0.90f);
3688 snprintf (buf, sizeof(buf), "%d", pos);
3691 pos = atoi (prop->value());
3694 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3695 editor_summary_pane.set_position (pos);
3698 done = (Pane) (done | Vertical);
3703 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3705 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3706 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3707 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3708 top_hbox.remove (toolbar_frame);
3713 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3715 if (toolbar_frame.get_parent() == 0) {
3716 top_hbox.pack_end (toolbar_frame);
3721 Editor::set_show_measures (bool yn)
3723 if (_show_measures != yn) {
3726 if ((_show_measures = yn) == true) {
3728 tempo_lines->show();
3730 (void) redraw_measures ();
3737 Editor::toggle_follow_playhead ()
3739 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3741 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3742 set_follow_playhead (tact->get_active());
3746 /** @param yn true to follow playhead, otherwise false.
3747 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3750 Editor::set_follow_playhead (bool yn, bool catch_up)
3752 if (_follow_playhead != yn) {
3753 if ((_follow_playhead = yn) == true && catch_up) {
3755 reset_x_origin_to_follow_playhead ();
3762 Editor::toggle_stationary_playhead ()
3764 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3766 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3767 set_stationary_playhead (tact->get_active());
3772 Editor::set_stationary_playhead (bool yn)
3774 if (_stationary_playhead != yn) {
3775 if ((_stationary_playhead = yn) == true) {
3777 // FIXME need a 3.0 equivalent of this 2.X call
3778 // update_current_screen ();
3785 Editor::playlist_selector () const
3787 return *_playlist_selector;
3791 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3795 switch (_snap_type) {
3800 case SnapToBeatDiv128:
3803 case SnapToBeatDiv64:
3806 case SnapToBeatDiv32:
3809 case SnapToBeatDiv28:
3812 case SnapToBeatDiv24:
3815 case SnapToBeatDiv20:
3818 case SnapToBeatDiv16:
3821 case SnapToBeatDiv14:
3824 case SnapToBeatDiv12:
3827 case SnapToBeatDiv10:
3830 case SnapToBeatDiv8:
3833 case SnapToBeatDiv7:
3836 case SnapToBeatDiv6:
3839 case SnapToBeatDiv5:
3842 case SnapToBeatDiv4:
3845 case SnapToBeatDiv3:
3848 case SnapToBeatDiv2:
3854 return _session->tempo_map().meter_at (position).divisions_per_bar();
3859 case SnapToTimecodeFrame:
3860 case SnapToTimecodeSeconds:
3861 case SnapToTimecodeMinutes:
3864 case SnapToRegionStart:
3865 case SnapToRegionEnd:
3866 case SnapToRegionSync:
3867 case SnapToRegionBoundary:
3877 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3881 ret = nudge_clock->current_duration (pos);
3882 next = ret + 1; /* XXXX fix me */
3888 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3890 ArdourDialog dialog (_("Playlist Deletion"));
3891 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3892 "If it is kept, its audio files will not be cleaned.\n"
3893 "If it is deleted, audio files used by it alone will be cleaned."),
3896 dialog.set_position (WIN_POS_CENTER);
3897 dialog.get_vbox()->pack_start (label);
3901 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3902 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3903 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3905 switch (dialog.run ()) {
3906 case RESPONSE_ACCEPT:
3907 /* delete the playlist */
3911 case RESPONSE_REJECT:
3912 /* keep the playlist */
3924 Editor::audio_region_selection_covers (framepos_t where)
3926 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3927 if ((*a)->region()->covers (where)) {
3936 Editor::prepare_for_cleanup ()
3938 cut_buffer->clear_regions ();
3939 cut_buffer->clear_playlists ();
3941 selection->clear_regions ();
3942 selection->clear_playlists ();
3944 _regions->suspend_redisplay ();
3948 Editor::finish_cleanup ()
3950 _regions->resume_redisplay ();
3954 Editor::transport_loop_location()
3957 return _session->locations()->auto_loop_location();
3964 Editor::transport_punch_location()
3967 return _session->locations()->auto_punch_location();
3974 Editor::control_layout_scroll (GdkEventScroll* ev)
3976 if (Keyboard::some_magic_widget_has_focus()) {
3980 switch (ev->direction) {
3982 scroll_tracks_up_line ();
3986 case GDK_SCROLL_DOWN:
3987 scroll_tracks_down_line ();
3991 /* no left/right handling yet */
3999 Editor::session_state_saved (string)
4002 _snapshots->redisplay ();
4006 Editor::update_tearoff_visibility()
4008 bool visible = Config->get_keep_tearoffs();
4009 _mouse_mode_tearoff->set_visible (visible);
4010 _tools_tearoff->set_visible (visible);
4011 _zoom_tearoff->set_visible (visible);
4015 Editor::maximise_editing_space ()
4027 Editor::restore_editing_space ()
4039 * Make new playlists for a given track and also any others that belong
4040 * to the same active route group with the `select' property.
4045 Editor::new_playlists (TimeAxisView* v)
4047 begin_reversible_command (_("new playlists"));
4048 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4049 _session->playlists->get (playlists);
4050 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4051 commit_reversible_command ();
4055 * Use a copy of the current playlist for a given track and also any others that belong
4056 * to the same active route group with the `select' property.
4061 Editor::copy_playlists (TimeAxisView* v)
4063 begin_reversible_command (_("copy playlists"));
4064 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4065 _session->playlists->get (playlists);
4066 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4067 commit_reversible_command ();
4070 /** Clear the current playlist for a given track and also any others that belong
4071 * to the same active route group with the `select' property.
4076 Editor::clear_playlists (TimeAxisView* v)
4078 begin_reversible_command (_("clear playlists"));
4079 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4080 _session->playlists->get (playlists);
4081 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4082 commit_reversible_command ();
4086 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4088 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4092 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4094 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4098 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4100 atv.clear_playlist ();
4104 Editor::on_key_press_event (GdkEventKey* ev)
4106 return key_press_focus_accelerator_handler (*this, ev);
4110 Editor::on_key_release_event (GdkEventKey* ev)
4112 return Gtk::Window::on_key_release_event (ev);
4113 // return key_press_focus_accelerator_handler (*this, ev);
4116 /** Queue up a change to the viewport x origin.
4117 * @param frame New x origin.
4120 Editor::reset_x_origin (framepos_t frame)
4122 pending_visual_change.add (VisualChange::TimeOrigin);
4123 pending_visual_change.time_origin = frame;
4124 ensure_visual_change_idle_handler ();
4128 Editor::reset_y_origin (double y)
4130 pending_visual_change.add (VisualChange::YOrigin);
4131 pending_visual_change.y_origin = y;
4132 ensure_visual_change_idle_handler ();
4136 Editor::reset_zoom (double fpu)
4138 clamp_frames_per_unit (fpu);
4140 if (fpu == frames_per_unit) {
4144 pending_visual_change.add (VisualChange::ZoomLevel);
4145 pending_visual_change.frames_per_unit = fpu;
4146 ensure_visual_change_idle_handler ();
4150 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4152 reset_x_origin (frame);
4155 if (!no_save_visual) {
4156 undo_visual_stack.push_back (current_visual_state(false));
4160 Editor::VisualState::VisualState (bool with_tracks)
4161 : gui_state (with_tracks ? new GUIObjectState : 0)
4165 Editor::VisualState::~VisualState ()
4170 Editor::VisualState*
4171 Editor::current_visual_state (bool with_tracks)
4173 VisualState* vs = new VisualState (with_tracks);
4174 vs->y_position = vertical_adjustment.get_value();
4175 vs->frames_per_unit = frames_per_unit;
4176 vs->leftmost_frame = leftmost_frame;
4177 vs->zoom_focus = zoom_focus;
4180 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4187 Editor::undo_visual_state ()
4189 if (undo_visual_stack.empty()) {
4193 VisualState* vs = undo_visual_stack.back();
4194 undo_visual_stack.pop_back();
4197 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4199 use_visual_state (*vs);
4203 Editor::redo_visual_state ()
4205 if (redo_visual_stack.empty()) {
4209 VisualState* vs = redo_visual_stack.back();
4210 redo_visual_stack.pop_back();
4212 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4214 use_visual_state (*vs);
4218 Editor::swap_visual_state ()
4220 if (undo_visual_stack.empty()) {
4221 redo_visual_state ();
4223 undo_visual_state ();
4228 Editor::use_visual_state (VisualState& vs)
4230 PBD::Unwinder<bool> nsv (no_save_visual, true);
4232 _routes->suspend_redisplay ();
4234 vertical_adjustment.set_value (vs.y_position);
4236 set_zoom_focus (vs.zoom_focus);
4237 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4240 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4242 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4243 (*i)->reset_visual_state ();
4247 _routes->update_visibility ();
4248 _routes->resume_redisplay ();
4251 /** This is the core function that controls the zoom level of the canvas. It is called
4252 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4253 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4256 Editor::set_frames_per_unit (double fpu)
4259 tempo_lines->tempo_map_changed();
4262 frames_per_unit = fpu;
4264 /* convert fpu to frame count */
4266 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4268 if (frames_per_unit != zoom_range_clock->current_duration()) {
4269 zoom_range_clock->set (frames);
4272 bool const showing_time_selection = selection->time.length() > 0;
4274 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4275 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4276 (*i)->reshow_selection (selection->time);
4280 ZoomChanged (); /* EMIT_SIGNAL */
4282 //reset_scrolling_region ();
4284 if (playhead_cursor) {
4285 playhead_cursor->set_position (playhead_cursor->current_frame);
4288 refresh_location_display();
4289 _summary->set_overlays_dirty ();
4291 update_marker_labels ();
4296 #ifdef WITH_VIDEOTIMELINE
4298 Editor::queue_visual_videotimeline_update ()
4301 * pending_visual_change.add (VisualChange::VideoTimeline);
4302 * or maybe even more specific: which videotimeline-image
4303 * currently it calls update_video_timeline() to update
4304 * _all outdated_ images on the video-timeline.
4305 * see 'exposeimg()' in video_image_frame.cc
4307 ensure_visual_change_idle_handler ();
4312 Editor::ensure_visual_change_idle_handler ()
4314 if (pending_visual_change.idle_handler_id < 0) {
4315 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4320 Editor::_idle_visual_changer (void* arg)
4322 return static_cast<Editor*>(arg)->idle_visual_changer ();
4326 Editor::idle_visual_changer ()
4328 /* set_horizontal_position() below (and maybe other calls) call
4329 gtk_main_iteration(), so it's possible that a signal will be handled
4330 half-way through this method. If this signal wants an
4331 idle_visual_changer we must schedule another one after this one, so
4332 mark the idle_handler_id as -1 here to allow that. Also make a note
4333 that we are doing the visual change, so that changes in response to
4334 super-rapid-screen-update can be dropped if we are still processing
4338 pending_visual_change.idle_handler_id = -1;
4339 pending_visual_change.being_handled = true;
4341 VisualChange::Type p = pending_visual_change.pending;
4342 pending_visual_change.pending = (VisualChange::Type) 0;
4344 double const last_time_origin = horizontal_position ();
4346 if (p & VisualChange::ZoomLevel) {
4347 set_frames_per_unit (pending_visual_change.frames_per_unit);
4349 compute_fixed_ruler_scale ();
4351 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4352 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4354 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4355 current_bbt_points_begin, current_bbt_points_end);
4356 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4357 current_bbt_points_begin, current_bbt_points_end);
4358 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4361 #ifdef WITH_VIDEOTIMELINE
4362 if (p & VisualChange::ZoomLevel) {
4363 update_video_timeline();
4367 if (p & VisualChange::TimeOrigin) {
4368 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4371 if (p & VisualChange::YOrigin) {
4372 vertical_adjustment.set_value (pending_visual_change.y_origin);
4375 if (last_time_origin == horizontal_position ()) {
4376 /* changed signal not emitted */
4377 update_fixed_rulers ();
4378 redisplay_tempo (true);
4380 #ifdef WITH_VIDEOTIMELINE
4381 if (!(p & VisualChange::ZoomLevel)) {
4382 update_video_timeline();
4386 _summary->set_overlays_dirty ();
4388 pending_visual_change.being_handled = false;
4389 return 0; /* this is always a one-shot call */
4392 struct EditorOrderTimeAxisSorter {
4393 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4394 return a->order () < b->order ();
4399 Editor::sort_track_selection (TrackViewList& sel)
4401 EditorOrderTimeAxisSorter cmp;
4406 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4409 framepos_t where = 0;
4410 EditPoint ep = _edit_point;
4412 if (from_context_menu && (ep == EditAtMouse)) {
4413 return event_frame (&context_click_event, 0, 0);
4416 if (entered_marker) {
4417 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4418 return entered_marker->position();
4421 if (ignore_playhead && ep == EditAtPlayhead) {
4422 ep = EditAtSelectedMarker;
4426 case EditAtPlayhead:
4427 where = _session->audible_frame();
4428 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4431 case EditAtSelectedMarker:
4432 if (!selection->markers.empty()) {
4434 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4437 where = loc->start();
4441 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4449 if (!mouse_frame (where, ignored)) {
4450 /* XXX not right but what can we do ? */
4454 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4462 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4464 if (!_session) return;
4466 begin_reversible_command (cmd);
4470 if ((tll = transport_loop_location()) == 0) {
4471 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4472 XMLNode &before = _session->locations()->get_state();
4473 _session->locations()->add (loc, true);
4474 _session->set_auto_loop_location (loc);
4475 XMLNode &after = _session->locations()->get_state();
4476 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4478 XMLNode &before = tll->get_state();
4479 tll->set_hidden (false, this);
4480 tll->set (start, end);
4481 XMLNode &after = tll->get_state();
4482 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4485 commit_reversible_command ();
4489 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4491 if (!_session) return;
4493 begin_reversible_command (cmd);
4497 if ((tpl = transport_punch_location()) == 0) {
4498 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4499 XMLNode &before = _session->locations()->get_state();
4500 _session->locations()->add (loc, true);
4501 _session->set_auto_loop_location (loc);
4502 XMLNode &after = _session->locations()->get_state();
4503 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4506 XMLNode &before = tpl->get_state();
4507 tpl->set_hidden (false, this);
4508 tpl->set (start, end);
4509 XMLNode &after = tpl->get_state();
4510 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4513 commit_reversible_command ();
4516 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4517 * @param rs List to which found regions are added.
4518 * @param where Time to look at.
4519 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4522 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4524 const TrackViewList* tracks;
4527 tracks = &track_views;
4532 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4534 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4537 boost::shared_ptr<Track> tr;
4538 boost::shared_ptr<Playlist> pl;
4540 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4542 boost::shared_ptr<RegionList> regions = pl->regions_at (
4543 (framepos_t) floor ( (double) where * tr->speed()));
4545 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4546 RegionView* rv = rtv->view()->find_view (*i);
4557 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4559 const TrackViewList* tracks;
4562 tracks = &track_views;
4567 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4568 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4570 boost::shared_ptr<Track> tr;
4571 boost::shared_ptr<Playlist> pl;
4573 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4575 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4576 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4578 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4580 RegionView* rv = rtv->view()->find_view (*i);
4591 /** Get regions using the following method:
4593 * Make a region list using the selected regions, unless
4594 * the edit point is `mouse' and the mouse is over an unselected
4595 * region. In this case, use just that region.
4597 * If the edit point is not 'mouse', and there are no regions selected,
4598 * search the list of selected tracks and return regions that are under
4599 * the edit point on these tracks. If there are no selected tracks and
4600 * 'No Selection = All Tracks' is active, search all tracks,
4602 * The rationale here is that the mouse edit point is special in that
4603 * its position describes both a time and a track; the other edit
4604 * modes only describe a time. Hence if the edit point is `mouse' we
4605 * ignore selected tracks, as we assume the user means something by
4606 * pointing at a particular track. Also in this case we take note of
4607 * the region directly under the edit point, as there is always just one
4608 * (rather than possibly several with non-mouse edit points).
4612 Editor::get_regions_from_selection_and_edit_point ()
4614 RegionSelection regions;
4616 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4617 regions.add (entered_regionview);
4619 regions = selection->regions;
4623 if (regions.empty() && _edit_point != EditAtMouse) {
4624 TrackViewList tracks = selection->tracks;
4626 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4627 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4628 * is enabled, so consider all tracks
4630 tracks = track_views;
4633 if (!tracks.empty()) {
4634 /* no region selected or entered, but some selected tracks:
4635 * act on all regions on the selected tracks at the edit point
4637 framepos_t const where = get_preferred_edit_position ();
4638 get_regions_at(regions, where, tracks);
4644 /** Start with regions that are selected, or the entered regionview if none are selected.
4645 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4646 * of the regions that we started with.
4650 Editor::get_regions_from_selection_and_entered ()
4652 RegionSelection regions = selection->regions;
4654 if (regions.empty() && entered_regionview) {
4655 regions.add (entered_regionview);
4662 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4664 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4666 RouteTimeAxisView* tatv;
4668 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4670 boost::shared_ptr<Playlist> pl;
4671 vector<boost::shared_ptr<Region> > results;
4673 boost::shared_ptr<Track> tr;
4675 if ((tr = tatv->track()) == 0) {
4680 if ((pl = (tr->playlist())) != 0) {
4681 if (src_comparison) {
4682 pl->get_source_equivalent_regions (region, results);
4684 pl->get_region_list_equivalent_regions (region, results);
4688 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4689 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4690 regions.push_back (marv);
4699 Editor::show_rhythm_ferret ()
4701 if (rhythm_ferret == 0) {
4702 rhythm_ferret = new RhythmFerret(*this);
4705 rhythm_ferret->set_session (_session);
4706 rhythm_ferret->show ();
4707 rhythm_ferret->present ();
4711 Editor::first_idle ()
4713 MessageDialog* dialog = 0;
4715 if (track_views.size() > 1) {
4716 dialog = new MessageDialog (
4718 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4722 ARDOUR_UI::instance()->flush_pending ();
4725 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4729 // first idle adds route children (automation tracks), so we need to redisplay here
4730 _routes->redisplay ();
4737 Editor::_idle_resize (gpointer arg)
4739 return ((Editor*)arg)->idle_resize ();
4743 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4745 if (resize_idle_id < 0) {
4746 resize_idle_id = g_idle_add (_idle_resize, this);
4747 _pending_resize_amount = 0;
4750 /* make a note of the smallest resulting height, so that we can clamp the
4751 lower limit at TimeAxisView::hSmall */
4753 int32_t min_resulting = INT32_MAX;
4755 _pending_resize_amount += h;
4756 _pending_resize_view = view;
4758 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4760 if (selection->tracks.contains (_pending_resize_view)) {
4761 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4762 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4766 if (min_resulting < 0) {
4771 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4772 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4776 /** Handle pending resizing of tracks */
4778 Editor::idle_resize ()
4780 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4782 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4783 selection->tracks.contains (_pending_resize_view)) {
4785 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4786 if (*i != _pending_resize_view) {
4787 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4792 _pending_resize_amount = 0;
4794 _group_tabs->set_dirty ();
4795 resize_idle_id = -1;
4803 ENSURE_GUI_THREAD (*this, &Editor::located);
4806 playhead_cursor->set_position (_session->audible_frame ());
4807 if (_follow_playhead && !_pending_initial_locate) {
4808 reset_x_origin_to_follow_playhead ();
4812 _pending_locate_request = false;
4813 _pending_initial_locate = false;
4817 Editor::region_view_added (RegionView *)
4819 _summary->set_dirty ();
4823 Editor::region_view_removed ()
4825 _summary->set_dirty ();
4829 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4831 TrackViewList::const_iterator j = track_views.begin ();
4832 while (j != track_views.end()) {
4833 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4834 if (rtv && rtv->route() == r) {
4845 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4849 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4850 TimeAxisView* tv = axis_view_from_route (*i);
4860 Editor::add_routes (RouteList& routes)
4862 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4864 RouteTimeAxisView *rtv;
4865 list<RouteTimeAxisView*> new_views;
4867 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4868 boost::shared_ptr<Route> route = (*x);
4870 if (route->is_hidden() || route->is_monitor()) {
4874 DataType dt = route->input()->default_type();
4876 if (dt == ARDOUR::DataType::AUDIO) {
4877 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4878 rtv->set_route (route);
4879 } else if (dt == ARDOUR::DataType::MIDI) {
4880 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4881 rtv->set_route (route);
4883 throw unknown_type();
4886 new_views.push_back (rtv);
4887 track_views.push_back (rtv);
4889 rtv->effective_gain_display ();
4891 if (internal_editing()) {
4892 rtv->enter_internal_edit_mode ();
4894 rtv->leave_internal_edit_mode ();
4897 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4898 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4901 _routes->routes_added (new_views);
4902 _summary->routes_added (new_views);
4904 if (show_editor_mixer_when_tracks_arrive) {
4905 show_editor_mixer (true);
4908 editor_list_button.set_sensitive (true);
4912 Editor::timeaxisview_deleted (TimeAxisView *tv)
4914 if (_session && _session->deletion_in_progress()) {
4915 /* the situation is under control */
4919 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4921 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4923 _routes->route_removed (tv);
4925 if (tv == entered_track) {
4929 TimeAxisView::Children c = tv->get_child_list ();
4930 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4931 if (entered_track == i->get()) {
4936 /* remove it from the list of track views */
4938 TrackViewList::iterator i;
4940 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4941 i = track_views.erase (i);
4944 /* update whatever the current mixer strip is displaying, if revelant */
4946 boost::shared_ptr<Route> route;
4949 route = rtav->route ();
4952 if (current_mixer_strip && current_mixer_strip->route() == route) {
4954 TimeAxisView* next_tv;
4956 if (track_views.empty()) {
4958 } else if (i == track_views.end()) {
4959 next_tv = track_views.front();
4966 set_selected_mixer_strip (*next_tv);
4968 /* make the editor mixer strip go away setting the
4969 * button to inactive (which also unticks the menu option)
4972 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4978 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4980 if (apply_to_selection) {
4981 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4983 TrackSelection::iterator j = i;
4986 hide_track_in_display (*i, false);
4991 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4993 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4994 // this will hide the mixer strip
4995 set_selected_mixer_strip (*tv);
4998 _routes->hide_track_in_display (*tv);
5003 Editor::sync_track_view_list_and_routes ()
5005 track_views = TrackViewList (_routes->views ());
5007 _summary->set_dirty ();
5008 _group_tabs->set_dirty ();
5010 return false; // do not call again (until needed)
5014 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5016 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5021 /** Find a RouteTimeAxisView by the ID of its route */
5023 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5025 RouteTimeAxisView* v;
5027 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5028 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5029 if(v->route()->id() == id) {
5039 Editor::fit_route_group (RouteGroup *g)
5041 TrackViewList ts = axis_views_from_routes (g->route_list ());
5046 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5048 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5051 _session->cancel_audition ();
5055 if (_session->is_auditioning()) {
5056 _session->cancel_audition ();
5057 if (r == last_audition_region) {
5062 _session->audition_region (r);
5063 last_audition_region = r;
5068 Editor::hide_a_region (boost::shared_ptr<Region> r)
5070 r->set_hidden (true);
5074 Editor::show_a_region (boost::shared_ptr<Region> r)
5076 r->set_hidden (false);
5080 Editor::audition_region_from_region_list ()
5082 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5086 Editor::hide_region_from_region_list ()
5088 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5092 Editor::show_region_in_region_list ()
5094 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5098 Editor::step_edit_status_change (bool yn)
5101 start_step_editing ();
5103 stop_step_editing ();
5108 Editor::start_step_editing ()
5110 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5114 Editor::stop_step_editing ()
5116 step_edit_connection.disconnect ();
5120 Editor::check_step_edit ()
5122 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5123 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5125 mtv->check_step_edit ();
5129 return true; // do it again, till we stop
5133 Editor::scroll_press (Direction dir)
5135 ++_scroll_callbacks;
5137 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5138 /* delay the first auto-repeat */
5144 scroll_backward (1);
5152 scroll_tracks_up_line ();
5156 scroll_tracks_down_line ();
5160 /* do hacky auto-repeat */
5161 if (!_scroll_connection.connected ()) {
5163 _scroll_connection = Glib::signal_timeout().connect (
5164 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5167 _scroll_callbacks = 0;
5174 Editor::scroll_release ()
5176 _scroll_connection.disconnect ();
5179 /** Queue a change for the Editor viewport x origin to follow the playhead */
5181 Editor::reset_x_origin_to_follow_playhead ()
5183 framepos_t const frame = playhead_cursor->current_frame;
5185 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5187 if (_session->transport_speed() < 0) {
5189 if (frame > (current_page_frames() / 2)) {
5190 center_screen (frame-(current_page_frames()/2));
5192 center_screen (current_page_frames()/2);
5199 if (frame < leftmost_frame) {
5201 if (_session->transport_rolling()) {
5202 /* rolling; end up with the playhead at the right of the page */
5203 l = frame - current_page_frames ();
5205 /* not rolling: end up with the playhead 1/4 of the way along the page */
5206 l = frame - current_page_frames() / 4;
5210 if (_session->transport_rolling()) {
5211 /* rolling: end up with the playhead on the left of the page */
5214 /* not rolling: end up with the playhead 3/4 of the way along the page */
5215 l = frame - 3 * current_page_frames() / 4;
5223 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5229 Editor::super_rapid_screen_update ()
5231 if (!_session || !_session->engine().running()) {
5235 /* METERING / MIXER STRIPS */
5237 /* update track meters, if required */
5238 if (is_mapped() && meters_running) {
5239 RouteTimeAxisView* rtv;
5240 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5241 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5242 rtv->fast_update ();
5247 /* and any current mixer strip */
5248 if (current_mixer_strip) {
5249 current_mixer_strip->fast_update ();
5252 /* PLAYHEAD AND VIEWPORT */
5254 framepos_t const frame = _session->audible_frame();
5256 /* There are a few reasons why we might not update the playhead / viewport stuff:
5258 * 1. we don't update things when there's a pending locate request, otherwise
5259 * when the editor requests a locate there is a chance that this method
5260 * will move the playhead before the locate request is processed, causing
5262 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5263 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5266 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5268 last_update_frame = frame;
5270 if (!_dragging_playhead) {
5271 playhead_cursor->set_position (frame);
5274 if (!_stationary_playhead) {
5276 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5277 /* We only do this if we aren't already
5278 handling a visual change (ie if
5279 pending_visual_change.being_handled is
5280 false) so that these requests don't stack
5281 up there are too many of them to handle in
5284 reset_x_origin_to_follow_playhead ();
5289 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5293 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5294 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5295 if (target <= 0.0) {
5298 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5299 target = (target * 0.15) + (current * 0.85);
5305 set_horizontal_position (current);
5314 Editor::session_going_away ()
5316 _have_idled = false;
5318 _session_connections.drop_connections ();
5320 super_rapid_screen_update_connection.disconnect ();
5322 selection->clear ();
5323 cut_buffer->clear ();
5325 clicked_regionview = 0;
5326 clicked_axisview = 0;
5327 clicked_routeview = 0;
5328 entered_regionview = 0;
5330 last_update_frame = 0;
5333 playhead_cursor->canvas_item.hide ();
5335 /* rip everything out of the list displays */
5339 _route_groups->clear ();
5341 /* do this first so that deleting a track doesn't reset cms to null
5342 and thus cause a leak.
5345 if (current_mixer_strip) {
5346 if (current_mixer_strip->get_parent() != 0) {
5347 global_hpacker.remove (*current_mixer_strip);
5349 delete current_mixer_strip;
5350 current_mixer_strip = 0;
5353 /* delete all trackviews */
5355 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5358 track_views.clear ();
5360 zoom_range_clock->set_session (0);
5361 nudge_clock->set_session (0);
5363 editor_list_button.set_active(false);
5364 editor_list_button.set_sensitive(false);
5366 /* clear tempo/meter rulers */
5367 remove_metric_marks ();
5369 clear_marker_display ();
5371 stop_step_editing ();
5373 /* get rid of any existing editor mixer strip */
5375 WindowTitle title(Glib::get_application_name());
5376 title += _("Editor");
5378 set_title (title.get_string());
5380 SessionHandlePtr::session_going_away ();
5385 Editor::show_editor_list (bool yn)
5388 _the_notebook.show ();
5390 _the_notebook.hide ();
5395 Editor::change_region_layering_order (bool from_context_menu)
5397 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5399 if (!clicked_routeview) {
5400 if (layering_order_editor) {
5401 layering_order_editor->hide ();
5406 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5412 boost::shared_ptr<Playlist> pl = track->playlist();
5418 if (layering_order_editor == 0) {
5419 layering_order_editor = new RegionLayeringOrderEditor (*this);
5420 layering_order_editor->set_position (WIN_POS_MOUSE);
5423 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5424 layering_order_editor->maybe_present ();
5428 Editor::update_region_layering_order_editor ()
5430 if (layering_order_editor && layering_order_editor->is_visible ()) {
5431 change_region_layering_order (true);
5436 Editor::setup_fade_images ()
5438 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5439 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5440 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5441 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5442 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5444 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5445 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5446 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5447 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5448 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5450 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5451 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5452 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5453 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5454 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5456 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5457 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5458 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5459 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5460 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5464 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5466 Editor::action_menu_item (std::string const & name)
5468 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5471 return *manage (a->create_menu_item ());
5475 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5477 EventBox* b = manage (new EventBox);
5478 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5479 Label* l = manage (new Label (name));
5483 _the_notebook.append_page (widget, *b);
5487 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5489 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5490 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5493 if (ev->type == GDK_2BUTTON_PRESS) {
5495 /* double-click on a notebook tab shrinks or expands the notebook */
5497 if (_notebook_shrunk) {
5498 if (pre_notebook_shrink_pane_width) {
5499 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5501 _notebook_shrunk = false;
5503 pre_notebook_shrink_pane_width = edit_pane.get_position();
5505 /* this expands the LHS of the edit pane to cover the notebook
5506 PAGE but leaves the tabs visible.
5508 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5509 _notebook_shrunk = true;
5517 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5519 using namespace Menu_Helpers;
5521 MenuList& items = _control_point_context_menu.items ();
5524 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5525 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5526 if (!can_remove_control_point (item)) {
5527 items.back().set_sensitive (false);
5530 _control_point_context_menu.popup (event->button.button, event->button.time);
5534 Editor::shift_key_released ()
5536 _stepping_axis_view = 0;