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"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
124 #include "verbose_cursor.h"
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_edit_mode_strings[] = {
199 static const gchar *_zoom_focus_strings[] = {
209 #ifdef USE_RUBBERBAND
210 static const gchar *_rb_opt_strings[] = {
213 N_("Balanced multitimbral mixture"),
214 N_("Unpitched percussion with stable notes"),
215 N_("Crisp monophonic instrumental"),
216 N_("Unpitched solo percussion"),
217 N_("Resample without preserving pitch"),
222 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
225 pane_size_watcher (Paned* pane)
227 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
231 Quartz: impossible to access
233 so stop that by preventing it from ever getting too narrow. 35
234 pixels is basically a rough guess at the tab width.
239 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
241 gint pos = pane->get_position ();
243 if (pos > max_width_of_lhs) {
244 pane->set_position (max_width_of_lhs);
249 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
251 /* time display buttons */
252 , minsec_label (_("Mins:Secs"))
253 , bbt_label (_("Bars:Beats"))
254 , timecode_label (_("Timecode"))
255 , samples_label (_("Samples"))
256 , tempo_label (_("Tempo"))
257 , meter_label (_("Meter"))
258 , mark_label (_("Location Markers"))
259 , range_mark_label (_("Range Markers"))
260 , transport_mark_label (_("Loop/Punch Ranges"))
261 , cd_mark_label (_("CD Markers"))
262 , videotl_label (_("Video Timeline"))
263 , edit_packer (4, 4, true)
265 /* the values here don't matter: layout widgets
266 reset them as needed.
269 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
270 , horizontal_adjustment (0.0, 0.0, 1e16)
271 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
273 , controls_layout (unused_adjustment, vertical_adjustment)
275 /* tool bar related */
277 , toolbar_selection_clock_table (2,3)
278 , _mouse_mode_tearoff (0)
279 , automation_mode_button (_("mode"))
283 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
288 , meters_running(false)
289 , _pending_locate_request (false)
290 , _pending_initial_locate (false)
291 , _last_cut_copy_source_track (0)
293 , _region_selection_change_updates_region_list (true)
294 , _following_mixer_selection (false)
295 , _control_point_toggled_on_press (false)
296 , _stepping_axis_view (0)
300 /* we are a singleton */
302 PublicEditor::_instance = this;
306 selection = new Selection (this);
307 cut_buffer = new Selection (this);
308 _selection_memento = new SelectionMemento ();
311 clicked_regionview = 0;
312 clicked_axisview = 0;
313 clicked_routeview = 0;
314 clicked_control_point = 0;
315 last_update_frame = 0;
316 pre_press_cursor = 0;
319 _drags = new DragManager (this);
322 current_mixer_strip = 0;
325 snap_type_strings = I18N (_snap_type_strings);
326 snap_mode_strings = I18N (_snap_mode_strings);
327 zoom_focus_strings = I18N (_zoom_focus_strings);
328 edit_mode_strings = I18N (_edit_mode_strings);
329 edit_point_strings = I18N (_edit_point_strings);
330 #ifdef USE_RUBBERBAND
331 rb_opt_strings = I18N (_rb_opt_strings);
335 build_edit_mode_menu();
336 build_zoom_focus_menu();
337 build_track_count_menu();
338 build_snap_mode_menu();
339 build_snap_type_menu();
340 build_edit_point_menu();
342 snap_threshold = 5.0;
343 bbt_beat_subdivision = 4;
344 _visible_canvas_width = 0;
345 _visible_canvas_height = 0;
346 autoscroll_horizontal_allowed = false;
347 autoscroll_vertical_allowed = false;
352 current_interthread_info = 0;
353 _show_measures = true;
355 show_gain_after_trim = false;
357 have_pending_keyboard_selection = false;
358 _follow_playhead = true;
359 _stationary_playhead = false;
360 editor_ruler_menu = 0;
361 no_ruler_shown_update = false;
363 range_marker_menu = 0;
364 marker_menu_item = 0;
365 tempo_or_meter_marker_menu = 0;
366 transport_marker_menu = 0;
367 new_transport_marker_menu = 0;
368 editor_mixer_strip_width = Wide;
369 show_editor_mixer_when_tracks_arrive = false;
370 region_edit_menu_split_multichannel_item = 0;
371 region_edit_menu_split_item = 0;
374 current_stepping_trackview = 0;
376 entered_regionview = 0;
378 clear_entered_track = false;
381 button_release_can_deselect = true;
382 _dragging_playhead = false;
383 _dragging_edit_point = false;
384 select_new_marker = false;
386 layering_order_editor = 0;
387 no_save_visual = false;
389 within_track_canvas = false;
391 scrubbing_direction = 0;
395 location_marker_color = ARDOUR_UI::config()->color ("location marker");
396 location_range_color = ARDOUR_UI::config()->color ("location range");
397 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
398 location_loop_color = ARDOUR_UI::config()->color ("location loop");
399 location_punch_color = ARDOUR_UI::config()->color ("location punch");
401 zoom_focus = ZoomFocusLeft;
402 _edit_point = EditAtMouse;
403 current_canvas_cursor = 0;
404 _visible_track_count = -1;
406 samples_per_pixel = 2048; /* too early to use reset_zoom () */
408 _scroll_callbacks = 0;
410 bbt_label.set_name ("EditorRulerLabel");
411 bbt_label.set_size_request (-1, (int)timebar_height);
412 bbt_label.set_alignment (1.0, 0.5);
413 bbt_label.set_padding (5,0);
415 bbt_label.set_no_show_all();
416 minsec_label.set_name ("EditorRulerLabel");
417 minsec_label.set_size_request (-1, (int)timebar_height);
418 minsec_label.set_alignment (1.0, 0.5);
419 minsec_label.set_padding (5,0);
420 minsec_label.hide ();
421 minsec_label.set_no_show_all();
422 timecode_label.set_name ("EditorRulerLabel");
423 timecode_label.set_size_request (-1, (int)timebar_height);
424 timecode_label.set_alignment (1.0, 0.5);
425 timecode_label.set_padding (5,0);
426 timecode_label.hide ();
427 timecode_label.set_no_show_all();
428 samples_label.set_name ("EditorRulerLabel");
429 samples_label.set_size_request (-1, (int)timebar_height);
430 samples_label.set_alignment (1.0, 0.5);
431 samples_label.set_padding (5,0);
432 samples_label.hide ();
433 samples_label.set_no_show_all();
435 tempo_label.set_name ("EditorRulerLabel");
436 tempo_label.set_size_request (-1, (int)timebar_height);
437 tempo_label.set_alignment (1.0, 0.5);
438 tempo_label.set_padding (5,0);
440 tempo_label.set_no_show_all();
442 meter_label.set_name ("EditorRulerLabel");
443 meter_label.set_size_request (-1, (int)timebar_height);
444 meter_label.set_alignment (1.0, 0.5);
445 meter_label.set_padding (5,0);
447 meter_label.set_no_show_all();
449 if (Profile->get_trx()) {
450 mark_label.set_text (_("Markers"));
452 mark_label.set_name ("EditorRulerLabel");
453 mark_label.set_size_request (-1, (int)timebar_height);
454 mark_label.set_alignment (1.0, 0.5);
455 mark_label.set_padding (5,0);
457 mark_label.set_no_show_all();
459 cd_mark_label.set_name ("EditorRulerLabel");
460 cd_mark_label.set_size_request (-1, (int)timebar_height);
461 cd_mark_label.set_alignment (1.0, 0.5);
462 cd_mark_label.set_padding (5,0);
463 cd_mark_label.hide();
464 cd_mark_label.set_no_show_all();
466 videotl_bar_height = 4;
467 videotl_label.set_name ("EditorRulerLabel");
468 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
469 videotl_label.set_alignment (1.0, 0.5);
470 videotl_label.set_padding (5,0);
471 videotl_label.hide();
472 videotl_label.set_no_show_all();
474 range_mark_label.set_name ("EditorRulerLabel");
475 range_mark_label.set_size_request (-1, (int)timebar_height);
476 range_mark_label.set_alignment (1.0, 0.5);
477 range_mark_label.set_padding (5,0);
478 range_mark_label.hide();
479 range_mark_label.set_no_show_all();
481 transport_mark_label.set_name ("EditorRulerLabel");
482 transport_mark_label.set_size_request (-1, (int)timebar_height);
483 transport_mark_label.set_alignment (1.0, 0.5);
484 transport_mark_label.set_padding (5,0);
485 transport_mark_label.hide();
486 transport_mark_label.set_no_show_all();
488 initialize_canvas ();
490 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
492 _summary = new EditorSummary (this);
494 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
495 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
497 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
499 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
500 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
502 edit_controls_vbox.set_spacing (0);
503 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
504 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
506 HBox* h = manage (new HBox);
507 _group_tabs = new EditorGroupTabs (this);
508 if (!ARDOUR::Profile->get_trx()) {
509 h->pack_start (*_group_tabs, PACK_SHRINK);
511 h->pack_start (edit_controls_vbox);
512 controls_layout.add (*h);
514 controls_layout.set_name ("EditControlsBase");
515 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
516 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
517 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
519 _cursors = new MouseCursors;
520 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
521 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
523 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
525 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
526 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
527 pad_line_1->set_outline_color (0xFF0000FF);
533 edit_packer.set_col_spacings (0);
534 edit_packer.set_row_spacings (0);
535 edit_packer.set_homogeneous (false);
536 edit_packer.set_border_width (0);
537 edit_packer.set_name ("EditorWindow");
539 time_bars_event_box.add (time_bars_vbox);
540 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
541 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
543 /* labels for the time bars */
544 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
546 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
548 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
550 bottom_hbox.set_border_width (2);
551 bottom_hbox.set_spacing (3);
553 _route_groups = new EditorRouteGroups (this);
554 _routes = new EditorRoutes (this);
555 _regions = new EditorRegions (this);
556 _snapshots = new EditorSnapshots (this);
557 _locations = new EditorLocations (this);
559 /* these are static location signals */
561 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
562 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
563 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
565 add_notebook_page (_("Regions"), _regions->widget ());
566 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
567 add_notebook_page (_("Snapshots"), _snapshots->widget ());
568 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
569 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
571 _the_notebook.set_show_tabs (true);
572 _the_notebook.set_scrollable (true);
573 _the_notebook.popup_disable ();
574 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
575 _the_notebook.show_all ();
577 _notebook_shrunk = false;
579 editor_summary_pane.pack1(edit_packer);
581 Button* summary_arrows_left_left = manage (new Button);
582 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
583 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
584 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
586 Button* summary_arrows_left_right = manage (new Button);
587 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
588 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
589 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591 VBox* summary_arrows_left = manage (new VBox);
592 summary_arrows_left->pack_start (*summary_arrows_left_left);
593 summary_arrows_left->pack_start (*summary_arrows_left_right);
595 Button* summary_arrows_right_up = manage (new Button);
596 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
597 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
598 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
600 Button* summary_arrows_right_down = manage (new Button);
601 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
602 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
603 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
605 VBox* summary_arrows_right = manage (new VBox);
606 summary_arrows_right->pack_start (*summary_arrows_right_up);
607 summary_arrows_right->pack_start (*summary_arrows_right_down);
609 Frame* summary_frame = manage (new Frame);
610 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
612 summary_frame->add (*_summary);
613 summary_frame->show ();
615 _summary_hbox.pack_start (*summary_arrows_left, false, false);
616 _summary_hbox.pack_start (*summary_frame, true, true);
617 _summary_hbox.pack_start (*summary_arrows_right, false, false);
619 if (!ARDOUR::Profile->get_trx()) {
620 editor_summary_pane.pack2 (_summary_hbox);
623 edit_pane.pack1 (editor_summary_pane, true, true);
624 if (!ARDOUR::Profile->get_trx()) {
625 edit_pane.pack2 (_the_notebook, false, true);
628 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
630 /* XXX: editor_summary_pane might need similar to the edit_pane */
632 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
634 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
635 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
637 top_hbox.pack_start (toolbar_frame);
639 HBox *hbox = manage (new HBox);
640 hbox->pack_start (edit_pane, true, true);
642 global_vpacker.pack_start (top_hbox, false, false);
643 global_vpacker.pack_start (*hbox, true, true);
645 global_hpacker.pack_start (global_vpacker, true, true);
647 set_name ("EditorWindow");
648 add_accel_group (ActionManager::ui_manager->get_accel_group());
650 status_bar_hpacker.show ();
652 vpacker.pack_end (status_bar_hpacker, false, false);
653 vpacker.pack_end (global_hpacker, true, true);
655 /* register actions now so that set_state() can find them and set toggles/checks etc */
658 /* when we start using our own keybinding system for the editor, this
659 * will be uncommented
665 set_zoom_focus (zoom_focus);
666 set_visible_track_count (_visible_track_count);
667 _snap_type = SnapToBeat;
668 set_snap_to (_snap_type);
669 _snap_mode = SnapOff;
670 set_snap_mode (_snap_mode);
671 set_mouse_mode (MouseObject, true);
672 set_edit_point_preference (EditAtMouse, true);
674 _playlist_selector = new PlaylistSelector();
675 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
677 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
681 nudge_forward_button.set_name ("nudge button");
682 nudge_forward_button.set_image(::get_icon("nudge_right"));
684 nudge_backward_button.set_name ("nudge button");
685 nudge_backward_button.set_image(::get_icon("nudge_left"));
687 fade_context_menu.set_name ("ArdourContextMenu");
689 /* icons, titles, WM stuff */
691 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
692 Glib::RefPtr<Gdk::Pixbuf> icon;
694 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
695 window_icons.push_back (icon);
697 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
698 window_icons.push_back (icon);
700 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
701 window_icons.push_back (icon);
703 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
704 window_icons.push_back (icon);
706 if (!window_icons.empty()) {
707 // set_icon_list (window_icons);
708 set_default_icon_list (window_icons);
711 WindowTitle title(Glib::get_application_name());
712 title += _("Editor");
713 set_title (title.get_string());
714 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
717 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
719 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
720 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
722 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
724 /* allow external control surfaces/protocols to do various things */
726 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
727 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
728 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
729 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
730 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
731 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
732 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
733 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
734 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
735 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
736 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
737 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
738 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
739 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
741 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
742 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
743 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
744 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
745 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
747 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
749 /* problematic: has to return a value and thus cannot be x-thread */
751 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
753 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
754 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
756 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
758 _ignore_region_action = false;
759 _last_region_menu_was_main = false;
760 _popup_region_menu_item = 0;
762 _ignore_follow_edits = false;
764 _show_marker_lines = false;
766 /* Button bindings */
768 button_bindings = new Bindings;
770 XMLNode* node = button_settings();
772 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
773 button_bindings->load (**i);
779 /* grab current parameter state */
780 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
781 ARDOUR_UI::config()->map_parameters (pc);
783 setup_fade_images ();
790 delete button_bindings;
792 delete _route_groups;
793 delete _track_canvas_viewport;
799 Editor::button_settings () const
801 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
802 XMLNode* node = find_named_node (*settings, X_("Buttons"));
805 node = new XMLNode (X_("Buttons"));
812 Editor::add_toplevel_menu (Container& cont)
814 vpacker.pack_start (cont, false, false);
819 Editor::add_transport_frame (Container& cont)
821 if(ARDOUR::Profile->get_mixbus()) {
822 global_vpacker.pack_start (cont, false, false);
823 global_vpacker.reorder_child (cont, 0);
826 vpacker.pack_start (cont, false, false);
831 Editor::get_smart_mode () const
833 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
837 Editor::catch_vanishing_regionview (RegionView *rv)
839 /* note: the selection will take care of the vanishing
840 audioregionview by itself.
843 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
847 if (clicked_regionview == rv) {
848 clicked_regionview = 0;
851 if (entered_regionview == rv) {
852 set_entered_regionview (0);
855 if (!_all_region_actions_sensitized) {
856 sensitize_all_region_actions (true);
861 Editor::set_entered_regionview (RegionView* rv)
863 if (rv == entered_regionview) {
867 if (entered_regionview) {
868 entered_regionview->exited ();
871 entered_regionview = rv;
873 if (entered_regionview != 0) {
874 entered_regionview->entered ();
877 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
878 /* This RegionView entry might have changed what region actions
879 are allowed, so sensitize them all in case a key is pressed.
881 sensitize_all_region_actions (true);
886 Editor::set_entered_track (TimeAxisView* tav)
889 entered_track->exited ();
895 entered_track->entered ();
900 Editor::show_window ()
902 if (!is_visible ()) {
906 /* XXX: this is a bit unfortunate; it would probably
907 be nicer if we could just call show () above rather
908 than needing the show_all ()
911 /* re-hide stuff if necessary */
912 editor_list_button_toggled ();
913 parameter_changed ("show-summary");
914 parameter_changed ("show-group-tabs");
915 parameter_changed ("show-zoom-tools");
917 /* now reset all audio_time_axis heights, because widgets might need
923 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
924 tv = (static_cast<TimeAxisView*>(*i));
928 if (current_mixer_strip) {
929 current_mixer_strip->hide_things ();
930 current_mixer_strip->parameter_changed ("mixer-element-visibility");
938 Editor::instant_save ()
940 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
945 _session->add_instant_xml(get_state());
947 Config->add_instant_xml(get_state());
952 Editor::control_vertical_zoom_in_all ()
954 tav_zoom_smooth (false, true);
958 Editor::control_vertical_zoom_out_all ()
960 tav_zoom_smooth (true, true);
964 Editor::control_vertical_zoom_in_selected ()
966 tav_zoom_smooth (false, false);
970 Editor::control_vertical_zoom_out_selected ()
972 tav_zoom_smooth (true, false);
976 Editor::control_view (uint32_t view)
978 goto_visual_state (view);
982 Editor::control_unselect ()
984 selection->clear_tracks ();
988 Editor::control_select (uint32_t rid, Selection::Operation op)
990 /* handles the (static) signal from the ControlProtocol class that
991 * requests setting the selected track to a given RID
998 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1004 TimeAxisView* tav = axis_view_from_route (r);
1008 case Selection::Add:
1009 selection->add (tav);
1011 case Selection::Toggle:
1012 selection->toggle (tav);
1014 case Selection::Extend:
1016 case Selection::Set:
1017 selection->set (tav);
1021 selection->clear_tracks ();
1026 Editor::control_step_tracks_up ()
1028 scroll_tracks_up_line ();
1032 Editor::control_step_tracks_down ()
1034 scroll_tracks_down_line ();
1038 Editor::control_scroll (float fraction)
1040 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1046 double step = fraction * current_page_samples();
1049 _control_scroll_target is an optional<T>
1051 it acts like a pointer to an framepos_t, with
1052 a operator conversion to boolean to check
1053 that it has a value could possibly use
1054 playhead_cursor->current_frame to store the
1055 value and a boolean in the class to know
1056 when it's out of date
1059 if (!_control_scroll_target) {
1060 _control_scroll_target = _session->transport_frame();
1061 _dragging_playhead = true;
1064 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1065 *_control_scroll_target = 0;
1066 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1067 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1069 *_control_scroll_target += (framepos_t) trunc (step);
1072 /* move visuals, we'll catch up with it later */
1074 playhead_cursor->set_position (*_control_scroll_target);
1075 UpdateAllTransportClocks (*_control_scroll_target);
1077 if (*_control_scroll_target > (current_page_samples() / 2)) {
1078 /* try to center PH in window */
1079 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1085 Now we do a timeout to actually bring the session to the right place
1086 according to the playhead. This is to avoid reading disk buffers on every
1087 call to control_scroll, which is driven by ScrollTimeline and therefore
1088 probably by a control surface wheel which can generate lots of events.
1090 /* cancel the existing timeout */
1092 control_scroll_connection.disconnect ();
1094 /* add the next timeout */
1096 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1100 Editor::deferred_control_scroll (framepos_t /*target*/)
1102 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1103 // reset for next stream
1104 _control_scroll_target = boost::none;
1105 _dragging_playhead = false;
1110 Editor::access_action (std::string action_group, std::string action_item)
1116 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1119 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1127 Editor::on_realize ()
1129 Window::on_realize ();
1132 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1133 start_lock_event_timing ();
1136 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1140 Editor::start_lock_event_timing ()
1142 /* check if we should lock the GUI every 30 seconds */
1144 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1148 Editor::generic_event_handler (GdkEvent* ev)
1151 case GDK_BUTTON_PRESS:
1152 case GDK_BUTTON_RELEASE:
1153 case GDK_MOTION_NOTIFY:
1155 case GDK_KEY_RELEASE:
1156 gettimeofday (&last_event_time, 0);
1159 case GDK_LEAVE_NOTIFY:
1160 switch (ev->crossing.detail) {
1161 case GDK_NOTIFY_UNKNOWN:
1162 case GDK_NOTIFY_INFERIOR:
1163 case GDK_NOTIFY_ANCESTOR:
1165 case GDK_NOTIFY_VIRTUAL:
1166 case GDK_NOTIFY_NONLINEAR:
1167 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1168 /* leaving window, so reset focus, thus ending any and
1169 all text entry operations.
1184 Editor::lock_timeout_callback ()
1186 struct timeval now, delta;
1188 gettimeofday (&now, 0);
1190 timersub (&now, &last_event_time, &delta);
1192 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1194 /* don't call again. Returning false will effectively
1195 disconnect us from the timer callback.
1197 unlock() will call start_lock_event_timing() to get things
1207 Editor::map_position_change (framepos_t frame)
1209 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1211 if (_session == 0) {
1215 if (_follow_playhead) {
1216 center_screen (frame);
1219 playhead_cursor->set_position (frame);
1223 Editor::center_screen (framepos_t frame)
1225 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1227 /* if we're off the page, then scroll.
1230 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1231 center_screen_internal (frame, page);
1236 Editor::center_screen_internal (framepos_t frame, float page)
1241 frame -= (framepos_t) page;
1246 reset_x_origin (frame);
1251 Editor::update_title ()
1253 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1256 bool dirty = _session->dirty();
1258 string session_name;
1260 if (_session->snap_name() != _session->name()) {
1261 session_name = _session->snap_name();
1263 session_name = _session->name();
1267 session_name = "*" + session_name;
1270 WindowTitle title(session_name);
1271 title += Glib::get_application_name();
1272 set_title (title.get_string());
1274 /* ::session_going_away() will have taken care of it */
1279 Editor::set_session (Session *t)
1281 SessionHandlePtr::set_session (t);
1287 _playlist_selector->set_session (_session);
1288 nudge_clock->set_session (_session);
1289 _summary->set_session (_session);
1290 _group_tabs->set_session (_session);
1291 _route_groups->set_session (_session);
1292 _regions->set_session (_session);
1293 _snapshots->set_session (_session);
1294 _routes->set_session (_session);
1295 _locations->set_session (_session);
1297 if (rhythm_ferret) {
1298 rhythm_ferret->set_session (_session);
1301 if (analysis_window) {
1302 analysis_window->set_session (_session);
1306 sfbrowser->set_session (_session);
1309 compute_fixed_ruler_scale ();
1311 /* Make sure we have auto loop and auto punch ranges */
1313 Location* loc = _session->locations()->auto_loop_location();
1315 loc->set_name (_("Loop"));
1318 loc = _session->locations()->auto_punch_location();
1321 loc->set_name (_("Punch"));
1324 refresh_location_display ();
1326 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1327 the selected Marker; this needs the LocationMarker list to be available.
1329 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1330 set_state (*node, Stateful::loading_state_version);
1332 /* catch up with the playhead */
1334 _session->request_locate (playhead_cursor->current_frame ());
1335 _pending_initial_locate = true;
1339 /* These signals can all be emitted by a non-GUI thread. Therefore the
1340 handlers for them must not attempt to directly interact with the GUI,
1341 but use PBD::Signal<T>::connect() which accepts an event loop
1342 ("context") where the handler will be asked to run.
1345 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1346 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1347 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1348 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1349 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1350 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1351 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1352 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1353 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1354 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1355 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1356 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1357 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1359 playhead_cursor->show ();
1361 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1362 Config->map_parameters (pc);
1363 _session->config.map_parameters (pc);
1365 restore_ruler_visibility ();
1366 //tempo_map_changed (PropertyChange (0));
1367 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1369 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1370 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1373 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1374 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1377 switch (_snap_type) {
1378 case SnapToRegionStart:
1379 case SnapToRegionEnd:
1380 case SnapToRegionSync:
1381 case SnapToRegionBoundary:
1382 build_region_boundary_cache ();
1389 /* register for undo history */
1390 _session->register_with_memento_command_factory(id(), this);
1391 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1393 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1395 start_updating_meters ();
1399 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1401 if (a->get_name() == "RegionMenu") {
1402 /* When the main menu's region menu is opened, we setup the actions so that they look right
1403 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1404 so we resensitize all region actions when the entered regionview or the region selection
1405 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1406 happens after the region context menu is opened. So we set a flag here, too.
1410 sensitize_the_right_region_actions ();
1411 _last_region_menu_was_main = true;
1416 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1418 using namespace Menu_Helpers;
1420 void (Editor::*emf)(FadeShape);
1421 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1424 images = &_xfade_in_images;
1425 emf = &Editor::set_fade_in_shape;
1427 images = &_xfade_out_images;
1428 emf = &Editor::set_fade_out_shape;
1433 _("Linear (for highly correlated material)"),
1434 *(*images)[FadeLinear],
1435 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1439 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1443 _("Constant power"),
1444 *(*images)[FadeConstantPower],
1445 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1448 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1453 *(*images)[FadeSymmetric],
1454 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1458 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1463 *(*images)[FadeSlow],
1464 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1467 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1472 *(*images)[FadeFast],
1473 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1476 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 /** Pop up a context menu for when the user clicks on a start crossfade */
1481 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1483 using namespace Menu_Helpers;
1484 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1489 MenuList& items (xfade_in_context_menu.items());
1492 if (arv->audio_region()->fade_in_active()) {
1493 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1495 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1498 items.push_back (SeparatorElem());
1499 fill_xfade_menu (items, true);
1501 xfade_in_context_menu.popup (button, time);
1504 /** Pop up a context menu for when the user clicks on an end crossfade */
1506 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1508 using namespace Menu_Helpers;
1509 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1514 MenuList& items (xfade_out_context_menu.items());
1517 if (arv->audio_region()->fade_out_active()) {
1518 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1520 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1523 items.push_back (SeparatorElem());
1524 fill_xfade_menu (items, false);
1526 xfade_out_context_menu.popup (button, time);
1530 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1532 using namespace Menu_Helpers;
1533 Menu* (Editor::*build_menu_function)();
1536 switch (item_type) {
1538 case RegionViewName:
1539 case RegionViewNameHighlight:
1540 case LeftFrameHandle:
1541 case RightFrameHandle:
1542 if (with_selection) {
1543 build_menu_function = &Editor::build_track_selection_context_menu;
1545 build_menu_function = &Editor::build_track_region_context_menu;
1550 if (with_selection) {
1551 build_menu_function = &Editor::build_track_selection_context_menu;
1553 build_menu_function = &Editor::build_track_context_menu;
1558 if (clicked_routeview->track()) {
1559 build_menu_function = &Editor::build_track_context_menu;
1561 build_menu_function = &Editor::build_track_bus_context_menu;
1566 /* probably shouldn't happen but if it does, we don't care */
1570 menu = (this->*build_menu_function)();
1571 menu->set_name ("ArdourContextMenu");
1573 /* now handle specific situations */
1575 switch (item_type) {
1577 case RegionViewName:
1578 case RegionViewNameHighlight:
1579 case LeftFrameHandle:
1580 case RightFrameHandle:
1581 if (!with_selection) {
1582 if (region_edit_menu_split_item) {
1583 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1584 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1586 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1589 if (region_edit_menu_split_multichannel_item) {
1590 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1591 region_edit_menu_split_multichannel_item->set_sensitive (true);
1593 region_edit_menu_split_multichannel_item->set_sensitive (false);
1606 /* probably shouldn't happen but if it does, we don't care */
1610 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1612 /* Bounce to disk */
1614 using namespace Menu_Helpers;
1615 MenuList& edit_items = menu->items();
1617 edit_items.push_back (SeparatorElem());
1619 switch (clicked_routeview->audio_track()->freeze_state()) {
1620 case AudioTrack::NoFreeze:
1621 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1624 case AudioTrack::Frozen:
1625 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1628 case AudioTrack::UnFrozen:
1629 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1635 if (item_type == StreamItem && clicked_routeview) {
1636 clicked_routeview->build_underlay_menu(menu);
1639 /* When the region menu is opened, we setup the actions so that they look right
1642 sensitize_the_right_region_actions ();
1643 _last_region_menu_was_main = false;
1645 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1646 menu->popup (button, time);
1650 Editor::build_track_context_menu ()
1652 using namespace Menu_Helpers;
1654 MenuList& edit_items = track_context_menu.items();
1657 add_dstream_context_items (edit_items);
1658 return &track_context_menu;
1662 Editor::build_track_bus_context_menu ()
1664 using namespace Menu_Helpers;
1666 MenuList& edit_items = track_context_menu.items();
1669 add_bus_context_items (edit_items);
1670 return &track_context_menu;
1674 Editor::build_track_region_context_menu ()
1676 using namespace Menu_Helpers;
1677 MenuList& edit_items = track_region_context_menu.items();
1680 /* we've just cleared the track region context menu, so the menu that these
1681 two items were on will have disappeared; stop them dangling.
1683 region_edit_menu_split_item = 0;
1684 region_edit_menu_split_multichannel_item = 0;
1686 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1689 boost::shared_ptr<Track> tr;
1690 boost::shared_ptr<Playlist> pl;
1692 if ((tr = rtv->track())) {
1693 add_region_context_items (edit_items, tr);
1697 add_dstream_context_items (edit_items);
1699 return &track_region_context_menu;
1703 Editor::analyze_region_selection ()
1705 if (analysis_window == 0) {
1706 analysis_window = new AnalysisWindow();
1709 analysis_window->set_session(_session);
1711 analysis_window->show_all();
1714 analysis_window->set_regionmode();
1715 analysis_window->analyze();
1717 analysis_window->present();
1721 Editor::analyze_range_selection()
1723 if (analysis_window == 0) {
1724 analysis_window = new AnalysisWindow();
1727 analysis_window->set_session(_session);
1729 analysis_window->show_all();
1732 analysis_window->set_rangemode();
1733 analysis_window->analyze();
1735 analysis_window->present();
1739 Editor::build_track_selection_context_menu ()
1741 using namespace Menu_Helpers;
1742 MenuList& edit_items = track_selection_context_menu.items();
1743 edit_items.clear ();
1745 add_selection_context_items (edit_items);
1746 // edit_items.push_back (SeparatorElem());
1747 // add_dstream_context_items (edit_items);
1749 return &track_selection_context_menu;
1753 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1755 using namespace Menu_Helpers;
1757 /* OK, stick the region submenu at the top of the list, and then add
1761 RegionSelection rs = get_regions_from_selection_and_entered ();
1763 string::size_type pos = 0;
1764 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1766 /* we have to hack up the region name because "_" has a special
1767 meaning for menu titles.
1770 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1771 menu_item_name.replace (pos, 1, "__");
1775 if (_popup_region_menu_item == 0) {
1776 _popup_region_menu_item = new MenuItem (menu_item_name);
1777 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1778 _popup_region_menu_item->show ();
1780 _popup_region_menu_item->set_label (menu_item_name);
1783 const framepos_t position = get_preferred_edit_position (false, true);
1785 edit_items.push_back (*_popup_region_menu_item);
1786 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1787 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1789 edit_items.push_back (SeparatorElem());
1792 /** Add context menu items relevant to selection ranges.
1793 * @param edit_items List to add the items to.
1796 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1798 using namespace Menu_Helpers;
1800 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1801 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1803 edit_items.push_back (SeparatorElem());
1804 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1806 edit_items.push_back (SeparatorElem());
1807 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1809 edit_items.push_back (SeparatorElem());
1811 edit_items.push_back (
1813 _("Move Range Start to Previous Region Boundary"),
1814 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1818 edit_items.push_back (
1820 _("Move Range Start to Next Region Boundary"),
1821 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1825 edit_items.push_back (
1827 _("Move Range End to Previous Region Boundary"),
1828 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1832 edit_items.push_back (
1834 _("Move Range End to Next Region Boundary"),
1835 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1839 edit_items.push_back (SeparatorElem());
1840 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1841 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1843 edit_items.push_back (SeparatorElem());
1844 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1846 edit_items.push_back (SeparatorElem());
1847 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1848 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1849 edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1851 edit_items.push_back (SeparatorElem());
1852 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1854 edit_items.push_back (SeparatorElem());
1855 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1856 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1857 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1859 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1861 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1862 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1863 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1864 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1865 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1866 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1872 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1874 using namespace Menu_Helpers;
1878 Menu *play_menu = manage (new Menu);
1879 MenuList& play_items = play_menu->items();
1880 play_menu->set_name ("ArdourContextMenu");
1882 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1883 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1884 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1885 play_items.push_back (SeparatorElem());
1886 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1888 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1892 Menu *select_menu = manage (new Menu);
1893 MenuList& select_items = select_menu->items();
1894 select_menu->set_name ("ArdourContextMenu");
1896 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1897 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1898 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1899 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1900 select_items.push_back (SeparatorElem());
1901 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1902 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1903 select_items.push_back (SeparatorElem());
1904 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1905 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1906 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1907 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1908 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1909 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1910 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1912 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1916 Menu *cutnpaste_menu = manage (new Menu);
1917 MenuList& cutnpaste_items = cutnpaste_menu->items();
1918 cutnpaste_menu->set_name ("ArdourContextMenu");
1920 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1921 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1922 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1924 cutnpaste_items.push_back (SeparatorElem());
1926 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1927 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1929 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1931 /* Adding new material */
1933 edit_items.push_back (SeparatorElem());
1934 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1935 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1939 Menu *nudge_menu = manage (new Menu());
1940 MenuList& nudge_items = nudge_menu->items();
1941 nudge_menu->set_name ("ArdourContextMenu");
1943 edit_items.push_back (SeparatorElem());
1944 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1945 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1946 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1947 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1949 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1953 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1955 using namespace Menu_Helpers;
1959 Menu *play_menu = manage (new Menu);
1960 MenuList& play_items = play_menu->items();
1961 play_menu->set_name ("ArdourContextMenu");
1963 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1964 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1965 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1969 Menu *select_menu = manage (new Menu);
1970 MenuList& select_items = select_menu->items();
1971 select_menu->set_name ("ArdourContextMenu");
1973 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1974 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1975 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1976 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1977 select_items.push_back (SeparatorElem());
1978 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1979 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1980 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1981 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1983 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1987 Menu *cutnpaste_menu = manage (new Menu);
1988 MenuList& cutnpaste_items = cutnpaste_menu->items();
1989 cutnpaste_menu->set_name ("ArdourContextMenu");
1991 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1992 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1993 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1995 Menu *nudge_menu = manage (new Menu());
1996 MenuList& nudge_items = nudge_menu->items();
1997 nudge_menu->set_name ("ArdourContextMenu");
1999 edit_items.push_back (SeparatorElem());
2000 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2001 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2002 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2003 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2005 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2009 Editor::snap_type() const
2015 Editor::snap_mode() const
2021 Editor::set_snap_to (SnapType st)
2023 unsigned int snap_ind = (unsigned int)st;
2027 if (snap_ind > snap_type_strings.size() - 1) {
2029 _snap_type = (SnapType)snap_ind;
2032 string str = snap_type_strings[snap_ind];
2034 if (str != snap_type_selector.get_text()) {
2035 snap_type_selector.set_text (str);
2040 switch (_snap_type) {
2041 case SnapToBeatDiv128:
2042 case SnapToBeatDiv64:
2043 case SnapToBeatDiv32:
2044 case SnapToBeatDiv28:
2045 case SnapToBeatDiv24:
2046 case SnapToBeatDiv20:
2047 case SnapToBeatDiv16:
2048 case SnapToBeatDiv14:
2049 case SnapToBeatDiv12:
2050 case SnapToBeatDiv10:
2051 case SnapToBeatDiv8:
2052 case SnapToBeatDiv7:
2053 case SnapToBeatDiv6:
2054 case SnapToBeatDiv5:
2055 case SnapToBeatDiv4:
2056 case SnapToBeatDiv3:
2057 case SnapToBeatDiv2: {
2058 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2059 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2061 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2062 current_bbt_points_begin, current_bbt_points_end);
2063 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2064 current_bbt_points_begin, current_bbt_points_end);
2065 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2069 case SnapToRegionStart:
2070 case SnapToRegionEnd:
2071 case SnapToRegionSync:
2072 case SnapToRegionBoundary:
2073 build_region_boundary_cache ();
2081 SnapChanged (); /* EMIT SIGNAL */
2085 Editor::set_snap_mode (SnapMode mode)
2087 string str = snap_mode_strings[(int)mode];
2091 if (str != snap_mode_selector.get_text ()) {
2092 snap_mode_selector.set_text (str);
2098 Editor::set_edit_point_preference (EditPoint ep, bool force)
2100 bool changed = (_edit_point != ep);
2103 if (Profile->get_mixbus())
2104 if (ep == EditAtSelectedMarker)
2105 ep = EditAtPlayhead;
2107 string str = edit_point_strings[(int)ep];
2108 if (str != edit_point_selector.get_text ()) {
2109 edit_point_selector.set_text (str);
2112 reset_canvas_cursor ();
2114 if (!force && !changed) {
2118 const char* action=NULL;
2120 switch (_edit_point) {
2121 case EditAtPlayhead:
2122 action = "edit-at-playhead";
2124 case EditAtSelectedMarker:
2125 action = "edit-at-marker";
2128 action = "edit-at-mouse";
2132 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2134 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2138 bool in_track_canvas;
2140 if (!mouse_frame (foo, in_track_canvas)) {
2141 in_track_canvas = false;
2144 reset_canvas_action_sensitivity (in_track_canvas);
2150 Editor::set_state (const XMLNode& node, int /*version*/)
2152 const XMLProperty* prop;
2159 g.base_width = default_width;
2160 g.base_height = default_height;
2164 if ((geometry = find_named_node (node, "geometry")) != 0) {
2168 if ((prop = geometry->property("x_size")) == 0) {
2169 prop = geometry->property ("x-size");
2172 g.base_width = atoi(prop->value());
2174 if ((prop = geometry->property("y_size")) == 0) {
2175 prop = geometry->property ("y-size");
2178 g.base_height = atoi(prop->value());
2181 if ((prop = geometry->property ("x_pos")) == 0) {
2182 prop = geometry->property ("x-pos");
2185 x = atoi (prop->value());
2188 if ((prop = geometry->property ("y_pos")) == 0) {
2189 prop = geometry->property ("y-pos");
2192 y = atoi (prop->value());
2196 set_default_size (g.base_width, g.base_height);
2199 if (_session && (prop = node.property ("playhead"))) {
2201 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2203 playhead_cursor->set_position (pos);
2205 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2206 playhead_cursor->set_position (0);
2209 playhead_cursor->set_position (0);
2212 if ((prop = node.property ("mixer-width"))) {
2213 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2216 if ((prop = node.property ("zoom-focus"))) {
2217 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2220 if ((prop = node.property ("zoom"))) {
2221 /* older versions of ardour used floating point samples_per_pixel */
2222 double f = PBD::atof (prop->value());
2223 reset_zoom (llrintf (f));
2225 reset_zoom (samples_per_pixel);
2228 if ((prop = node.property ("visible-track-count"))) {
2229 set_visible_track_count (PBD::atoi (prop->value()));
2232 if ((prop = node.property ("snap-to"))) {
2233 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2236 if ((prop = node.property ("snap-mode"))) {
2237 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2240 if ((prop = node.property ("mouse-mode"))) {
2241 MouseMode m = str2mousemode(prop->value());
2242 set_mouse_mode (m, true);
2244 set_mouse_mode (MouseObject, true);
2247 if ((prop = node.property ("left-frame")) != 0) {
2249 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2253 reset_x_origin (pos);
2257 if ((prop = node.property ("y-origin")) != 0) {
2258 reset_y_origin (atof (prop->value ()));
2261 if ((prop = node.property ("join-object-range"))) {
2262 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2263 bool yn = string_is_affirmative (prop->value());
2265 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2266 tact->set_active (!yn);
2267 tact->set_active (yn);
2269 set_mouse_mode(mouse_mode, true);
2272 if ((prop = node.property ("edit-point"))) {
2273 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2276 if ((prop = node.property ("show-measures"))) {
2277 bool yn = string_is_affirmative (prop->value());
2278 _show_measures = yn;
2279 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2281 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2282 /* do it twice to force the change */
2283 tact->set_active (!yn);
2284 tact->set_active (yn);
2288 if ((prop = node.property ("follow-playhead"))) {
2289 bool yn = string_is_affirmative (prop->value());
2290 set_follow_playhead (yn);
2291 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2293 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2294 if (tact->get_active() != yn) {
2295 tact->set_active (yn);
2300 if ((prop = node.property ("stationary-playhead"))) {
2301 bool yn = string_is_affirmative (prop->value());
2302 set_stationary_playhead (yn);
2303 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2305 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2306 if (tact->get_active() != yn) {
2307 tact->set_active (yn);
2312 if ((prop = node.property ("region-list-sort-type"))) {
2313 RegionListSortType st;
2314 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2317 if ((prop = node.property ("show-editor-mixer"))) {
2319 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2322 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2323 bool yn = string_is_affirmative (prop->value());
2325 /* do it twice to force the change */
2327 tact->set_active (!yn);
2328 tact->set_active (yn);
2331 if ((prop = node.property ("show-editor-list"))) {
2333 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2336 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2337 bool yn = string_is_affirmative (prop->value());
2339 /* do it twice to force the change */
2341 tact->set_active (!yn);
2342 tact->set_active (yn);
2345 if ((prop = node.property (X_("editor-list-page")))) {
2346 _the_notebook.set_current_page (atoi (prop->value ()));
2349 if ((prop = node.property (X_("show-marker-lines")))) {
2350 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2352 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2353 bool yn = string_is_affirmative (prop->value ());
2355 tact->set_active (!yn);
2356 tact->set_active (yn);
2359 XMLNodeList children = node.children ();
2360 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2361 selection->set_state (**i, Stateful::current_state_version);
2362 _regions->set_state (**i);
2365 if ((prop = node.property ("maximised"))) {
2366 bool yn = string_is_affirmative (prop->value());
2367 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2369 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2370 bool fs = tact && tact->get_active();
2372 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2376 if ((prop = node.property ("nudge-clock-value"))) {
2378 sscanf (prop->value().c_str(), "%" PRId64, &f);
2379 nudge_clock->set (f);
2381 nudge_clock->set_mode (AudioClock::Timecode);
2382 nudge_clock->set (_session->frame_rate() * 5, true);
2389 Editor::get_state ()
2391 XMLNode* node = new XMLNode ("Editor");
2394 id().print (buf, sizeof (buf));
2395 node->add_property ("id", buf);
2397 if (is_realized()) {
2398 Glib::RefPtr<Gdk::Window> win = get_window();
2400 int x, y, width, height;
2401 win->get_root_origin(x, y);
2402 win->get_size(width, height);
2404 XMLNode* geometry = new XMLNode ("geometry");
2406 snprintf(buf, sizeof(buf), "%d", width);
2407 geometry->add_property("x-size", string(buf));
2408 snprintf(buf, sizeof(buf), "%d", height);
2409 geometry->add_property("y-size", string(buf));
2410 snprintf(buf, sizeof(buf), "%d", x);
2411 geometry->add_property("x-pos", string(buf));
2412 snprintf(buf, sizeof(buf), "%d", y);
2413 geometry->add_property("y-pos", string(buf));
2414 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2415 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2416 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2417 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2418 geometry->add_property("edit-vertical-pane-pos", string(buf));
2420 node->add_child_nocopy (*geometry);
2423 maybe_add_mixer_strip_width (*node);
2425 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2427 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2428 node->add_property ("zoom", buf);
2429 node->add_property ("snap-to", enum_2_string (_snap_type));
2430 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2431 node->add_property ("edit-point", enum_2_string (_edit_point));
2432 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2433 node->add_property ("visible-track-count", buf);
2435 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2436 node->add_property ("playhead", buf);
2437 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2438 node->add_property ("left-frame", buf);
2439 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2440 node->add_property ("y-origin", buf);
2442 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2443 node->add_property ("maximised", _maximised ? "yes" : "no");
2444 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2445 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2446 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2447 node->add_property ("mouse-mode", enum2str(mouse_mode));
2448 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2450 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2452 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2453 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2456 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2458 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2459 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2462 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2463 node->add_property (X_("editor-list-page"), buf);
2465 if (button_bindings) {
2466 XMLNode* bb = new XMLNode (X_("Buttons"));
2467 button_bindings->save (*bb);
2468 node->add_child_nocopy (*bb);
2471 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2473 node->add_child_nocopy (selection->get_state ());
2474 node->add_child_nocopy (_regions->get_state ());
2476 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2477 node->add_property ("nudge-clock-value", buf);
2482 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2483 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2485 * @return pair: TimeAxisView that y is over, layer index.
2487 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2488 * in stacked or expanded region display mode, otherwise 0.
2490 std::pair<TimeAxisView *, double>
2491 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2493 if (!trackview_relative_offset) {
2494 y -= _trackview_group->canvas_origin().y;
2498 return std::make_pair ( (TimeAxisView *) 0, 0);
2501 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2503 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2510 return std::make_pair ( (TimeAxisView *) 0, 0);
2513 /** Snap a position to the grid, if appropriate, taking into account current
2514 * grid settings and also the state of any snap modifier keys that may be pressed.
2515 * @param start Position to snap.
2516 * @param event Event to get current key modifier information from, or 0.
2519 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2521 if (!_session || !event) {
2525 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2526 if (_snap_mode == SnapOff) {
2527 snap_to_internal (start, direction, for_mark);
2530 if (_snap_mode != SnapOff) {
2531 snap_to_internal (start, direction, for_mark);
2537 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2539 if (!_session || _snap_mode == SnapOff) {
2543 snap_to_internal (start, direction, for_mark);
2547 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2549 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2550 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2552 switch (_snap_type) {
2553 case SnapToTimecodeFrame:
2554 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2555 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2556 /* start is already on a whole timecode frame, do nothing */
2557 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2558 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2560 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2564 case SnapToTimecodeSeconds:
2565 if (_session->config.get_timecode_offset_negative()) {
2566 start += _session->config.get_timecode_offset ();
2568 start -= _session->config.get_timecode_offset ();
2570 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2571 (start % one_timecode_second == 0)) {
2572 /* start is already on a whole second, do nothing */
2573 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2574 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2576 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2579 if (_session->config.get_timecode_offset_negative()) {
2580 start -= _session->config.get_timecode_offset ();
2582 start += _session->config.get_timecode_offset ();
2586 case SnapToTimecodeMinutes:
2587 if (_session->config.get_timecode_offset_negative()) {
2588 start += _session->config.get_timecode_offset ();
2590 start -= _session->config.get_timecode_offset ();
2592 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2593 (start % one_timecode_minute == 0)) {
2594 /* start is already on a whole minute, do nothing */
2595 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2596 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2598 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2600 if (_session->config.get_timecode_offset_negative()) {
2601 start -= _session->config.get_timecode_offset ();
2603 start += _session->config.get_timecode_offset ();
2607 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2608 abort(); /*NOTREACHED*/
2613 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2615 const framepos_t one_second = _session->frame_rate();
2616 const framepos_t one_minute = _session->frame_rate() * 60;
2617 framepos_t presnap = start;
2621 switch (_snap_type) {
2622 case SnapToTimecodeFrame:
2623 case SnapToTimecodeSeconds:
2624 case SnapToTimecodeMinutes:
2625 return timecode_snap_to_internal (start, direction, for_mark);
2628 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2629 start % (one_second/75) == 0) {
2630 /* start is already on a whole CD frame, do nothing */
2631 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2632 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2634 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2639 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2640 start % one_second == 0) {
2641 /* start is already on a whole second, do nothing */
2642 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2643 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2645 start = (framepos_t) floor ((double) start / one_second) * one_second;
2650 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2651 start % one_minute == 0) {
2652 /* start is already on a whole minute, do nothing */
2653 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2654 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2656 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2661 start = _session->tempo_map().round_to_bar (start, direction);
2665 start = _session->tempo_map().round_to_beat (start, direction);
2668 case SnapToBeatDiv128:
2669 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2671 case SnapToBeatDiv64:
2672 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2674 case SnapToBeatDiv32:
2675 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2677 case SnapToBeatDiv28:
2678 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2680 case SnapToBeatDiv24:
2681 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2683 case SnapToBeatDiv20:
2684 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2686 case SnapToBeatDiv16:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2689 case SnapToBeatDiv14:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2692 case SnapToBeatDiv12:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2695 case SnapToBeatDiv10:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2698 case SnapToBeatDiv8:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2701 case SnapToBeatDiv7:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2704 case SnapToBeatDiv6:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2707 case SnapToBeatDiv5:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2710 case SnapToBeatDiv4:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2713 case SnapToBeatDiv3:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2716 case SnapToBeatDiv2:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2725 _session->locations()->marks_either_side (start, before, after);
2727 if (before == max_framepos && after == max_framepos) {
2728 /* No marks to snap to, so just don't snap */
2730 } else if (before == max_framepos) {
2732 } else if (after == max_framepos) {
2734 } else if (before != max_framepos && after != max_framepos) {
2735 /* have before and after */
2736 if ((start - before) < (after - start)) {
2745 case SnapToRegionStart:
2746 case SnapToRegionEnd:
2747 case SnapToRegionSync:
2748 case SnapToRegionBoundary:
2749 if (!region_boundary_cache.empty()) {
2751 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2752 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2754 if (direction > 0) {
2755 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2757 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2760 if (next != region_boundary_cache.begin ()) {
2765 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2766 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2768 if (start > (p + n) / 2) {
2777 switch (_snap_mode) {
2783 if (presnap > start) {
2784 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2788 } else if (presnap < start) {
2789 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2795 /* handled at entry */
2803 Editor::setup_toolbar ()
2805 HBox* mode_box = manage(new HBox);
2806 mode_box->set_border_width (2);
2807 mode_box->set_spacing(2);
2809 HBox* mouse_mode_box = manage (new HBox);
2810 HBox* mouse_mode_hbox = manage (new HBox);
2811 VBox* mouse_mode_vbox = manage (new VBox);
2812 Alignment* mouse_mode_align = manage (new Alignment);
2814 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2815 mouse_mode_size_group->add_widget (smart_mode_button);
2816 mouse_mode_size_group->add_widget (mouse_move_button);
2817 mouse_mode_size_group->add_widget (mouse_cut_button);
2818 mouse_mode_size_group->add_widget (mouse_select_button);
2819 mouse_mode_size_group->add_widget (mouse_timefx_button);
2820 mouse_mode_size_group->add_widget (mouse_audition_button);
2821 mouse_mode_size_group->add_widget (mouse_draw_button);
2822 mouse_mode_size_group->add_widget (mouse_content_button);
2824 mouse_mode_size_group->add_widget (zoom_in_button);
2825 mouse_mode_size_group->add_widget (zoom_out_button);
2826 mouse_mode_size_group->add_widget (zoom_preset_selector);
2827 mouse_mode_size_group->add_widget (zoom_out_full_button);
2828 mouse_mode_size_group->add_widget (zoom_focus_selector);
2830 mouse_mode_size_group->add_widget (tav_shrink_button);
2831 mouse_mode_size_group->add_widget (tav_expand_button);
2832 mouse_mode_size_group->add_widget (visible_tracks_selector);
2834 mouse_mode_size_group->add_widget (snap_type_selector);
2835 mouse_mode_size_group->add_widget (snap_mode_selector);
2837 mouse_mode_size_group->add_widget (edit_point_selector);
2838 mouse_mode_size_group->add_widget (edit_mode_selector);
2840 mouse_mode_size_group->add_widget (*nudge_clock);
2841 mouse_mode_size_group->add_widget (nudge_forward_button);
2842 mouse_mode_size_group->add_widget (nudge_backward_button);
2844 mouse_mode_hbox->set_spacing (2);
2846 if (!ARDOUR::Profile->get_trx()) {
2847 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2850 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2851 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2853 if (!ARDOUR::Profile->get_mixbus()) {
2854 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2857 if (!ARDOUR::Profile->get_trx()) {
2858 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2859 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2860 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2861 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2864 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2866 mouse_mode_align->add (*mouse_mode_vbox);
2867 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2869 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2871 edit_mode_selector.set_name ("mouse mode button");
2873 if (!ARDOUR::Profile->get_trx()) {
2874 mode_box->pack_start (edit_mode_selector, false, false);
2876 mode_box->pack_start (*mouse_mode_box, false, false);
2878 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2879 _mouse_mode_tearoff->set_name ("MouseModeBase");
2880 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2882 if (Profile->get_sae() || Profile->get_mixbus() ) {
2883 _mouse_mode_tearoff->set_can_be_torn_off (false);
2886 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2887 &_mouse_mode_tearoff->tearoff_window()));
2888 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2889 &_mouse_mode_tearoff->tearoff_window(), 1));
2890 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2891 &_mouse_mode_tearoff->tearoff_window()));
2892 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2893 &_mouse_mode_tearoff->tearoff_window(), 1));
2897 _zoom_box.set_spacing (2);
2898 _zoom_box.set_border_width (2);
2902 zoom_preset_selector.set_name ("zoom button");
2903 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2904 zoom_preset_selector.set_size_request (42, -1);
2906 zoom_in_button.set_name ("zoom button");
2907 zoom_in_button.set_image(::get_icon ("zoom_in"));
2908 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2909 zoom_in_button.set_related_action (act);
2911 zoom_out_button.set_name ("zoom button");
2912 zoom_out_button.set_image(::get_icon ("zoom_out"));
2913 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2914 zoom_out_button.set_related_action (act);
2916 zoom_out_full_button.set_name ("zoom button");
2917 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2918 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2919 zoom_out_full_button.set_related_action (act);
2921 zoom_focus_selector.set_name ("zoom button");
2923 if (ARDOUR::Profile->get_mixbus()) {
2924 _zoom_box.pack_start (zoom_preset_selector, false, false);
2925 } else if (ARDOUR::Profile->get_trx()) {
2926 mode_box->pack_start (zoom_out_button, false, false);
2927 mode_box->pack_start (zoom_in_button, false, false);
2929 _zoom_box.pack_start (zoom_out_button, false, false);
2930 _zoom_box.pack_start (zoom_in_button, false, false);
2931 _zoom_box.pack_start (zoom_out_full_button, false, false);
2932 _zoom_box.pack_start (zoom_focus_selector, false, false);
2935 /* Track zoom buttons */
2936 visible_tracks_selector.set_name ("zoom button");
2937 if (Profile->get_mixbus()) {
2938 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2939 visible_tracks_selector.set_size_request (42, -1);
2941 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2944 tav_expand_button.set_name ("zoom button");
2945 tav_expand_button.set_image(::get_icon ("tav_exp"));
2946 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2947 tav_expand_button.set_related_action (act);
2949 tav_shrink_button.set_name ("zoom button");
2950 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2951 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2952 tav_shrink_button.set_related_action (act);
2954 if (ARDOUR::Profile->get_mixbus()) {
2955 _zoom_box.pack_start (visible_tracks_selector);
2956 } else if (ARDOUR::Profile->get_trx()) {
2957 _zoom_box.pack_start (tav_shrink_button);
2958 _zoom_box.pack_start (tav_expand_button);
2960 _zoom_box.pack_start (visible_tracks_selector);
2961 _zoom_box.pack_start (tav_shrink_button);
2962 _zoom_box.pack_start (tav_expand_button);
2965 if (!ARDOUR::Profile->get_trx()) {
2966 _zoom_tearoff = manage (new TearOff (_zoom_box));
2968 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2969 &_zoom_tearoff->tearoff_window()));
2970 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2971 &_zoom_tearoff->tearoff_window(), 0));
2972 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2973 &_zoom_tearoff->tearoff_window()));
2974 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2975 &_zoom_tearoff->tearoff_window(), 0));
2978 if (Profile->get_sae() || Profile->get_mixbus() ) {
2979 _zoom_tearoff->set_can_be_torn_off (false);
2982 snap_box.set_spacing (2);
2983 snap_box.set_border_width (2);
2985 snap_type_selector.set_name ("mouse mode button");
2987 snap_mode_selector.set_name ("mouse mode button");
2989 edit_point_selector.set_name ("mouse mode button");
2991 snap_box.pack_start (snap_mode_selector, false, false);
2992 snap_box.pack_start (snap_type_selector, false, false);
2993 snap_box.pack_start (edit_point_selector, false, false);
2997 HBox *nudge_box = manage (new HBox);
2998 nudge_box->set_spacing (2);
2999 nudge_box->set_border_width (2);
3001 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3002 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3004 nudge_box->pack_start (nudge_backward_button, false, false);
3005 nudge_box->pack_start (nudge_forward_button, false, false);
3006 nudge_box->pack_start (*nudge_clock, false, false);
3009 /* Pack everything in... */
3011 HBox* hbox = manage (new HBox);
3012 hbox->set_spacing(2);
3014 _tools_tearoff = manage (new TearOff (*hbox));
3015 _tools_tearoff->set_name ("MouseModeBase");
3016 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3018 if (Profile->get_sae() || Profile->get_mixbus()) {
3019 _tools_tearoff->set_can_be_torn_off (false);
3022 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3023 &_tools_tearoff->tearoff_window()));
3024 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3025 &_tools_tearoff->tearoff_window(), 0));
3026 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3027 &_tools_tearoff->tearoff_window()));
3028 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3029 &_tools_tearoff->tearoff_window(), 0));
3031 toolbar_hbox.set_spacing (2);
3032 toolbar_hbox.set_border_width (1);
3034 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3035 if (!ARDOUR::Profile->get_trx()) {
3036 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3037 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3040 if (!ARDOUR::Profile->get_trx()) {
3041 hbox->pack_start (snap_box, false, false);
3042 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3043 hbox->pack_start (*nudge_box, false, false);
3045 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3048 hbox->pack_start (panic_box, false, false);
3052 toolbar_base.set_name ("ToolBarBase");
3053 toolbar_base.add (toolbar_hbox);
3055 _toolbar_viewport.add (toolbar_base);
3056 /* stick to the required height but allow width to vary if there's not enough room */
3057 _toolbar_viewport.set_size_request (1, -1);
3059 toolbar_frame.set_shadow_type (SHADOW_OUT);
3060 toolbar_frame.set_name ("BaseFrame");
3061 toolbar_frame.add (_toolbar_viewport);
3065 Editor::build_edit_point_menu ()
3067 using namespace Menu_Helpers;
3069 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3070 if(!Profile->get_mixbus())
3071 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3072 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3074 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3078 Editor::build_edit_mode_menu ()
3080 using namespace Menu_Helpers;
3082 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3083 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3084 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3085 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3087 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3091 Editor::build_snap_mode_menu ()
3093 using namespace Menu_Helpers;
3095 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3096 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3097 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3099 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3103 Editor::build_snap_type_menu ()
3105 using namespace Menu_Helpers;
3107 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3108 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3109 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3110 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3111 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3112 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3113 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3114 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3115 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3116 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3117 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3118 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3119 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3120 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3121 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3122 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3123 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3124 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3125 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3126 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3133 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3134 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3135 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3136 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3138 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3143 Editor::setup_tooltips ()
3145 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3146 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3147 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3148 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3149 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3150 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3151 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3152 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Select/move contents (notes and automation)"));
3153 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3154 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3155 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3156 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3157 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3158 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3159 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3160 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3161 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3162 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3163 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3164 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3165 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3166 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3167 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3168 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3172 Editor::convert_drop_to_paths (
3173 vector<string>& paths,
3174 const RefPtr<Gdk::DragContext>& /*context*/,
3177 const SelectionData& data,
3181 if (_session == 0) {
3185 vector<string> uris = data.get_uris();
3189 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3190 are actually URI lists. So do it by hand.
3193 if (data.get_target() != "text/plain") {
3197 /* Parse the "uri-list" format that Nautilus provides,
3198 where each pathname is delimited by \r\n.
3200 THERE MAY BE NO NULL TERMINATING CHAR!!!
3203 string txt = data.get_text();
3207 p = (char *) malloc (txt.length() + 1);
3208 txt.copy (p, txt.length(), 0);
3209 p[txt.length()] = '\0';
3215 while (g_ascii_isspace (*p))
3219 while (*q && (*q != '\n') && (*q != '\r')) {
3226 while (q > p && g_ascii_isspace (*q))
3231 uris.push_back (string (p, q - p + 1));
3235 p = strchr (p, '\n');
3247 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3248 if ((*i).substr (0,7) == "file://") {
3249 paths.push_back (Glib::filename_from_uri (*i));
3257 Editor::new_tempo_section ()
3262 Editor::map_transport_state ()
3264 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3266 if (_session && _session->transport_stopped()) {
3267 have_pending_keyboard_selection = false;
3270 update_loop_range_view ();
3276 Editor::begin_reversible_command (string name)
3279 before.push_back (&_selection_memento->get_state ());
3280 _session->begin_reversible_command (name);
3285 Editor::begin_reversible_command (GQuark q)
3288 before.push_back (&_selection_memento->get_state ());
3289 _session->begin_reversible_command (q);
3294 Editor::commit_reversible_command ()
3297 if (before.size() == 1) {
3298 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3301 if (!before.empty()) {
3305 _session->commit_reversible_command ();
3310 Editor::history_changed ()
3314 if (undo_action && _session) {
3315 if (_session->undo_depth() == 0) {
3316 label = S_("Command|Undo");
3318 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3320 undo_action->property_label() = label;
3323 if (redo_action && _session) {
3324 if (_session->redo_depth() == 0) {
3327 label = string_compose(_("Redo (%1)"), _session->next_redo());
3329 redo_action->property_label() = label;
3334 Editor::duplicate_range (bool with_dialog)
3338 RegionSelection rs = get_regions_from_selection_and_entered ();
3340 if ( selection->time.length() == 0 && rs.empty()) {
3346 ArdourDialog win (_("Duplicate"));
3347 Label label (_("Number of duplications:"));
3348 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3349 SpinButton spinner (adjustment, 0.0, 1);
3352 win.get_vbox()->set_spacing (12);
3353 win.get_vbox()->pack_start (hbox);
3354 hbox.set_border_width (6);
3355 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3357 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3358 place, visually. so do this by hand.
3361 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3362 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3363 spinner.grab_focus();
3369 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3370 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3371 win.set_default_response (RESPONSE_ACCEPT);
3373 spinner.grab_focus ();
3375 switch (win.run ()) {
3376 case RESPONSE_ACCEPT:
3382 times = adjustment.get_value();
3385 if ((current_mouse_mode() == Editing::MouseRange)) {
3386 if (selection->time.length()) {
3387 duplicate_selection (times);
3389 } else if (get_smart_mode()) {
3390 if (selection->time.length()) {
3391 duplicate_selection (times);
3393 duplicate_some_regions (rs, times);
3395 duplicate_some_regions (rs, times);
3400 Editor::set_edit_mode (EditMode m)
3402 Config->set_edit_mode (m);
3406 Editor::cycle_edit_mode ()
3408 switch (Config->get_edit_mode()) {
3410 if (Profile->get_sae()) {
3411 Config->set_edit_mode (Lock);
3413 Config->set_edit_mode (Ripple);
3418 Config->set_edit_mode (Lock);
3421 Config->set_edit_mode (Slide);
3427 Editor::edit_mode_selection_done ( EditMode m )
3429 Config->set_edit_mode ( m );
3433 Editor::snap_type_selection_done (SnapType snaptype)
3435 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3437 ract->set_active ();
3442 Editor::snap_mode_selection_done (SnapMode mode)
3444 RefPtr<RadioAction> ract = snap_mode_action (mode);
3447 ract->set_active (true);
3452 Editor::cycle_edit_point (bool with_marker)
3454 if(Profile->get_mixbus())
3455 with_marker = false;
3457 switch (_edit_point) {
3459 set_edit_point_preference (EditAtPlayhead);
3461 case EditAtPlayhead:
3463 set_edit_point_preference (EditAtSelectedMarker);
3465 set_edit_point_preference (EditAtMouse);
3468 case EditAtSelectedMarker:
3469 set_edit_point_preference (EditAtMouse);
3475 Editor::edit_point_selection_done (EditPoint ep)
3477 set_edit_point_preference ( ep );
3481 Editor::build_zoom_focus_menu ()
3483 using namespace Menu_Helpers;
3485 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3486 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3487 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3488 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3489 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3490 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3492 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3496 Editor::zoom_focus_selection_done ( ZoomFocus f )
3498 RefPtr<RadioAction> ract = zoom_focus_action (f);
3500 ract->set_active ();
3505 Editor::build_track_count_menu ()
3507 using namespace Menu_Helpers;
3509 if (!Profile->get_mixbus()) {
3510 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3511 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3512 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3513 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3514 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3515 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3516 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3517 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3518 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3519 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3520 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3521 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3522 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3524 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3525 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3526 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3527 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3528 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3529 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3530 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3531 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3532 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3533 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3535 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3536 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3537 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3538 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3539 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3540 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3541 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3542 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3543 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3544 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3545 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3550 Editor::set_zoom_preset (int64_t ms)
3553 temporal_zoom_session();
3557 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3558 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3562 Editor::set_visible_track_count (int32_t n)
3564 _visible_track_count = n;
3566 /* if the canvas hasn't really been allocated any size yet, just
3567 record the desired number of visible tracks and return. when canvas
3568 allocation happens, we will get called again and then we can do the
3572 if (_visible_canvas_height <= 1) {
3579 if (_visible_track_count > 0) {
3580 h = trackviews_height() / _visible_track_count;
3581 std::ostringstream s;
3582 s << _visible_track_count;
3584 } else if (_visible_track_count == 0) {
3586 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3587 if ((*i)->marked_for_display()) {
3591 h = trackviews_height() / n;
3594 /* negative value means that the visible track count has
3595 been overridden by explicit track height changes.
3597 visible_tracks_selector.set_text (X_("*"));
3601 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3602 (*i)->set_height (h);
3605 if (str != visible_tracks_selector.get_text()) {
3606 visible_tracks_selector.set_text (str);
3611 Editor::override_visible_track_count ()
3613 _visible_track_count = -1;
3614 visible_tracks_selector.set_text ( _("*") );
3618 Editor::edit_controls_button_release (GdkEventButton* ev)
3620 if (Keyboard::is_context_menu_event (ev)) {
3621 ARDOUR_UI::instance()->add_route (this);
3622 } else if (ev->button == 1) {
3623 selection->clear_tracks ();
3630 Editor::mouse_select_button_release (GdkEventButton* ev)
3632 /* this handles just right-clicks */
3634 if (ev->button != 3) {
3642 Editor::set_zoom_focus (ZoomFocus f)
3644 string str = zoom_focus_strings[(int)f];
3646 if (str != zoom_focus_selector.get_text()) {
3647 zoom_focus_selector.set_text (str);
3650 if (zoom_focus != f) {
3657 Editor::cycle_zoom_focus ()
3659 switch (zoom_focus) {
3661 set_zoom_focus (ZoomFocusRight);
3663 case ZoomFocusRight:
3664 set_zoom_focus (ZoomFocusCenter);
3666 case ZoomFocusCenter:
3667 set_zoom_focus (ZoomFocusPlayhead);
3669 case ZoomFocusPlayhead:
3670 set_zoom_focus (ZoomFocusMouse);
3672 case ZoomFocusMouse:
3673 set_zoom_focus (ZoomFocusEdit);
3676 set_zoom_focus (ZoomFocusLeft);
3682 Editor::ensure_float (Window& win)
3684 win.set_transient_for (*this);
3688 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3690 /* recover or initialize pane positions. do this here rather than earlier because
3691 we don't want the positions to change the child allocations, which they seem to do.
3697 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3706 XMLNode* geometry = find_named_node (*node, "geometry");
3708 if (which == static_cast<Paned*> (&edit_pane)) {
3710 if (done & Horizontal) {
3714 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3715 _notebook_shrunk = string_is_affirmative (prop->value ());
3718 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3719 /* initial allocation is 90% to canvas, 10% to notebook */
3720 pos = (int) floor (alloc.get_width() * 0.90f);
3721 snprintf (buf, sizeof(buf), "%d", pos);
3723 pos = atoi (prop->value());
3726 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3727 edit_pane.set_position (pos);
3730 done = (Pane) (done | Horizontal);
3732 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3734 if (done & Vertical) {
3738 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3739 /* initial allocation is 90% to canvas, 10% to summary */
3740 pos = (int) floor (alloc.get_height() * 0.90f);
3741 snprintf (buf, sizeof(buf), "%d", pos);
3744 pos = atoi (prop->value());
3747 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3748 editor_summary_pane.set_position (pos);
3751 done = (Pane) (done | Vertical);
3756 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3758 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3759 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3760 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3761 top_hbox.remove (toolbar_frame);
3766 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3768 if (toolbar_frame.get_parent() == 0) {
3769 top_hbox.pack_end (toolbar_frame);
3774 Editor::set_show_measures (bool yn)
3776 if (_show_measures != yn) {
3779 if ((_show_measures = yn) == true) {
3781 tempo_lines->show();
3784 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3785 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3787 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3788 draw_measures (begin, end);
3796 Editor::toggle_follow_playhead ()
3798 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3800 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3801 set_follow_playhead (tact->get_active());
3805 /** @param yn true to follow playhead, otherwise false.
3806 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3809 Editor::set_follow_playhead (bool yn, bool catch_up)
3811 if (_follow_playhead != yn) {
3812 if ((_follow_playhead = yn) == true && catch_up) {
3814 reset_x_origin_to_follow_playhead ();
3821 Editor::toggle_stationary_playhead ()
3823 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3825 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3826 set_stationary_playhead (tact->get_active());
3831 Editor::set_stationary_playhead (bool yn)
3833 if (_stationary_playhead != yn) {
3834 if ((_stationary_playhead = yn) == true) {
3836 // FIXME need a 3.0 equivalent of this 2.X call
3837 // update_current_screen ();
3844 Editor::playlist_selector () const
3846 return *_playlist_selector;
3850 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3852 if (paste_count == 0) {
3853 /* don't bother calculating an offset that will be zero anyway */
3857 /* calculate basic unsnapped multi-paste offset */
3858 framecnt_t offset = paste_count * duration;
3860 /* snap offset so pos + offset is aligned to the grid */
3861 framepos_t offset_pos = pos + offset;
3862 snap_to(offset_pos, RoundUpMaybe);
3863 offset = offset_pos - pos;
3869 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3873 switch (_snap_type) {
3875 return Evoral::MusicalTime(1.0);
3878 case SnapToBeatDiv128:
3879 return Evoral::MusicalTime(1.0/128.0);
3881 case SnapToBeatDiv64:
3882 return Evoral::MusicalTime(1.0/64.0);
3884 case SnapToBeatDiv32:
3885 return Evoral::MusicalTime(1.0/32.0);
3887 case SnapToBeatDiv28:
3888 return Evoral::MusicalTime(1.0/28.0);
3890 case SnapToBeatDiv24:
3891 return Evoral::MusicalTime(1.0/24.0);
3893 case SnapToBeatDiv20:
3894 return Evoral::MusicalTime(1.0/20.0);
3896 case SnapToBeatDiv16:
3897 return Evoral::MusicalTime(1.0/16.0);
3899 case SnapToBeatDiv14:
3900 return Evoral::MusicalTime(1.0/14.0);
3902 case SnapToBeatDiv12:
3903 return Evoral::MusicalTime(1.0/12.0);
3905 case SnapToBeatDiv10:
3906 return Evoral::MusicalTime(1.0/10.0);
3908 case SnapToBeatDiv8:
3909 return Evoral::MusicalTime(1.0/8.0);
3911 case SnapToBeatDiv7:
3912 return Evoral::MusicalTime(1.0/7.0);
3914 case SnapToBeatDiv6:
3915 return Evoral::MusicalTime(1.0/6.0);
3917 case SnapToBeatDiv5:
3918 return Evoral::MusicalTime(1.0/5.0);
3920 case SnapToBeatDiv4:
3921 return Evoral::MusicalTime(1.0/4.0);
3923 case SnapToBeatDiv3:
3924 return Evoral::MusicalTime(1.0/3.0);
3926 case SnapToBeatDiv2:
3927 return Evoral::MusicalTime(1.0/2.0);
3932 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3937 case SnapToTimecodeFrame:
3938 case SnapToTimecodeSeconds:
3939 case SnapToTimecodeMinutes:
3942 case SnapToRegionStart:
3943 case SnapToRegionEnd:
3944 case SnapToRegionSync:
3945 case SnapToRegionBoundary:
3951 return Evoral::MusicalTime();
3955 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3959 ret = nudge_clock->current_duration (pos);
3960 next = ret + 1; /* XXXX fix me */
3966 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3968 ArdourDialog dialog (_("Playlist Deletion"));
3969 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3970 "If it is kept, its audio files will not be cleaned.\n"
3971 "If it is deleted, audio files used by it alone will be cleaned."),
3974 dialog.set_position (WIN_POS_CENTER);
3975 dialog.get_vbox()->pack_start (label);
3979 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3980 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3981 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3983 switch (dialog.run ()) {
3984 case RESPONSE_ACCEPT:
3985 /* delete the playlist */
3989 case RESPONSE_REJECT:
3990 /* keep the playlist */
4002 Editor::audio_region_selection_covers (framepos_t where)
4004 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4005 if ((*a)->region()->covers (where)) {
4014 Editor::prepare_for_cleanup ()
4016 cut_buffer->clear_regions ();
4017 cut_buffer->clear_playlists ();
4019 selection->clear_regions ();
4020 selection->clear_playlists ();
4022 _regions->suspend_redisplay ();
4026 Editor::finish_cleanup ()
4028 _regions->resume_redisplay ();
4032 Editor::transport_loop_location()
4035 return _session->locations()->auto_loop_location();
4042 Editor::transport_punch_location()
4045 return _session->locations()->auto_punch_location();
4052 Editor::control_layout_scroll (GdkEventScroll* ev)
4054 /* Just forward to the normal canvas scroll method. The coordinate
4055 systems are different but since the canvas is always larger than the
4056 track headers, and aligned with the trackview area, this will work.
4058 In the not too distant future this layout is going away anyway and
4059 headers will be on the canvas.
4061 return canvas_scroll_event (ev, false);
4065 Editor::session_state_saved (string)
4068 _snapshots->redisplay ();
4072 Editor::update_tearoff_visibility()
4074 bool visible = Config->get_keep_tearoffs();
4075 _mouse_mode_tearoff->set_visible (visible);
4076 _tools_tearoff->set_visible (visible);
4077 if (_zoom_tearoff) {
4078 _zoom_tearoff->set_visible (visible);
4083 Editor::reattach_all_tearoffs ()
4085 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4086 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4087 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4091 Editor::maximise_editing_space ()
4103 Editor::restore_editing_space ()
4115 * Make new playlists for a given track and also any others that belong
4116 * to the same active route group with the `select' property.
4121 Editor::new_playlists (TimeAxisView* v)
4123 begin_reversible_command (_("new playlists"));
4124 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4125 _session->playlists->get (playlists);
4126 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4127 commit_reversible_command ();
4131 * Use a copy of the current playlist for a given track and also any others that belong
4132 * to the same active route group with the `select' property.
4137 Editor::copy_playlists (TimeAxisView* v)
4139 begin_reversible_command (_("copy playlists"));
4140 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4141 _session->playlists->get (playlists);
4142 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4143 commit_reversible_command ();
4146 /** Clear the current playlist for a given track and also any others that belong
4147 * to the same active route group with the `select' property.
4152 Editor::clear_playlists (TimeAxisView* v)
4154 begin_reversible_command (_("clear playlists"));
4155 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4156 _session->playlists->get (playlists);
4157 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4158 commit_reversible_command ();
4162 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4164 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4168 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4170 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4174 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4176 atv.clear_playlist ();
4180 Editor::on_key_press_event (GdkEventKey* ev)
4182 return key_press_focus_accelerator_handler (*this, ev);
4186 Editor::on_key_release_event (GdkEventKey* ev)
4188 return Gtk::Window::on_key_release_event (ev);
4189 // return key_press_focus_accelerator_handler (*this, ev);
4193 Editor::get_y_origin () const
4195 return vertical_adjustment.get_value ();
4198 /** Queue up a change to the viewport x origin.
4199 * @param frame New x origin.
4202 Editor::reset_x_origin (framepos_t frame)
4204 pending_visual_change.add (VisualChange::TimeOrigin);
4205 pending_visual_change.time_origin = frame;
4206 ensure_visual_change_idle_handler ();
4210 Editor::reset_y_origin (double y)
4212 pending_visual_change.add (VisualChange::YOrigin);
4213 pending_visual_change.y_origin = y;
4214 ensure_visual_change_idle_handler ();
4218 Editor::reset_zoom (framecnt_t spp)
4220 if (spp == samples_per_pixel) {
4224 pending_visual_change.add (VisualChange::ZoomLevel);
4225 pending_visual_change.samples_per_pixel = spp;
4226 ensure_visual_change_idle_handler ();
4230 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4232 reset_x_origin (frame);
4235 if (!no_save_visual) {
4236 undo_visual_stack.push_back (current_visual_state(false));
4240 Editor::VisualState::VisualState (bool with_tracks)
4241 : gui_state (with_tracks ? new GUIObjectState : 0)
4245 Editor::VisualState::~VisualState ()
4250 Editor::VisualState*
4251 Editor::current_visual_state (bool with_tracks)
4253 VisualState* vs = new VisualState (with_tracks);
4254 vs->y_position = vertical_adjustment.get_value();
4255 vs->samples_per_pixel = samples_per_pixel;
4256 vs->leftmost_frame = leftmost_frame;
4257 vs->zoom_focus = zoom_focus;
4260 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4267 Editor::undo_visual_state ()
4269 if (undo_visual_stack.empty()) {
4273 VisualState* vs = undo_visual_stack.back();
4274 undo_visual_stack.pop_back();
4277 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4280 use_visual_state (*vs);
4285 Editor::redo_visual_state ()
4287 if (redo_visual_stack.empty()) {
4291 VisualState* vs = redo_visual_stack.back();
4292 redo_visual_stack.pop_back();
4294 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4295 // why do we check here?
4296 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4299 use_visual_state (*vs);
4304 Editor::swap_visual_state ()
4306 if (undo_visual_stack.empty()) {
4307 redo_visual_state ();
4309 undo_visual_state ();
4314 Editor::use_visual_state (VisualState& vs)
4316 PBD::Unwinder<bool> nsv (no_save_visual, true);
4317 DisplaySuspender ds;
4319 vertical_adjustment.set_value (vs.y_position);
4321 set_zoom_focus (vs.zoom_focus);
4322 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4325 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4327 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4328 (*i)->reset_visual_state ();
4332 _routes->update_visibility ();
4335 /** This is the core function that controls the zoom level of the canvas. It is called
4336 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4337 * @param spp new number of samples per pixel
4340 Editor::set_samples_per_pixel (framecnt_t spp)
4346 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4347 const framecnt_t lots_of_pixels = 4000;
4349 /* if the zoom level is greater than what you'd get trying to display 3
4350 * days of audio on a really big screen, then it's too big.
4353 if (spp * lots_of_pixels > three_days) {
4357 samples_per_pixel = spp;
4360 tempo_lines->tempo_map_changed();
4363 bool const showing_time_selection = selection->time.length() > 0;
4365 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4366 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4367 (*i)->reshow_selection (selection->time);
4371 ZoomChanged (); /* EMIT_SIGNAL */
4373 ArdourCanvas::GtkCanvasViewport* c;
4375 c = get_track_canvas();
4377 c->canvas()->zoomed ();
4380 if (playhead_cursor) {
4381 playhead_cursor->set_position (playhead_cursor->current_frame ());
4384 refresh_location_display();
4385 _summary->set_overlays_dirty ();
4387 update_marker_labels ();
4393 Editor::queue_visual_videotimeline_update ()
4396 * pending_visual_change.add (VisualChange::VideoTimeline);
4397 * or maybe even more specific: which videotimeline-image
4398 * currently it calls update_video_timeline() to update
4399 * _all outdated_ images on the video-timeline.
4400 * see 'exposeimg()' in video_image_frame.cc
4402 ensure_visual_change_idle_handler ();
4406 Editor::ensure_visual_change_idle_handler ()
4408 if (pending_visual_change.idle_handler_id < 0) {
4409 // see comment in add_to_idle_resize above.
4410 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4411 pending_visual_change.being_handled = false;
4416 Editor::_idle_visual_changer (void* arg)
4418 return static_cast<Editor*>(arg)->idle_visual_changer ();
4422 Editor::idle_visual_changer ()
4424 /* set_horizontal_position() below (and maybe other calls) call
4425 gtk_main_iteration(), so it's possible that a signal will be handled
4426 half-way through this method. If this signal wants an
4427 idle_visual_changer we must schedule another one after this one, so
4428 mark the idle_handler_id as -1 here to allow that. Also make a note
4429 that we are doing the visual change, so that changes in response to
4430 super-rapid-screen-update can be dropped if we are still processing
4434 pending_visual_change.idle_handler_id = -1;
4435 pending_visual_change.being_handled = true;
4437 VisualChange vc = pending_visual_change;
4439 pending_visual_change.pending = (VisualChange::Type) 0;
4441 visual_changer (vc);
4443 pending_visual_change.being_handled = false;
4445 return 0; /* this is always a one-shot call */
4449 Editor::visual_changer (const VisualChange& vc)
4451 double const last_time_origin = horizontal_position ();
4453 if (vc.pending & VisualChange::ZoomLevel) {
4454 set_samples_per_pixel (vc.samples_per_pixel);
4456 compute_fixed_ruler_scale ();
4458 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4459 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4461 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4462 current_bbt_points_begin, current_bbt_points_end);
4463 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4464 current_bbt_points_begin, current_bbt_points_end);
4465 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4467 update_video_timeline();
4470 if (vc.pending & VisualChange::TimeOrigin) {
4471 set_horizontal_position (vc.time_origin / samples_per_pixel);
4474 if (vc.pending & VisualChange::YOrigin) {
4475 vertical_adjustment.set_value (vc.y_origin);
4478 if (last_time_origin == horizontal_position ()) {
4479 /* changed signal not emitted */
4480 update_fixed_rulers ();
4481 redisplay_tempo (true);
4484 if (!(vc.pending & VisualChange::ZoomLevel)) {
4485 update_video_timeline();
4488 _summary->set_overlays_dirty ();
4491 struct EditorOrderTimeAxisSorter {
4492 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4493 return a->order () < b->order ();
4498 Editor::sort_track_selection (TrackViewList& sel)
4500 EditorOrderTimeAxisSorter cmp;
4505 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4508 framepos_t where = 0;
4509 EditPoint ep = _edit_point;
4511 if(Profile->get_mixbus())
4512 if (ep == EditAtSelectedMarker)
4515 if (from_context_menu && (ep == EditAtMouse)) {
4516 return canvas_event_sample (&context_click_event, 0, 0);
4519 if (entered_marker) {
4520 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4521 return entered_marker->position();
4524 if (ignore_playhead && ep == EditAtPlayhead) {
4525 ep = EditAtSelectedMarker;
4529 case EditAtPlayhead:
4530 where = _session->audible_frame();
4531 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4534 case EditAtSelectedMarker:
4535 if (!selection->markers.empty()) {
4537 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4540 where = loc->start();
4544 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4552 if (!mouse_frame (where, ignored)) {
4553 /* XXX not right but what can we do ? */
4557 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4565 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4567 if (!_session) return;
4569 begin_reversible_command (cmd);
4573 if ((tll = transport_loop_location()) == 0) {
4574 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4575 XMLNode &before = _session->locations()->get_state();
4576 _session->locations()->add (loc, true);
4577 _session->set_auto_loop_location (loc);
4578 XMLNode &after = _session->locations()->get_state();
4579 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4581 XMLNode &before = tll->get_state();
4582 tll->set_hidden (false, this);
4583 tll->set (start, end);
4584 XMLNode &after = tll->get_state();
4585 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4588 commit_reversible_command ();
4592 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4594 if (!_session) return;
4596 begin_reversible_command (cmd);
4600 if ((tpl = transport_punch_location()) == 0) {
4601 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4602 XMLNode &before = _session->locations()->get_state();
4603 _session->locations()->add (loc, true);
4604 _session->set_auto_punch_location (loc);
4605 XMLNode &after = _session->locations()->get_state();
4606 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4608 XMLNode &before = tpl->get_state();
4609 tpl->set_hidden (false, this);
4610 tpl->set (start, end);
4611 XMLNode &after = tpl->get_state();
4612 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4615 commit_reversible_command ();
4618 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4619 * @param rs List to which found regions are added.
4620 * @param where Time to look at.
4621 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4624 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4626 const TrackViewList* tracks;
4629 tracks = &track_views;
4634 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4636 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4639 boost::shared_ptr<Track> tr;
4640 boost::shared_ptr<Playlist> pl;
4642 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4644 boost::shared_ptr<RegionList> regions = pl->regions_at (
4645 (framepos_t) floor ( (double) where * tr->speed()));
4647 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4648 RegionView* rv = rtv->view()->find_view (*i);
4659 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4661 const TrackViewList* tracks;
4664 tracks = &track_views;
4669 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4670 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4672 boost::shared_ptr<Track> tr;
4673 boost::shared_ptr<Playlist> pl;
4675 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4677 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4678 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4680 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4682 RegionView* rv = rtv->view()->find_view (*i);
4693 /** Get regions using the following method:
4695 * Make a region list using:
4696 * (a) any selected regions
4697 * (b) the intersection of any selected tracks and the edit point(*)
4698 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4700 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4702 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4706 Editor::get_regions_from_selection_and_edit_point ()
4708 RegionSelection regions;
4710 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4711 regions.add (entered_regionview);
4713 regions = selection->regions;
4716 if ( regions.empty() ) {
4717 TrackViewList tracks = selection->tracks;
4719 if (!tracks.empty()) {
4720 /* no region selected or entered, but some selected tracks:
4721 * act on all regions on the selected tracks at the edit point
4723 framepos_t const where = get_preferred_edit_position ();
4724 get_regions_at(regions, where, tracks);
4731 /** Get regions using the following method:
4733 * Make a region list using:
4734 * (a) any selected regions
4735 * (b) the intersection of any selected tracks and the edit point(*)
4736 * (c) if neither exists, then whatever region is under the mouse
4738 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4740 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4743 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4745 RegionSelection regions;
4747 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4748 regions.add (entered_regionview);
4750 regions = selection->regions;
4753 if ( regions.empty() ) {
4754 TrackViewList tracks = selection->tracks;
4756 if (!tracks.empty()) {
4757 /* no region selected or entered, but some selected tracks:
4758 * act on all regions on the selected tracks at the edit point
4760 get_regions_at(regions, pos, tracks);
4767 /** Start with regions that are selected, or the entered regionview if none are selected.
4768 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4769 * of the regions that we started with.
4773 Editor::get_regions_from_selection_and_entered ()
4775 RegionSelection regions = selection->regions;
4777 if (regions.empty() && entered_regionview) {
4778 regions.add (entered_regionview);
4785 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4787 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4788 RouteTimeAxisView* tatv;
4790 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4791 boost::shared_ptr<Playlist> pl;
4792 std::vector<boost::shared_ptr<Region> > results;
4793 boost::shared_ptr<Track> tr;
4795 if ((tr = tatv->track()) == 0) {
4800 if ((pl = (tr->playlist())) != 0) {
4801 boost::shared_ptr<Region> r = pl->region_by_id (id);
4803 RegionView* marv = tatv->view()->find_view (r);
4805 regions.push_back (marv);
4814 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4816 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4818 RouteTimeAxisView* tatv;
4820 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4822 boost::shared_ptr<Playlist> pl;
4823 vector<boost::shared_ptr<Region> > results;
4825 boost::shared_ptr<Track> tr;
4827 if ((tr = tatv->track()) == 0) {
4832 if ((pl = (tr->playlist())) != 0) {
4833 if (src_comparison) {
4834 pl->get_source_equivalent_regions (region, results);
4836 pl->get_region_list_equivalent_regions (region, results);
4840 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4841 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4842 regions.push_back (marv);
4851 Editor::show_rhythm_ferret ()
4853 if (rhythm_ferret == 0) {
4854 rhythm_ferret = new RhythmFerret(*this);
4857 rhythm_ferret->set_session (_session);
4858 rhythm_ferret->show ();
4859 rhythm_ferret->present ();
4863 Editor::first_idle ()
4865 MessageDialog* dialog = 0;
4867 if (track_views.size() > 1) {
4868 dialog = new MessageDialog (
4870 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4874 ARDOUR_UI::instance()->flush_pending ();
4877 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4881 // first idle adds route children (automation tracks), so we need to redisplay here
4882 _routes->redisplay ();
4889 Editor::_idle_resize (gpointer arg)
4891 return ((Editor*)arg)->idle_resize ();
4895 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4897 if (resize_idle_id < 0) {
4898 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4899 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4900 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4902 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4903 _pending_resize_amount = 0;
4906 /* make a note of the smallest resulting height, so that we can clamp the
4907 lower limit at TimeAxisView::hSmall */
4909 int32_t min_resulting = INT32_MAX;
4911 _pending_resize_amount += h;
4912 _pending_resize_view = view;
4914 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4916 if (selection->tracks.contains (_pending_resize_view)) {
4917 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4918 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4922 if (min_resulting < 0) {
4927 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4928 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4932 /** Handle pending resizing of tracks */
4934 Editor::idle_resize ()
4936 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4938 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4939 selection->tracks.contains (_pending_resize_view)) {
4941 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4942 if (*i != _pending_resize_view) {
4943 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4948 _pending_resize_amount = 0;
4949 _group_tabs->set_dirty ();
4950 resize_idle_id = -1;
4958 ENSURE_GUI_THREAD (*this, &Editor::located);
4961 playhead_cursor->set_position (_session->audible_frame ());
4962 if (_follow_playhead && !_pending_initial_locate) {
4963 reset_x_origin_to_follow_playhead ();
4967 _pending_locate_request = false;
4968 _pending_initial_locate = false;
4972 Editor::region_view_added (RegionView * rv)
4974 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
4975 if (rv->region ()->id () == (*pr)) {
4976 selection->add (rv);
4977 selection->regions.pending.erase (pr);
4981 _summary->set_background_dirty ();
4985 Editor::region_view_removed ()
4987 _summary->set_background_dirty ();
4991 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4993 TrackViewList::const_iterator j = track_views.begin ();
4994 while (j != track_views.end()) {
4995 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4996 if (rtv && rtv->route() == r) {
5007 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5011 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5012 TimeAxisView* tv = axis_view_from_route (*i);
5022 Editor::suspend_route_redisplay ()
5025 _routes->suspend_redisplay();
5030 Editor::resume_route_redisplay ()
5033 _routes->resume_redisplay();
5038 Editor::add_routes (RouteList& routes)
5040 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5042 RouteTimeAxisView *rtv;
5043 list<RouteTimeAxisView*> new_views;
5045 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5046 boost::shared_ptr<Route> route = (*x);
5048 if (route->is_auditioner() || route->is_monitor()) {
5052 DataType dt = route->input()->default_type();
5054 if (dt == ARDOUR::DataType::AUDIO) {
5055 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5056 rtv->set_route (route);
5057 } else if (dt == ARDOUR::DataType::MIDI) {
5058 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5059 rtv->set_route (route);
5061 throw unknown_type();
5064 new_views.push_back (rtv);
5065 track_views.push_back (rtv);
5067 rtv->effective_gain_display ();
5069 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5070 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5073 if (new_views.size() > 0) {
5074 _routes->routes_added (new_views);
5075 _summary->routes_added (new_views);
5078 if (show_editor_mixer_when_tracks_arrive) {
5079 show_editor_mixer (true);
5082 editor_list_button.set_sensitive (true);
5086 Editor::timeaxisview_deleted (TimeAxisView *tv)
5088 if (tv == entered_track) {
5092 if (_session && _session->deletion_in_progress()) {
5093 /* the situation is under control */
5097 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5099 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5101 _routes->route_removed (tv);
5103 TimeAxisView::Children c = tv->get_child_list ();
5104 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5105 if (entered_track == i->get()) {
5110 /* remove it from the list of track views */
5112 TrackViewList::iterator i;
5114 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5115 i = track_views.erase (i);
5118 /* update whatever the current mixer strip is displaying, if revelant */
5120 boost::shared_ptr<Route> route;
5123 route = rtav->route ();
5126 if (current_mixer_strip && current_mixer_strip->route() == route) {
5128 TimeAxisView* next_tv;
5130 if (track_views.empty()) {
5132 } else if (i == track_views.end()) {
5133 next_tv = track_views.front();
5140 set_selected_mixer_strip (*next_tv);
5142 /* make the editor mixer strip go away setting the
5143 * button to inactive (which also unticks the menu option)
5146 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5152 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5154 if (apply_to_selection) {
5155 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5157 TrackSelection::iterator j = i;
5160 hide_track_in_display (*i, false);
5165 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5167 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5168 // this will hide the mixer strip
5169 set_selected_mixer_strip (*tv);
5172 _routes->hide_track_in_display (*tv);
5177 Editor::sync_track_view_list_and_routes ()
5179 track_views = TrackViewList (_routes->views ());
5181 _summary->set_dirty ();
5182 _group_tabs->set_dirty ();
5184 return false; // do not call again (until needed)
5188 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5190 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5195 /** Find a RouteTimeAxisView by the ID of its route */
5197 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5199 RouteTimeAxisView* v;
5201 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5202 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5203 if(v->route()->id() == id) {
5213 Editor::fit_route_group (RouteGroup *g)
5215 TrackViewList ts = axis_views_from_routes (g->route_list ());
5220 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5222 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5225 _session->cancel_audition ();
5229 if (_session->is_auditioning()) {
5230 _session->cancel_audition ();
5231 if (r == last_audition_region) {
5236 _session->audition_region (r);
5237 last_audition_region = r;
5242 Editor::hide_a_region (boost::shared_ptr<Region> r)
5244 r->set_hidden (true);
5248 Editor::show_a_region (boost::shared_ptr<Region> r)
5250 r->set_hidden (false);
5254 Editor::audition_region_from_region_list ()
5256 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5260 Editor::hide_region_from_region_list ()
5262 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5266 Editor::show_region_in_region_list ()
5268 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5272 Editor::step_edit_status_change (bool yn)
5275 start_step_editing ();
5277 stop_step_editing ();
5282 Editor::start_step_editing ()
5284 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5288 Editor::stop_step_editing ()
5290 step_edit_connection.disconnect ();
5294 Editor::check_step_edit ()
5296 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5297 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5299 mtv->check_step_edit ();
5303 return true; // do it again, till we stop
5307 Editor::scroll_press (Direction dir)
5309 ++_scroll_callbacks;
5311 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5312 /* delay the first auto-repeat */
5318 scroll_backward (1);
5326 scroll_up_one_track ();
5330 scroll_down_one_track ();
5334 /* do hacky auto-repeat */
5335 if (!_scroll_connection.connected ()) {
5337 _scroll_connection = Glib::signal_timeout().connect (
5338 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5341 _scroll_callbacks = 0;
5348 Editor::scroll_release ()
5350 _scroll_connection.disconnect ();
5353 /** Queue a change for the Editor viewport x origin to follow the playhead */
5355 Editor::reset_x_origin_to_follow_playhead ()
5357 framepos_t const frame = playhead_cursor->current_frame ();
5359 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5361 if (_session->transport_speed() < 0) {
5363 if (frame > (current_page_samples() / 2)) {
5364 center_screen (frame-(current_page_samples()/2));
5366 center_screen (current_page_samples()/2);
5373 if (frame < leftmost_frame) {
5375 if (_session->transport_rolling()) {
5376 /* rolling; end up with the playhead at the right of the page */
5377 l = frame - current_page_samples ();
5379 /* not rolling: end up with the playhead 1/4 of the way along the page */
5380 l = frame - current_page_samples() / 4;
5384 if (_session->transport_rolling()) {
5385 /* rolling: end up with the playhead on the left of the page */
5388 /* not rolling: end up with the playhead 3/4 of the way along the page */
5389 l = frame - 3 * current_page_samples() / 4;
5397 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5403 Editor::super_rapid_screen_update ()
5405 if (!_session || !_session->engine().running()) {
5409 /* METERING / MIXER STRIPS */
5411 /* update track meters, if required */
5412 if (is_mapped() && meters_running) {
5413 RouteTimeAxisView* rtv;
5414 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5415 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5416 rtv->fast_update ();
5421 /* and any current mixer strip */
5422 if (current_mixer_strip) {
5423 current_mixer_strip->fast_update ();
5426 /* PLAYHEAD AND VIEWPORT */
5428 framepos_t const frame = _session->audible_frame();
5430 /* There are a few reasons why we might not update the playhead / viewport stuff:
5432 * 1. we don't update things when there's a pending locate request, otherwise
5433 * when the editor requests a locate there is a chance that this method
5434 * will move the playhead before the locate request is processed, causing
5436 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5437 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5440 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5442 last_update_frame = frame;
5444 if (!_dragging_playhead) {
5445 playhead_cursor->set_position (frame);
5448 if (!_stationary_playhead) {
5450 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5451 /* We only do this if we aren't already
5452 handling a visual change (ie if
5453 pending_visual_change.being_handled is
5454 false) so that these requests don't stack
5455 up there are too many of them to handle in
5458 reset_x_origin_to_follow_playhead ();
5463 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5467 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5468 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5469 if (target <= 0.0) {
5472 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5473 target = (target * 0.15) + (current * 0.85);
5479 set_horizontal_position (current);
5488 Editor::session_going_away ()
5490 _have_idled = false;
5492 _session_connections.drop_connections ();
5494 super_rapid_screen_update_connection.disconnect ();
5496 selection->clear ();
5497 cut_buffer->clear ();
5499 clicked_regionview = 0;
5500 clicked_axisview = 0;
5501 clicked_routeview = 0;
5502 entered_regionview = 0;
5504 last_update_frame = 0;
5507 playhead_cursor->hide ();
5509 /* rip everything out of the list displays */
5513 _route_groups->clear ();
5515 /* do this first so that deleting a track doesn't reset cms to null
5516 and thus cause a leak.
5519 if (current_mixer_strip) {
5520 if (current_mixer_strip->get_parent() != 0) {
5521 global_hpacker.remove (*current_mixer_strip);
5523 delete current_mixer_strip;
5524 current_mixer_strip = 0;
5527 /* delete all trackviews */
5529 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5532 track_views.clear ();
5534 nudge_clock->set_session (0);
5536 editor_list_button.set_active(false);
5537 editor_list_button.set_sensitive(false);
5539 /* clear tempo/meter rulers */
5540 remove_metric_marks ();
5542 clear_marker_display ();
5544 stop_step_editing ();
5546 /* get rid of any existing editor mixer strip */
5548 WindowTitle title(Glib::get_application_name());
5549 title += _("Editor");
5551 set_title (title.get_string());
5553 SessionHandlePtr::session_going_away ();
5558 Editor::show_editor_list (bool yn)
5561 _the_notebook.show ();
5563 _the_notebook.hide ();
5568 Editor::change_region_layering_order (bool from_context_menu)
5570 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5572 if (!clicked_routeview) {
5573 if (layering_order_editor) {
5574 layering_order_editor->hide ();
5579 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5585 boost::shared_ptr<Playlist> pl = track->playlist();
5591 if (layering_order_editor == 0) {
5592 layering_order_editor = new RegionLayeringOrderEditor (*this);
5595 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5596 layering_order_editor->maybe_present ();
5600 Editor::update_region_layering_order_editor ()
5602 if (layering_order_editor && layering_order_editor->is_visible ()) {
5603 change_region_layering_order (true);
5608 Editor::setup_fade_images ()
5610 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5611 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5612 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5613 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5614 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5616 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5617 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5618 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5619 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5620 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5622 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5623 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5624 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5625 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5626 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5628 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5629 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5630 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5631 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5632 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5636 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5638 Editor::action_menu_item (std::string const & name)
5640 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5643 return *manage (a->create_menu_item ());
5647 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5649 EventBox* b = manage (new EventBox);
5650 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5651 Label* l = manage (new Label (name));
5655 _the_notebook.append_page (widget, *b);
5659 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5661 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5662 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5665 if (ev->type == GDK_2BUTTON_PRESS) {
5667 /* double-click on a notebook tab shrinks or expands the notebook */
5669 if (_notebook_shrunk) {
5670 if (pre_notebook_shrink_pane_width) {
5671 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5673 _notebook_shrunk = false;
5675 pre_notebook_shrink_pane_width = edit_pane.get_position();
5677 /* this expands the LHS of the edit pane to cover the notebook
5678 PAGE but leaves the tabs visible.
5680 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5681 _notebook_shrunk = true;
5689 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5691 using namespace Menu_Helpers;
5693 MenuList& items = _control_point_context_menu.items ();
5696 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5697 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5698 if (!can_remove_control_point (item)) {
5699 items.back().set_sensitive (false);
5702 _control_point_context_menu.popup (event->button.button, event->button.time);
5706 Editor::zoom_vertical_modifier_released()
5708 _stepping_axis_view = 0;
5712 Editor::ui_parameter_changed (string parameter)
5714 if (parameter == "icon-set") {
5715 while (!_cursor_stack.empty()) {
5716 _cursor_stack.pop();
5718 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5719 } else if (parameter == "draggable-playhead") {
5720 if (_verbose_cursor) {
5721 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());