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);
309 clicked_regionview = 0;
310 clicked_axisview = 0;
311 clicked_routeview = 0;
312 clicked_control_point = 0;
313 last_update_frame = 0;
314 pre_press_cursor = 0;
315 _drags = new DragManager (this);
318 current_mixer_strip = 0;
321 snap_type_strings = I18N (_snap_type_strings);
322 snap_mode_strings = I18N (_snap_mode_strings);
323 zoom_focus_strings = I18N (_zoom_focus_strings);
324 edit_mode_strings = I18N (_edit_mode_strings);
325 edit_point_strings = I18N (_edit_point_strings);
326 #ifdef USE_RUBBERBAND
327 rb_opt_strings = I18N (_rb_opt_strings);
331 build_edit_mode_menu();
332 build_zoom_focus_menu();
333 build_track_count_menu();
334 build_snap_mode_menu();
335 build_snap_type_menu();
336 build_edit_point_menu();
338 snap_threshold = 5.0;
339 bbt_beat_subdivision = 4;
340 _visible_canvas_width = 0;
341 _visible_canvas_height = 0;
342 autoscroll_horizontal_allowed = false;
343 autoscroll_vertical_allowed = false;
348 current_interthread_info = 0;
349 _show_measures = true;
351 show_gain_after_trim = false;
353 have_pending_keyboard_selection = false;
354 _follow_playhead = true;
355 _stationary_playhead = false;
356 editor_ruler_menu = 0;
357 no_ruler_shown_update = false;
359 range_marker_menu = 0;
360 marker_menu_item = 0;
361 tempo_or_meter_marker_menu = 0;
362 transport_marker_menu = 0;
363 new_transport_marker_menu = 0;
364 editor_mixer_strip_width = Wide;
365 show_editor_mixer_when_tracks_arrive = false;
366 region_edit_menu_split_multichannel_item = 0;
367 region_edit_menu_split_item = 0;
370 current_stepping_trackview = 0;
372 entered_regionview = 0;
374 clear_entered_track = false;
377 button_release_can_deselect = true;
378 _dragging_playhead = false;
379 _dragging_edit_point = false;
380 select_new_marker = false;
382 layering_order_editor = 0;
383 no_save_visual = false;
385 within_track_canvas = false;
387 scrubbing_direction = 0;
391 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
392 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
393 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
394 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
395 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
397 zoom_focus = ZoomFocusLeft;
398 _edit_point = EditAtMouse;
399 _internal_editing = false;
400 current_canvas_cursor = 0;
401 _visible_track_count = 16;
403 samples_per_pixel = 2048; /* too early to use reset_zoom () */
405 _scroll_callbacks = 0;
407 bbt_label.set_name ("EditorRulerLabel");
408 bbt_label.set_size_request (-1, (int)timebar_height);
409 bbt_label.set_alignment (1.0, 0.5);
410 bbt_label.set_padding (5,0);
412 bbt_label.set_no_show_all();
413 minsec_label.set_name ("EditorRulerLabel");
414 minsec_label.set_size_request (-1, (int)timebar_height);
415 minsec_label.set_alignment (1.0, 0.5);
416 minsec_label.set_padding (5,0);
417 minsec_label.hide ();
418 minsec_label.set_no_show_all();
419 timecode_label.set_name ("EditorRulerLabel");
420 timecode_label.set_size_request (-1, (int)timebar_height);
421 timecode_label.set_alignment (1.0, 0.5);
422 timecode_label.set_padding (5,0);
423 timecode_label.hide ();
424 timecode_label.set_no_show_all();
425 samples_label.set_name ("EditorRulerLabel");
426 samples_label.set_size_request (-1, (int)timebar_height);
427 samples_label.set_alignment (1.0, 0.5);
428 samples_label.set_padding (5,0);
429 samples_label.hide ();
430 samples_label.set_no_show_all();
432 tempo_label.set_name ("EditorRulerLabel");
433 tempo_label.set_size_request (-1, (int)timebar_height);
434 tempo_label.set_alignment (1.0, 0.5);
435 tempo_label.set_padding (5,0);
437 tempo_label.set_no_show_all();
439 meter_label.set_name ("EditorRulerLabel");
440 meter_label.set_size_request (-1, (int)timebar_height);
441 meter_label.set_alignment (1.0, 0.5);
442 meter_label.set_padding (5,0);
444 meter_label.set_no_show_all();
446 if (Profile->get_trx()) {
447 mark_label.set_text (_("Markers"));
449 mark_label.set_name ("EditorRulerLabel");
450 mark_label.set_size_request (-1, (int)timebar_height);
451 mark_label.set_alignment (1.0, 0.5);
452 mark_label.set_padding (5,0);
454 mark_label.set_no_show_all();
456 cd_mark_label.set_name ("EditorRulerLabel");
457 cd_mark_label.set_size_request (-1, (int)timebar_height);
458 cd_mark_label.set_alignment (1.0, 0.5);
459 cd_mark_label.set_padding (5,0);
460 cd_mark_label.hide();
461 cd_mark_label.set_no_show_all();
463 videotl_bar_height = 4;
464 videotl_label.set_name ("EditorRulerLabel");
465 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
466 videotl_label.set_alignment (1.0, 0.5);
467 videotl_label.set_padding (5,0);
468 videotl_label.hide();
469 videotl_label.set_no_show_all();
471 range_mark_label.set_name ("EditorRulerLabel");
472 range_mark_label.set_size_request (-1, (int)timebar_height);
473 range_mark_label.set_alignment (1.0, 0.5);
474 range_mark_label.set_padding (5,0);
475 range_mark_label.hide();
476 range_mark_label.set_no_show_all();
478 transport_mark_label.set_name ("EditorRulerLabel");
479 transport_mark_label.set_size_request (-1, (int)timebar_height);
480 transport_mark_label.set_alignment (1.0, 0.5);
481 transport_mark_label.set_padding (5,0);
482 transport_mark_label.hide();
483 transport_mark_label.set_no_show_all();
485 initialize_canvas ();
487 _summary = new EditorSummary (this);
489 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
490 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
492 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
494 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
495 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
497 edit_controls_vbox.set_spacing (0);
498 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
499 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
501 HBox* h = manage (new HBox);
502 _group_tabs = new EditorGroupTabs (this);
503 if (!ARDOUR::Profile->get_trx()) {
504 h->pack_start (*_group_tabs, PACK_SHRINK);
506 h->pack_start (edit_controls_vbox);
507 controls_layout.add (*h);
509 controls_layout.set_name ("EditControlsBase");
510 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
511 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
512 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
514 _cursors = new MouseCursors;
515 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
516 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
518 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
520 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
521 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
522 pad_line_1->set_outline_color (0xFF0000FF);
528 edit_packer.set_col_spacings (0);
529 edit_packer.set_row_spacings (0);
530 edit_packer.set_homogeneous (false);
531 edit_packer.set_border_width (0);
532 edit_packer.set_name ("EditorWindow");
534 time_bars_event_box.add (time_bars_vbox);
535 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
536 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
538 /* labels for the time bars */
539 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
541 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
543 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
545 bottom_hbox.set_border_width (2);
546 bottom_hbox.set_spacing (3);
548 _route_groups = new EditorRouteGroups (this);
549 _routes = new EditorRoutes (this);
550 _regions = new EditorRegions (this);
551 _snapshots = new EditorSnapshots (this);
552 _locations = new EditorLocations (this);
554 add_notebook_page (_("Regions"), _regions->widget ());
555 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
556 add_notebook_page (_("Snapshots"), _snapshots->widget ());
557 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
558 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
560 _the_notebook.set_show_tabs (true);
561 _the_notebook.set_scrollable (true);
562 _the_notebook.popup_disable ();
563 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
564 _the_notebook.show_all ();
566 _notebook_shrunk = false;
568 editor_summary_pane.pack1(edit_packer);
570 Button* summary_arrows_left_left = manage (new Button);
571 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
572 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
573 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
575 Button* summary_arrows_left_right = manage (new Button);
576 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
577 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
578 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
580 VBox* summary_arrows_left = manage (new VBox);
581 summary_arrows_left->pack_start (*summary_arrows_left_left);
582 summary_arrows_left->pack_start (*summary_arrows_left_right);
584 Button* summary_arrows_right_up = manage (new Button);
585 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
586 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
587 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
589 Button* summary_arrows_right_down = manage (new Button);
590 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
591 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
592 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
594 VBox* summary_arrows_right = manage (new VBox);
595 summary_arrows_right->pack_start (*summary_arrows_right_up);
596 summary_arrows_right->pack_start (*summary_arrows_right_down);
598 Frame* summary_frame = manage (new Frame);
599 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
601 summary_frame->add (*_summary);
602 summary_frame->show ();
604 _summary_hbox.pack_start (*summary_arrows_left, false, false);
605 _summary_hbox.pack_start (*summary_frame, true, true);
606 _summary_hbox.pack_start (*summary_arrows_right, false, false);
608 if (!ARDOUR::Profile->get_trx()) {
609 editor_summary_pane.pack2 (_summary_hbox);
612 edit_pane.pack1 (editor_summary_pane, true, true);
613 if (!ARDOUR::Profile->get_trx()) {
614 edit_pane.pack2 (_the_notebook, false, true);
617 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
619 /* XXX: editor_summary_pane might need similar to the edit_pane */
621 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
623 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
624 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
626 top_hbox.pack_start (toolbar_frame);
628 HBox *hbox = manage (new HBox);
629 hbox->pack_start (edit_pane, true, true);
631 global_vpacker.pack_start (top_hbox, false, false);
632 global_vpacker.pack_start (*hbox, true, true);
634 global_hpacker.pack_start (global_vpacker, true, true);
636 set_name ("EditorWindow");
637 add_accel_group (ActionManager::ui_manager->get_accel_group());
639 status_bar_hpacker.show ();
641 vpacker.pack_end (status_bar_hpacker, false, false);
642 vpacker.pack_end (global_hpacker, true, true);
644 /* register actions now so that set_state() can find them and set toggles/checks etc */
647 /* when we start using our own keybinding system for the editor, this
648 * will be uncommented
654 set_zoom_focus (zoom_focus);
655 set_visible_track_count (_visible_track_count);
656 _snap_type = SnapToBeat;
657 set_snap_to (_snap_type);
658 _snap_mode = SnapOff;
659 set_snap_mode (_snap_mode);
660 set_mouse_mode (MouseObject, true);
661 pre_internal_mouse_mode = MouseObject;
662 pre_internal_snap_type = _snap_type;
663 pre_internal_snap_mode = _snap_mode;
664 internal_snap_type = _snap_type;
665 internal_snap_mode = _snap_mode;
666 set_edit_point_preference (EditAtMouse, true);
668 _playlist_selector = new PlaylistSelector();
669 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
671 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
675 nudge_forward_button.set_name ("nudge button");
676 nudge_forward_button.set_image(::get_icon("nudge_right"));
678 nudge_backward_button.set_name ("nudge button");
679 nudge_backward_button.set_image(::get_icon("nudge_left"));
681 fade_context_menu.set_name ("ArdourContextMenu");
683 /* icons, titles, WM stuff */
685 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
686 Glib::RefPtr<Gdk::Pixbuf> icon;
688 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
689 window_icons.push_back (icon);
691 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
692 window_icons.push_back (icon);
694 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
695 window_icons.push_back (icon);
697 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
698 window_icons.push_back (icon);
700 if (!window_icons.empty()) {
701 // set_icon_list (window_icons);
702 set_default_icon_list (window_icons);
705 WindowTitle title(Glib::get_application_name());
706 title += _("Editor");
707 set_title (title.get_string());
708 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
711 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
713 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
714 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
716 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
718 /* allow external control surfaces/protocols to do various things */
720 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
721 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
722 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
723 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
724 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
725 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
726 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
727 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
728 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
729 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
730 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
731 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
732 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
733 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
735 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
736 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
737 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
738 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
739 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
741 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
743 /* problematic: has to return a value and thus cannot be x-thread */
745 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
747 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
748 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
750 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
752 _ignore_region_action = false;
753 _last_region_menu_was_main = false;
754 _popup_region_menu_item = 0;
756 _ignore_follow_edits = false;
758 _show_marker_lines = false;
760 /* Button bindings */
762 button_bindings = new Bindings;
764 XMLNode* node = button_settings();
766 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
767 button_bindings->load (**i);
773 /* grab current parameter state */
774 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
775 ARDOUR_UI::config()->map_parameters (pc);
777 setup_fade_images ();
784 delete button_bindings;
786 delete _route_groups;
787 delete _track_canvas_viewport;
792 Editor::button_settings () const
794 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
795 XMLNode* node = find_named_node (*settings, X_("Buttons"));
798 node = new XMLNode (X_("Buttons"));
805 Editor::add_toplevel_menu (Container& cont)
807 vpacker.pack_start (cont, false, false);
812 Editor::add_transport_frame (Container& cont)
814 if(ARDOUR::Profile->get_mixbus()) {
815 global_vpacker.pack_start (cont, false, false);
816 global_vpacker.reorder_child (cont, 0);
819 vpacker.pack_start (cont, false, false);
824 Editor::get_smart_mode () const
826 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
830 Editor::catch_vanishing_regionview (RegionView *rv)
832 /* note: the selection will take care of the vanishing
833 audioregionview by itself.
836 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
840 if (clicked_regionview == rv) {
841 clicked_regionview = 0;
844 if (entered_regionview == rv) {
845 set_entered_regionview (0);
848 if (!_all_region_actions_sensitized) {
849 sensitize_all_region_actions (true);
854 Editor::set_entered_regionview (RegionView* rv)
856 if (rv == entered_regionview) {
860 if (entered_regionview) {
861 entered_regionview->exited ();
864 entered_regionview = rv;
866 if (entered_regionview != 0) {
867 entered_regionview->entered (internal_editing ());
870 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
871 /* This RegionView entry might have changed what region actions
872 are allowed, so sensitize them all in case a key is pressed.
874 sensitize_all_region_actions (true);
879 Editor::set_entered_track (TimeAxisView* tav)
882 entered_track->exited ();
888 entered_track->entered ();
893 Editor::show_window ()
895 if (!is_visible ()) {
899 /* XXX: this is a bit unfortunate; it would probably
900 be nicer if we could just call show () above rather
901 than needing the show_all ()
904 /* re-hide stuff if necessary */
905 editor_list_button_toggled ();
906 parameter_changed ("show-summary");
907 parameter_changed ("show-group-tabs");
908 parameter_changed ("show-zoom-tools");
910 /* now reset all audio_time_axis heights, because widgets might need
916 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
917 tv = (static_cast<TimeAxisView*>(*i));
921 if (current_mixer_strip) {
922 current_mixer_strip->hide_things ();
923 current_mixer_strip->parameter_changed ("mixer-element-visibility");
931 Editor::instant_save ()
933 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
938 _session->add_instant_xml(get_state());
940 Config->add_instant_xml(get_state());
945 Editor::control_vertical_zoom_in_all ()
947 tav_zoom_smooth (false, true);
951 Editor::control_vertical_zoom_out_all ()
953 tav_zoom_smooth (true, true);
957 Editor::control_vertical_zoom_in_selected ()
959 tav_zoom_smooth (false, false);
963 Editor::control_vertical_zoom_out_selected ()
965 tav_zoom_smooth (true, false);
969 Editor::control_view (uint32_t view)
971 goto_visual_state (view);
975 Editor::control_unselect ()
977 selection->clear_tracks ();
981 Editor::control_select (uint32_t rid, Selection::Operation op)
983 /* handles the (static) signal from the ControlProtocol class that
984 * requests setting the selected track to a given RID
991 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
997 TimeAxisView* tav = axis_view_from_route (r);
1001 case Selection::Add:
1002 selection->add (tav);
1004 case Selection::Toggle:
1005 selection->toggle (tav);
1007 case Selection::Extend:
1009 case Selection::Set:
1010 selection->set (tav);
1014 selection->clear_tracks ();
1019 Editor::control_step_tracks_up ()
1021 scroll_tracks_up_line ();
1025 Editor::control_step_tracks_down ()
1027 scroll_tracks_down_line ();
1031 Editor::control_scroll (float fraction)
1033 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1039 double step = fraction * current_page_samples();
1042 _control_scroll_target is an optional<T>
1044 it acts like a pointer to an framepos_t, with
1045 a operator conversion to boolean to check
1046 that it has a value could possibly use
1047 playhead_cursor->current_frame to store the
1048 value and a boolean in the class to know
1049 when it's out of date
1052 if (!_control_scroll_target) {
1053 _control_scroll_target = _session->transport_frame();
1054 _dragging_playhead = true;
1057 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1058 *_control_scroll_target = 0;
1059 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1060 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1062 *_control_scroll_target += (framepos_t) floor (step);
1065 /* move visuals, we'll catch up with it later */
1067 playhead_cursor->set_position (*_control_scroll_target);
1068 UpdateAllTransportClocks (*_control_scroll_target);
1070 if (*_control_scroll_target > (current_page_samples() / 2)) {
1071 /* try to center PH in window */
1072 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1078 Now we do a timeout to actually bring the session to the right place
1079 according to the playhead. This is to avoid reading disk buffers on every
1080 call to control_scroll, which is driven by ScrollTimeline and therefore
1081 probably by a control surface wheel which can generate lots of events.
1083 /* cancel the existing timeout */
1085 control_scroll_connection.disconnect ();
1087 /* add the next timeout */
1089 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1093 Editor::deferred_control_scroll (framepos_t /*target*/)
1095 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1096 // reset for next stream
1097 _control_scroll_target = boost::none;
1098 _dragging_playhead = false;
1103 Editor::access_action (std::string action_group, std::string action_item)
1109 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1112 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1120 Editor::on_realize ()
1122 Window::on_realize ();
1125 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1126 start_lock_event_timing ();
1129 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1133 Editor::start_lock_event_timing ()
1135 /* check if we should lock the GUI every 30 seconds */
1137 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1141 Editor::generic_event_handler (GdkEvent* ev)
1144 case GDK_BUTTON_PRESS:
1145 case GDK_BUTTON_RELEASE:
1146 case GDK_MOTION_NOTIFY:
1148 case GDK_KEY_RELEASE:
1149 gettimeofday (&last_event_time, 0);
1158 Editor::lock_timeout_callback ()
1160 struct timeval now, delta;
1162 gettimeofday (&now, 0);
1164 timersub (&now, &last_event_time, &delta);
1166 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1168 /* don't call again. Returning false will effectively
1169 disconnect us from the timer callback.
1171 unlock() will call start_lock_event_timing() to get things
1181 Editor::map_position_change (framepos_t frame)
1183 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1185 if (_session == 0) {
1189 if (_follow_playhead) {
1190 center_screen (frame);
1193 playhead_cursor->set_position (frame);
1197 Editor::center_screen (framepos_t frame)
1199 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1201 /* if we're off the page, then scroll.
1204 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1205 center_screen_internal (frame, page);
1210 Editor::center_screen_internal (framepos_t frame, float page)
1215 frame -= (framepos_t) page;
1220 reset_x_origin (frame);
1225 Editor::update_title ()
1227 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1230 bool dirty = _session->dirty();
1232 string session_name;
1234 if (_session->snap_name() != _session->name()) {
1235 session_name = _session->snap_name();
1237 session_name = _session->name();
1241 session_name = "*" + session_name;
1244 WindowTitle title(session_name);
1245 title += Glib::get_application_name();
1246 set_title (title.get_string());
1248 /* ::session_going_away() will have taken care of it */
1253 Editor::set_session (Session *t)
1255 SessionHandlePtr::set_session (t);
1261 _playlist_selector->set_session (_session);
1262 nudge_clock->set_session (_session);
1263 _summary->set_session (_session);
1264 _group_tabs->set_session (_session);
1265 _route_groups->set_session (_session);
1266 _regions->set_session (_session);
1267 _snapshots->set_session (_session);
1268 _routes->set_session (_session);
1269 _locations->set_session (_session);
1271 if (rhythm_ferret) {
1272 rhythm_ferret->set_session (_session);
1275 if (analysis_window) {
1276 analysis_window->set_session (_session);
1280 sfbrowser->set_session (_session);
1283 compute_fixed_ruler_scale ();
1285 /* Make sure we have auto loop and auto punch ranges */
1287 Location* loc = _session->locations()->auto_loop_location();
1289 loc->set_name (_("Loop"));
1292 loc = _session->locations()->auto_punch_location();
1295 loc->set_name (_("Punch"));
1298 refresh_location_display ();
1300 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1301 the selected Marker; this needs the LocationMarker list to be available.
1303 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1304 set_state (*node, Stateful::loading_state_version);
1306 /* catch up with the playhead */
1308 _session->request_locate (playhead_cursor->current_frame ());
1309 _pending_initial_locate = true;
1313 /* These signals can all be emitted by a non-GUI thread. Therefore the
1314 handlers for them must not attempt to directly interact with the GUI,
1315 but use PBD::Signal<T>::connect() which accepts an event loop
1316 ("context") where the handler will be asked to run.
1319 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1320 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1321 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1322 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1323 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1324 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1325 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1326 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1327 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1328 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1329 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1330 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1331 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1332 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1334 playhead_cursor->show ();
1336 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1337 Config->map_parameters (pc);
1338 _session->config.map_parameters (pc);
1340 restore_ruler_visibility ();
1341 //tempo_map_changed (PropertyChange (0));
1342 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1344 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1345 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1348 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1349 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1352 switch (_snap_type) {
1353 case SnapToRegionStart:
1354 case SnapToRegionEnd:
1355 case SnapToRegionSync:
1356 case SnapToRegionBoundary:
1357 build_region_boundary_cache ();
1364 /* register for undo history */
1365 _session->register_with_memento_command_factory(id(), this);
1367 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1369 start_updating_meters ();
1373 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1375 if (a->get_name() == "RegionMenu") {
1376 /* When the main menu's region menu is opened, we setup the actions so that they look right
1377 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1378 so we resensitize all region actions when the entered regionview or the region selection
1379 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1380 happens after the region context menu is opened. So we set a flag here, too.
1384 sensitize_the_right_region_actions ();
1385 _last_region_menu_was_main = true;
1390 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1392 using namespace Menu_Helpers;
1394 void (Editor::*emf)(FadeShape);
1395 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1398 images = &_xfade_in_images;
1399 emf = &Editor::set_fade_in_shape;
1401 images = &_xfade_out_images;
1402 emf = &Editor::set_fade_out_shape;
1407 _("Linear (for highly correlated material)"),
1408 *(*images)[FadeLinear],
1409 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1417 _("Constant power"),
1418 *(*images)[FadeConstantPower],
1419 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1422 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1427 *(*images)[FadeSymmetric],
1428 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1432 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1437 *(*images)[FadeSlow],
1438 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1441 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1446 *(*images)[FadeFast],
1447 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1450 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1453 /** Pop up a context menu for when the user clicks on a start crossfade */
1455 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1457 using namespace Menu_Helpers;
1458 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1461 MenuList& items (xfade_in_context_menu.items());
1464 if (arv->audio_region()->fade_in_active()) {
1465 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1467 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1470 items.push_back (SeparatorElem());
1471 fill_xfade_menu (items, true);
1473 xfade_in_context_menu.popup (button, time);
1476 /** Pop up a context menu for when the user clicks on an end crossfade */
1478 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1480 using namespace Menu_Helpers;
1481 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1484 MenuList& items (xfade_out_context_menu.items());
1487 if (arv->audio_region()->fade_out_active()) {
1488 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1490 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1493 items.push_back (SeparatorElem());
1494 fill_xfade_menu (items, false);
1496 xfade_out_context_menu.popup (button, time);
1500 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1502 using namespace Menu_Helpers;
1503 Menu* (Editor::*build_menu_function)();
1506 switch (item_type) {
1508 case RegionViewName:
1509 case RegionViewNameHighlight:
1510 case LeftFrameHandle:
1511 case RightFrameHandle:
1512 if (with_selection) {
1513 build_menu_function = &Editor::build_track_selection_context_menu;
1515 build_menu_function = &Editor::build_track_region_context_menu;
1520 if (with_selection) {
1521 build_menu_function = &Editor::build_track_selection_context_menu;
1523 build_menu_function = &Editor::build_track_context_menu;
1528 if (clicked_routeview->track()) {
1529 build_menu_function = &Editor::build_track_context_menu;
1531 build_menu_function = &Editor::build_track_bus_context_menu;
1536 /* probably shouldn't happen but if it does, we don't care */
1540 menu = (this->*build_menu_function)();
1541 menu->set_name ("ArdourContextMenu");
1543 /* now handle specific situations */
1545 switch (item_type) {
1547 case RegionViewName:
1548 case RegionViewNameHighlight:
1549 case LeftFrameHandle:
1550 case RightFrameHandle:
1551 if (!with_selection) {
1552 if (region_edit_menu_split_item) {
1553 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1554 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1556 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1559 if (region_edit_menu_split_multichannel_item) {
1560 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1561 region_edit_menu_split_multichannel_item->set_sensitive (true);
1563 region_edit_menu_split_multichannel_item->set_sensitive (false);
1576 /* probably shouldn't happen but if it does, we don't care */
1580 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1582 /* Bounce to disk */
1584 using namespace Menu_Helpers;
1585 MenuList& edit_items = menu->items();
1587 edit_items.push_back (SeparatorElem());
1589 switch (clicked_routeview->audio_track()->freeze_state()) {
1590 case AudioTrack::NoFreeze:
1591 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1594 case AudioTrack::Frozen:
1595 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1598 case AudioTrack::UnFrozen:
1599 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1605 if (item_type == StreamItem && clicked_routeview) {
1606 clicked_routeview->build_underlay_menu(menu);
1609 /* When the region menu is opened, we setup the actions so that they look right
1612 sensitize_the_right_region_actions ();
1613 _last_region_menu_was_main = false;
1615 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1616 menu->popup (button, time);
1620 Editor::build_track_context_menu ()
1622 using namespace Menu_Helpers;
1624 MenuList& edit_items = track_context_menu.items();
1627 add_dstream_context_items (edit_items);
1628 return &track_context_menu;
1632 Editor::build_track_bus_context_menu ()
1634 using namespace Menu_Helpers;
1636 MenuList& edit_items = track_context_menu.items();
1639 add_bus_context_items (edit_items);
1640 return &track_context_menu;
1644 Editor::build_track_region_context_menu ()
1646 using namespace Menu_Helpers;
1647 MenuList& edit_items = track_region_context_menu.items();
1650 /* we've just cleared the track region context menu, so the menu that these
1651 two items were on will have disappeared; stop them dangling.
1653 region_edit_menu_split_item = 0;
1654 region_edit_menu_split_multichannel_item = 0;
1656 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1659 boost::shared_ptr<Track> tr;
1660 boost::shared_ptr<Playlist> pl;
1662 if ((tr = rtv->track())) {
1663 add_region_context_items (edit_items, tr);
1667 add_dstream_context_items (edit_items);
1669 return &track_region_context_menu;
1673 Editor::analyze_region_selection ()
1675 if (analysis_window == 0) {
1676 analysis_window = new AnalysisWindow();
1679 analysis_window->set_session(_session);
1681 analysis_window->show_all();
1684 analysis_window->set_regionmode();
1685 analysis_window->analyze();
1687 analysis_window->present();
1691 Editor::analyze_range_selection()
1693 if (analysis_window == 0) {
1694 analysis_window = new AnalysisWindow();
1697 analysis_window->set_session(_session);
1699 analysis_window->show_all();
1702 analysis_window->set_rangemode();
1703 analysis_window->analyze();
1705 analysis_window->present();
1709 Editor::build_track_selection_context_menu ()
1711 using namespace Menu_Helpers;
1712 MenuList& edit_items = track_selection_context_menu.items();
1713 edit_items.clear ();
1715 add_selection_context_items (edit_items);
1716 // edit_items.push_back (SeparatorElem());
1717 // add_dstream_context_items (edit_items);
1719 return &track_selection_context_menu;
1723 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1725 using namespace Menu_Helpers;
1727 /* OK, stick the region submenu at the top of the list, and then add
1731 RegionSelection rs = get_regions_from_selection_and_entered ();
1733 string::size_type pos = 0;
1734 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1736 /* we have to hack up the region name because "_" has a special
1737 meaning for menu titles.
1740 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1741 menu_item_name.replace (pos, 1, "__");
1745 if (_popup_region_menu_item == 0) {
1746 _popup_region_menu_item = new MenuItem (menu_item_name);
1747 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1748 _popup_region_menu_item->show ();
1750 _popup_region_menu_item->set_label (menu_item_name);
1753 const framepos_t position = get_preferred_edit_position (false, true);
1755 edit_items.push_back (*_popup_region_menu_item);
1756 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1757 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1759 edit_items.push_back (SeparatorElem());
1762 /** Add context menu items relevant to selection ranges.
1763 * @param edit_items List to add the items to.
1766 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1768 using namespace Menu_Helpers;
1770 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1771 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1773 edit_items.push_back (SeparatorElem());
1774 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1776 edit_items.push_back (SeparatorElem());
1777 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1779 edit_items.push_back (SeparatorElem());
1781 edit_items.push_back (
1783 _("Move Range Start to Previous Region Boundary"),
1784 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1788 edit_items.push_back (
1790 _("Move Range Start to Next Region Boundary"),
1791 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1795 edit_items.push_back (
1797 _("Move Range End to Previous Region Boundary"),
1798 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1802 edit_items.push_back (
1804 _("Move Range End to Next Region Boundary"),
1805 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1809 edit_items.push_back (SeparatorElem());
1810 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1811 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1813 edit_items.push_back (SeparatorElem());
1814 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1816 edit_items.push_back (SeparatorElem());
1817 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1818 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1820 edit_items.push_back (SeparatorElem());
1821 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1823 edit_items.push_back (SeparatorElem());
1824 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1825 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1826 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1828 edit_items.push_back (SeparatorElem());
1829 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1830 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1831 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1832 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1833 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1834 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1835 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1841 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1843 using namespace Menu_Helpers;
1847 Menu *play_menu = manage (new Menu);
1848 MenuList& play_items = play_menu->items();
1849 play_menu->set_name ("ArdourContextMenu");
1851 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1852 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1853 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1854 play_items.push_back (SeparatorElem());
1855 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1857 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1861 Menu *select_menu = manage (new Menu);
1862 MenuList& select_items = select_menu->items();
1863 select_menu->set_name ("ArdourContextMenu");
1865 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1866 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1867 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1868 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1869 select_items.push_back (SeparatorElem());
1870 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1871 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1872 select_items.push_back (SeparatorElem());
1873 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1874 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1875 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1876 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1877 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1878 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1879 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1881 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1885 Menu *cutnpaste_menu = manage (new Menu);
1886 MenuList& cutnpaste_items = cutnpaste_menu->items();
1887 cutnpaste_menu->set_name ("ArdourContextMenu");
1889 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1890 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1891 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1893 cutnpaste_items.push_back (SeparatorElem());
1895 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1896 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1898 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1900 /* Adding new material */
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1904 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1908 Menu *nudge_menu = manage (new Menu());
1909 MenuList& nudge_items = nudge_menu->items();
1910 nudge_menu->set_name ("ArdourContextMenu");
1912 edit_items.push_back (SeparatorElem());
1913 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1914 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1915 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1916 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1918 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1922 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1924 using namespace Menu_Helpers;
1928 Menu *play_menu = manage (new Menu);
1929 MenuList& play_items = play_menu->items();
1930 play_menu->set_name ("ArdourContextMenu");
1932 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1933 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1934 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1938 Menu *select_menu = manage (new Menu);
1939 MenuList& select_items = select_menu->items();
1940 select_menu->set_name ("ArdourContextMenu");
1942 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1943 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1944 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1945 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1946 select_items.push_back (SeparatorElem());
1947 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1948 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1949 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1950 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1952 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1956 Menu *cutnpaste_menu = manage (new Menu);
1957 MenuList& cutnpaste_items = cutnpaste_menu->items();
1958 cutnpaste_menu->set_name ("ArdourContextMenu");
1960 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1961 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1962 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1964 Menu *nudge_menu = manage (new Menu());
1965 MenuList& nudge_items = nudge_menu->items();
1966 nudge_menu->set_name ("ArdourContextMenu");
1968 edit_items.push_back (SeparatorElem());
1969 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1970 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1971 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1972 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1974 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1978 Editor::snap_type() const
1984 Editor::snap_mode() const
1990 Editor::set_snap_to (SnapType st)
1992 unsigned int snap_ind = (unsigned int)st;
1996 if (snap_ind > snap_type_strings.size() - 1) {
1998 _snap_type = (SnapType)snap_ind;
2001 string str = snap_type_strings[snap_ind];
2003 if (str != snap_type_selector.get_text()) {
2004 snap_type_selector.set_text (str);
2009 switch (_snap_type) {
2010 case SnapToBeatDiv128:
2011 case SnapToBeatDiv64:
2012 case SnapToBeatDiv32:
2013 case SnapToBeatDiv28:
2014 case SnapToBeatDiv24:
2015 case SnapToBeatDiv20:
2016 case SnapToBeatDiv16:
2017 case SnapToBeatDiv14:
2018 case SnapToBeatDiv12:
2019 case SnapToBeatDiv10:
2020 case SnapToBeatDiv8:
2021 case SnapToBeatDiv7:
2022 case SnapToBeatDiv6:
2023 case SnapToBeatDiv5:
2024 case SnapToBeatDiv4:
2025 case SnapToBeatDiv3:
2026 case SnapToBeatDiv2: {
2027 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2028 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2030 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2031 current_bbt_points_begin, current_bbt_points_end);
2032 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2033 current_bbt_points_begin, current_bbt_points_end);
2034 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2038 case SnapToRegionStart:
2039 case SnapToRegionEnd:
2040 case SnapToRegionSync:
2041 case SnapToRegionBoundary:
2042 build_region_boundary_cache ();
2050 SnapChanged (); /* EMIT SIGNAL */
2054 Editor::set_snap_mode (SnapMode mode)
2056 string str = snap_mode_strings[(int)mode];
2058 if (_internal_editing) {
2059 internal_snap_mode = mode;
2061 pre_internal_snap_mode = mode;
2066 if (str != snap_mode_selector.get_text ()) {
2067 snap_mode_selector.set_text (str);
2073 Editor::set_edit_point_preference (EditPoint ep, bool force)
2075 bool changed = (_edit_point != ep);
2078 string str = edit_point_strings[(int)ep];
2080 if (Profile->get_mixbus())
2081 if (ep == EditAtSelectedMarker)
2082 ep = EditAtPlayhead;
2084 if (str != edit_point_selector.get_text ()) {
2085 edit_point_selector.set_text (str);
2088 reset_canvas_cursor ();
2090 if (!force && !changed) {
2094 const char* action=NULL;
2096 switch (_edit_point) {
2097 case EditAtPlayhead:
2098 action = "edit-at-playhead";
2100 case EditAtSelectedMarker:
2101 action = "edit-at-marker";
2104 action = "edit-at-mouse";
2108 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2110 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2114 bool in_track_canvas;
2116 if (!mouse_frame (foo, in_track_canvas)) {
2117 in_track_canvas = false;
2120 reset_canvas_action_sensitivity (in_track_canvas);
2126 Editor::set_state (const XMLNode& node, int /*version*/)
2128 const XMLProperty* prop;
2135 g.base_width = default_width;
2136 g.base_height = default_height;
2140 if ((geometry = find_named_node (node, "geometry")) != 0) {
2144 if ((prop = geometry->property("x_size")) == 0) {
2145 prop = geometry->property ("x-size");
2148 g.base_width = atoi(prop->value());
2150 if ((prop = geometry->property("y_size")) == 0) {
2151 prop = geometry->property ("y-size");
2154 g.base_height = atoi(prop->value());
2157 if ((prop = geometry->property ("x_pos")) == 0) {
2158 prop = geometry->property ("x-pos");
2161 x = atoi (prop->value());
2164 if ((prop = geometry->property ("y_pos")) == 0) {
2165 prop = geometry->property ("y-pos");
2168 y = atoi (prop->value());
2172 set_default_size (g.base_width, g.base_height);
2175 if (_session && (prop = node.property ("playhead"))) {
2177 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2178 playhead_cursor->set_position (pos);
2180 playhead_cursor->set_position (0);
2183 if ((prop = node.property ("mixer-width"))) {
2184 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2187 if ((prop = node.property ("zoom-focus"))) {
2188 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2191 if ((prop = node.property ("zoom"))) {
2192 /* older versions of ardour used floating point samples_per_pixel */
2193 double f = PBD::atof (prop->value());
2194 reset_zoom (llrintf (f));
2196 reset_zoom (samples_per_pixel);
2199 if ((prop = node.property ("visible-track-count"))) {
2200 set_visible_track_count (PBD::atoi (prop->value()));
2203 if ((prop = node.property ("snap-to"))) {
2204 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2207 if ((prop = node.property ("snap-mode"))) {
2208 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2211 if ((prop = node.property ("internal-snap-to"))) {
2212 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2215 if ((prop = node.property ("internal-snap-mode"))) {
2216 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2219 if ((prop = node.property ("pre-internal-snap-to"))) {
2220 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2224 if ((prop = node.property ("pre-internal-snap-mode"))) {
2225 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2228 if ((prop = node.property ("mouse-mode"))) {
2229 MouseMode m = str2mousemode(prop->value());
2230 set_mouse_mode (m, true);
2232 set_mouse_mode (MouseObject, true);
2235 if ((prop = node.property ("left-frame")) != 0) {
2237 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2241 reset_x_origin (pos);
2245 if ((prop = node.property ("y-origin")) != 0) {
2246 reset_y_origin (atof (prop->value ()));
2249 if ((prop = node.property ("internal-edit"))) {
2250 bool yn = string_is_affirmative (prop->value());
2251 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2253 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2254 tact->set_active (!yn);
2255 tact->set_active (yn);
2259 if ((prop = node.property ("join-object-range"))) {
2260 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2261 bool yn = string_is_affirmative (prop->value());
2263 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2264 tact->set_active (!yn);
2265 tact->set_active (yn);
2267 set_mouse_mode(mouse_mode, true);
2270 if ((prop = node.property ("edit-point"))) {
2271 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2274 if ((prop = node.property ("show-measures"))) {
2275 bool yn = string_is_affirmative (prop->value());
2276 _show_measures = yn;
2277 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2279 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2280 /* do it twice to force the change */
2281 tact->set_active (!yn);
2282 tact->set_active (yn);
2286 if ((prop = node.property ("follow-playhead"))) {
2287 bool yn = string_is_affirmative (prop->value());
2288 set_follow_playhead (yn);
2289 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2291 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2292 if (tact->get_active() != yn) {
2293 tact->set_active (yn);
2298 if ((prop = node.property ("stationary-playhead"))) {
2299 bool yn = string_is_affirmative (prop->value());
2300 set_stationary_playhead (yn);
2301 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2303 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2304 if (tact->get_active() != yn) {
2305 tact->set_active (yn);
2310 if ((prop = node.property ("region-list-sort-type"))) {
2311 RegionListSortType st;
2312 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2315 if ((prop = node.property ("show-editor-mixer"))) {
2317 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2320 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2321 bool yn = string_is_affirmative (prop->value());
2323 /* do it twice to force the change */
2325 tact->set_active (!yn);
2326 tact->set_active (yn);
2329 if ((prop = node.property ("show-editor-list"))) {
2331 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2334 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2335 bool yn = string_is_affirmative (prop->value());
2337 /* do it twice to force the change */
2339 tact->set_active (!yn);
2340 tact->set_active (yn);
2343 if ((prop = node.property (X_("editor-list-page")))) {
2344 _the_notebook.set_current_page (atoi (prop->value ()));
2347 if ((prop = node.property (X_("show-marker-lines")))) {
2348 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2350 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2351 bool yn = string_is_affirmative (prop->value ());
2353 tact->set_active (!yn);
2354 tact->set_active (yn);
2357 XMLNodeList children = node.children ();
2358 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2359 selection->set_state (**i, Stateful::current_state_version);
2360 _regions->set_state (**i);
2363 if ((prop = node.property ("maximised"))) {
2364 bool yn = string_is_affirmative (prop->value());
2365 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2367 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2368 bool fs = tact && tact->get_active();
2370 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2374 if ((prop = node.property ("nudge-clock-value"))) {
2376 sscanf (prop->value().c_str(), "%" PRId64, &f);
2377 nudge_clock->set (f);
2379 nudge_clock->set_mode (AudioClock::Timecode);
2380 nudge_clock->set (_session->frame_rate() * 5, true);
2387 Editor::get_state ()
2389 XMLNode* node = new XMLNode ("Editor");
2392 id().print (buf, sizeof (buf));
2393 node->add_property ("id", buf);
2395 if (is_realized()) {
2396 Glib::RefPtr<Gdk::Window> win = get_window();
2398 int x, y, width, height;
2399 win->get_root_origin(x, y);
2400 win->get_size(width, height);
2402 XMLNode* geometry = new XMLNode ("geometry");
2404 snprintf(buf, sizeof(buf), "%d", width);
2405 geometry->add_property("x-size", string(buf));
2406 snprintf(buf, sizeof(buf), "%d", height);
2407 geometry->add_property("y-size", string(buf));
2408 snprintf(buf, sizeof(buf), "%d", x);
2409 geometry->add_property("x-pos", string(buf));
2410 snprintf(buf, sizeof(buf), "%d", y);
2411 geometry->add_property("y-pos", string(buf));
2412 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2413 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2414 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2415 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2416 geometry->add_property("edit-vertical-pane-pos", string(buf));
2418 node->add_child_nocopy (*geometry);
2421 maybe_add_mixer_strip_width (*node);
2423 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2425 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2426 node->add_property ("zoom", buf);
2427 node->add_property ("snap-to", enum_2_string (_snap_type));
2428 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2429 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2430 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2431 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2432 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2433 node->add_property ("edit-point", enum_2_string (_edit_point));
2434 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2435 node->add_property ("visible-track-count", buf);
2437 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2438 node->add_property ("playhead", buf);
2439 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2440 node->add_property ("left-frame", buf);
2441 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2442 node->add_property ("y-origin", buf);
2444 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2445 node->add_property ("maximised", _maximised ? "yes" : "no");
2446 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2447 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2448 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2449 node->add_property ("mouse-mode", enum2str(mouse_mode));
2450 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2451 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2453 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2455 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2456 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2459 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2461 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2462 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2465 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2466 node->add_property (X_("editor-list-page"), buf);
2468 if (button_bindings) {
2469 XMLNode* bb = new XMLNode (X_("Buttons"));
2470 button_bindings->save (*bb);
2471 node->add_child_nocopy (*bb);
2474 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2476 node->add_child_nocopy (selection->get_state ());
2477 node->add_child_nocopy (_regions->get_state ());
2479 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2480 node->add_property ("nudge-clock-value", buf);
2485 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2486 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2488 * @return pair: TimeAxisView that y is over, layer index.
2490 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2491 * in stacked or expanded region display mode, otherwise 0.
2493 std::pair<TimeAxisView *, double>
2494 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2496 if (!trackview_relative_offset) {
2497 y -= _trackview_group->canvas_origin().y;
2501 return std::make_pair ( (TimeAxisView *) 0, 0);
2504 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2506 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2513 return std::make_pair ( (TimeAxisView *) 0, 0);
2516 /** Snap a position to the grid, if appropriate, taking into account current
2517 * grid settings and also the state of any snap modifier keys that may be pressed.
2518 * @param start Position to snap.
2519 * @param event Event to get current key modifier information from, or 0.
2522 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2524 if (!_session || !event) {
2528 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2529 if (_snap_mode == SnapOff) {
2530 snap_to_internal (start, direction, for_mark);
2533 if (_snap_mode != SnapOff) {
2534 snap_to_internal (start, direction, for_mark);
2540 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2542 if (!_session || _snap_mode == SnapOff) {
2546 snap_to_internal (start, direction, for_mark);
2550 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2552 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2553 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2555 switch (_snap_type) {
2556 case SnapToTimecodeFrame:
2557 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 == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2571 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2573 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2576 if (_session->config.get_timecode_offset_negative()) {
2577 start -= _session->config.get_timecode_offset ();
2579 start += _session->config.get_timecode_offset ();
2583 case SnapToTimecodeMinutes:
2584 if (_session->config.get_timecode_offset_negative()) {
2585 start += _session->config.get_timecode_offset ();
2587 start -= _session->config.get_timecode_offset ();
2589 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2590 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2592 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2594 if (_session->config.get_timecode_offset_negative()) {
2595 start -= _session->config.get_timecode_offset ();
2597 start += _session->config.get_timecode_offset ();
2601 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2607 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2609 const framepos_t one_second = _session->frame_rate();
2610 const framepos_t one_minute = _session->frame_rate() * 60;
2611 framepos_t presnap = start;
2615 switch (_snap_type) {
2616 case SnapToTimecodeFrame:
2617 case SnapToTimecodeSeconds:
2618 case SnapToTimecodeMinutes:
2619 return timecode_snap_to_internal (start, direction, for_mark);
2622 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2623 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2625 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2630 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2631 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2633 start = (framepos_t) floor ((double) start / one_second) * one_second;
2638 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2639 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2641 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2646 start = _session->tempo_map().round_to_bar (start, direction);
2650 start = _session->tempo_map().round_to_beat (start, direction);
2653 case SnapToBeatDiv128:
2654 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2656 case SnapToBeatDiv64:
2657 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2659 case SnapToBeatDiv32:
2660 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2662 case SnapToBeatDiv28:
2663 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2665 case SnapToBeatDiv24:
2666 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2668 case SnapToBeatDiv20:
2669 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2671 case SnapToBeatDiv16:
2672 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2674 case SnapToBeatDiv14:
2675 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2677 case SnapToBeatDiv12:
2678 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2680 case SnapToBeatDiv10:
2681 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2683 case SnapToBeatDiv8:
2684 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2686 case SnapToBeatDiv7:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2689 case SnapToBeatDiv6:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2692 case SnapToBeatDiv5:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2695 case SnapToBeatDiv4:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2698 case SnapToBeatDiv3:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2701 case SnapToBeatDiv2:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2710 _session->locations()->marks_either_side (start, before, after);
2712 if (before == max_framepos && after == max_framepos) {
2713 /* No marks to snap to, so just don't snap */
2715 } else if (before == max_framepos) {
2717 } else if (after == max_framepos) {
2719 } else if (before != max_framepos && after != max_framepos) {
2720 /* have before and after */
2721 if ((start - before) < (after - start)) {
2730 case SnapToRegionStart:
2731 case SnapToRegionEnd:
2732 case SnapToRegionSync:
2733 case SnapToRegionBoundary:
2734 if (!region_boundary_cache.empty()) {
2736 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2737 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2739 if (direction > 0) {
2740 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2742 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2745 if (next != region_boundary_cache.begin ()) {
2750 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2751 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2753 if (start > (p + n) / 2) {
2762 switch (_snap_mode) {
2768 if (presnap > start) {
2769 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2773 } else if (presnap < start) {
2774 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2780 /* handled at entry */
2788 Editor::setup_toolbar ()
2790 HBox* mode_box = manage(new HBox);
2791 mode_box->set_border_width (2);
2792 mode_box->set_spacing(2);
2794 HBox* mouse_mode_box = manage (new HBox);
2795 HBox* mouse_mode_hbox = manage (new HBox);
2796 VBox* mouse_mode_vbox = manage (new VBox);
2797 Alignment* mouse_mode_align = manage (new Alignment);
2799 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2800 mouse_mode_size_group->add_widget (smart_mode_button);
2801 mouse_mode_size_group->add_widget (mouse_move_button);
2802 mouse_mode_size_group->add_widget (mouse_cut_button);
2803 mouse_mode_size_group->add_widget (mouse_select_button);
2804 mouse_mode_size_group->add_widget (mouse_zoom_button);
2805 mouse_mode_size_group->add_widget (mouse_gain_button);
2806 mouse_mode_size_group->add_widget (mouse_timefx_button);
2807 mouse_mode_size_group->add_widget (mouse_audition_button);
2808 mouse_mode_size_group->add_widget (mouse_draw_button);
2809 mouse_mode_size_group->add_widget (internal_edit_button);
2811 mouse_mode_size_group->add_widget (zoom_in_button);
2812 mouse_mode_size_group->add_widget (zoom_out_button);
2813 mouse_mode_size_group->add_widget (zoom_preset_selector);
2814 mouse_mode_size_group->add_widget (zoom_out_full_button);
2815 mouse_mode_size_group->add_widget (zoom_focus_selector);
2817 mouse_mode_size_group->add_widget (tav_shrink_button);
2818 mouse_mode_size_group->add_widget (tav_expand_button);
2819 mouse_mode_size_group->add_widget (visible_tracks_selector);
2821 mouse_mode_size_group->add_widget (snap_type_selector);
2822 mouse_mode_size_group->add_widget (snap_mode_selector);
2824 mouse_mode_size_group->add_widget (edit_point_selector);
2825 mouse_mode_size_group->add_widget (edit_mode_selector);
2827 mouse_mode_size_group->add_widget (*nudge_clock);
2828 mouse_mode_size_group->add_widget (nudge_forward_button);
2829 mouse_mode_size_group->add_widget (nudge_backward_button);
2831 mouse_mode_hbox->set_spacing (2);
2833 if (!ARDOUR::Profile->get_trx()) {
2834 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2837 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2838 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2840 if (!ARDOUR::Profile->get_mixbus()) {
2841 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2842 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2845 if (!ARDOUR::Profile->get_trx()) {
2846 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2847 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2848 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2849 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2850 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2853 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2855 mouse_mode_align->add (*mouse_mode_vbox);
2856 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2858 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2860 edit_mode_selector.set_name ("mouse mode button");
2862 if (!ARDOUR::Profile->get_trx()) {
2863 mode_box->pack_start (edit_mode_selector, false, false);
2865 mode_box->pack_start (*mouse_mode_box, false, false);
2867 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2868 _mouse_mode_tearoff->set_name ("MouseModeBase");
2869 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2871 if (Profile->get_sae() || Profile->get_mixbus() ) {
2872 _mouse_mode_tearoff->set_can_be_torn_off (false);
2875 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2876 &_mouse_mode_tearoff->tearoff_window()));
2877 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2878 &_mouse_mode_tearoff->tearoff_window(), 1));
2879 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2880 &_mouse_mode_tearoff->tearoff_window()));
2881 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2882 &_mouse_mode_tearoff->tearoff_window(), 1));
2886 _zoom_box.set_spacing (2);
2887 _zoom_box.set_border_width (2);
2891 zoom_preset_selector.set_name ("zoom button");
2892 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2893 zoom_preset_selector.set_size_request (42, -1);
2895 zoom_in_button.set_name ("zoom button");
2896 zoom_in_button.set_image(::get_icon ("zoom_in"));
2897 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2898 zoom_in_button.set_related_action (act);
2900 zoom_out_button.set_name ("zoom button");
2901 zoom_out_button.set_image(::get_icon ("zoom_out"));
2902 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2903 zoom_out_button.set_related_action (act);
2905 zoom_out_full_button.set_name ("zoom button");
2906 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2907 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2908 zoom_out_full_button.set_related_action (act);
2910 zoom_focus_selector.set_name ("zoom button");
2912 if (ARDOUR::Profile->get_mixbus()) {
2913 _zoom_box.pack_start (zoom_preset_selector, false, false);
2914 } else if (ARDOUR::Profile->get_trx()) {
2915 mode_box->pack_start (zoom_out_button, false, false);
2916 mode_box->pack_start (zoom_in_button, false, false);
2918 _zoom_box.pack_start (zoom_out_button, false, false);
2919 _zoom_box.pack_start (zoom_in_button, false, false);
2920 _zoom_box.pack_start (zoom_out_full_button, false, false);
2921 _zoom_box.pack_start (zoom_focus_selector, false, false);
2924 /* Track zoom buttons */
2925 visible_tracks_selector.set_name ("zoom button");
2926 if (Profile->get_mixbus()) {
2927 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2928 visible_tracks_selector.set_size_request (42, -1);
2930 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2933 tav_expand_button.set_name ("zoom button");
2934 tav_expand_button.set_image(::get_icon ("tav_exp"));
2935 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2936 tav_expand_button.set_related_action (act);
2938 tav_shrink_button.set_name ("zoom button");
2939 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2940 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2941 tav_shrink_button.set_related_action (act);
2943 if (ARDOUR::Profile->get_mixbus()) {
2944 _zoom_box.pack_start (visible_tracks_selector);
2945 } else if (ARDOUR::Profile->get_trx()) {
2946 _zoom_box.pack_start (tav_shrink_button);
2947 _zoom_box.pack_start (tav_expand_button);
2949 _zoom_box.pack_start (visible_tracks_selector);
2950 _zoom_box.pack_start (tav_shrink_button);
2951 _zoom_box.pack_start (tav_expand_button);
2954 if (!ARDOUR::Profile->get_trx()) {
2955 _zoom_tearoff = manage (new TearOff (_zoom_box));
2957 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2958 &_zoom_tearoff->tearoff_window()));
2959 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2960 &_zoom_tearoff->tearoff_window(), 0));
2961 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2962 &_zoom_tearoff->tearoff_window()));
2963 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2964 &_zoom_tearoff->tearoff_window(), 0));
2967 if (Profile->get_sae() || Profile->get_mixbus() ) {
2968 _zoom_tearoff->set_can_be_torn_off (false);
2971 snap_box.set_spacing (2);
2972 snap_box.set_border_width (2);
2974 snap_type_selector.set_name ("mouse mode button");
2976 snap_mode_selector.set_name ("mouse mode button");
2978 edit_point_selector.set_name ("mouse mode button");
2980 snap_box.pack_start (snap_mode_selector, false, false);
2981 snap_box.pack_start (snap_type_selector, false, false);
2982 snap_box.pack_start (edit_point_selector, false, false);
2986 HBox *nudge_box = manage (new HBox);
2987 nudge_box->set_spacing (2);
2988 nudge_box->set_border_width (2);
2990 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2991 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2993 nudge_box->pack_start (nudge_backward_button, false, false);
2994 nudge_box->pack_start (nudge_forward_button, false, false);
2995 nudge_box->pack_start (*nudge_clock, false, false);
2998 /* Pack everything in... */
3000 HBox* hbox = manage (new HBox);
3001 hbox->set_spacing(2);
3003 _tools_tearoff = manage (new TearOff (*hbox));
3004 _tools_tearoff->set_name ("MouseModeBase");
3005 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3007 if (Profile->get_sae() || Profile->get_mixbus()) {
3008 _tools_tearoff->set_can_be_torn_off (false);
3011 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3012 &_tools_tearoff->tearoff_window()));
3013 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3014 &_tools_tearoff->tearoff_window(), 0));
3015 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3016 &_tools_tearoff->tearoff_window()));
3017 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3018 &_tools_tearoff->tearoff_window(), 0));
3020 toolbar_hbox.set_spacing (2);
3021 toolbar_hbox.set_border_width (1);
3023 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3024 if (!ARDOUR::Profile->get_trx()) {
3025 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3026 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3029 if (!ARDOUR::Profile->get_trx()) {
3030 hbox->pack_start (snap_box, false, false);
3031 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3032 hbox->pack_start (*nudge_box, false, false);
3034 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3037 hbox->pack_start (panic_box, false, false);
3041 toolbar_base.set_name ("ToolBarBase");
3042 toolbar_base.add (toolbar_hbox);
3044 _toolbar_viewport.add (toolbar_base);
3045 /* stick to the required height but allow width to vary if there's not enough room */
3046 _toolbar_viewport.set_size_request (1, -1);
3048 toolbar_frame.set_shadow_type (SHADOW_OUT);
3049 toolbar_frame.set_name ("BaseFrame");
3050 toolbar_frame.add (_toolbar_viewport);
3054 Editor::build_edit_point_menu ()
3056 using namespace Menu_Helpers;
3058 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3059 if(!Profile->get_mixbus())
3060 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3061 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3063 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3067 Editor::build_edit_mode_menu ()
3069 using namespace Menu_Helpers;
3071 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3072 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3073 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3074 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3076 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3080 Editor::build_snap_mode_menu ()
3082 using namespace Menu_Helpers;
3084 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3085 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3086 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3088 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3092 Editor::build_snap_type_menu ()
3094 using namespace Menu_Helpers;
3096 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3097 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3098 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3099 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3100 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3101 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3102 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3103 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3104 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3105 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3106 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3107 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3108 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3109 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3110 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3111 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3112 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3113 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3114 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3115 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3116 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3117 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3118 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3119 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3120 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3121 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3122 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3123 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3124 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3125 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3127 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3132 Editor::setup_tooltips ()
3134 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3135 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3136 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3137 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3138 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3139 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3140 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3141 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3142 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3143 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3144 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3145 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3146 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3147 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3148 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3149 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3150 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3151 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3152 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3153 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3154 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3155 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3156 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3157 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3158 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3159 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3163 Editor::convert_drop_to_paths (
3164 vector<string>& paths,
3165 const RefPtr<Gdk::DragContext>& /*context*/,
3168 const SelectionData& data,
3172 if (_session == 0) {
3176 vector<string> uris = data.get_uris();
3180 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3181 are actually URI lists. So do it by hand.
3184 if (data.get_target() != "text/plain") {
3188 /* Parse the "uri-list" format that Nautilus provides,
3189 where each pathname is delimited by \r\n.
3191 THERE MAY BE NO NULL TERMINATING CHAR!!!
3194 string txt = data.get_text();
3198 p = (char *) malloc (txt.length() + 1);
3199 txt.copy (p, txt.length(), 0);
3200 p[txt.length()] = '\0';
3206 while (g_ascii_isspace (*p))
3210 while (*q && (*q != '\n') && (*q != '\r')) {
3217 while (q > p && g_ascii_isspace (*q))
3222 uris.push_back (string (p, q - p + 1));
3226 p = strchr (p, '\n');
3238 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3239 if ((*i).substr (0,7) == "file://") {
3240 paths.push_back (Glib::filename_from_uri (*i));
3248 Editor::new_tempo_section ()
3253 Editor::map_transport_state ()
3255 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3257 if (_session && _session->transport_stopped()) {
3258 have_pending_keyboard_selection = false;
3261 update_loop_range_view ();
3267 Editor::begin_reversible_command (string name)
3270 _session->begin_reversible_command (name);
3275 Editor::begin_reversible_command (GQuark q)
3278 _session->begin_reversible_command (q);
3283 Editor::commit_reversible_command ()
3286 _session->commit_reversible_command ();
3291 Editor::history_changed ()
3295 if (undo_action && _session) {
3296 if (_session->undo_depth() == 0) {
3297 label = S_("Command|Undo");
3299 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3301 undo_action->property_label() = label;
3304 if (redo_action && _session) {
3305 if (_session->redo_depth() == 0) {
3308 label = string_compose(_("Redo (%1)"), _session->next_redo());
3310 redo_action->property_label() = label;
3315 Editor::duplicate_range (bool with_dialog)
3319 RegionSelection rs = get_regions_from_selection_and_entered ();
3321 if ( selection->time.length() == 0 && rs.empty()) {
3327 ArdourDialog win (_("Duplicate"));
3328 Label label (_("Number of duplications:"));
3329 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3330 SpinButton spinner (adjustment, 0.0, 1);
3333 win.get_vbox()->set_spacing (12);
3334 win.get_vbox()->pack_start (hbox);
3335 hbox.set_border_width (6);
3336 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3338 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3339 place, visually. so do this by hand.
3342 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3343 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3344 spinner.grab_focus();
3350 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3351 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3352 win.set_default_response (RESPONSE_ACCEPT);
3354 spinner.grab_focus ();
3356 switch (win.run ()) {
3357 case RESPONSE_ACCEPT:
3363 times = adjustment.get_value();
3366 if ((current_mouse_mode() == Editing::MouseRange)) {
3367 if (selection->time.length()) {
3368 duplicate_selection (times);
3370 } else if (get_smart_mode()) {
3371 if (selection->time.length()) {
3372 duplicate_selection (times);
3374 duplicate_some_regions (rs, times);
3376 duplicate_some_regions (rs, times);
3381 Editor::set_edit_mode (EditMode m)
3383 Config->set_edit_mode (m);
3387 Editor::cycle_edit_mode ()
3389 switch (Config->get_edit_mode()) {
3391 if (Profile->get_sae()) {
3392 Config->set_edit_mode (Lock);
3394 Config->set_edit_mode (Ripple);
3399 Config->set_edit_mode (Lock);
3402 Config->set_edit_mode (Slide);
3408 Editor::edit_mode_selection_done ( EditMode m )
3410 Config->set_edit_mode ( m );
3414 Editor::snap_type_selection_done (SnapType snaptype)
3416 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3418 ract->set_active ();
3423 Editor::snap_mode_selection_done (SnapMode mode)
3425 RefPtr<RadioAction> ract = snap_mode_action (mode);
3428 ract->set_active (true);
3433 Editor::cycle_edit_point (bool with_marker)
3435 if(Profile->get_mixbus())
3436 with_marker = false;
3438 switch (_edit_point) {
3440 set_edit_point_preference (EditAtPlayhead);
3442 case EditAtPlayhead:
3444 set_edit_point_preference (EditAtSelectedMarker);
3446 set_edit_point_preference (EditAtMouse);
3449 case EditAtSelectedMarker:
3450 set_edit_point_preference (EditAtMouse);
3456 Editor::edit_point_selection_done (EditPoint ep)
3458 set_edit_point_preference ( ep );
3462 Editor::build_zoom_focus_menu ()
3464 using namespace Menu_Helpers;
3466 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3467 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3468 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3469 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3470 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3471 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3473 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3477 Editor::zoom_focus_selection_done ( ZoomFocus f )
3479 RefPtr<RadioAction> ract = zoom_focus_action (f);
3481 ract->set_active ();
3486 Editor::build_track_count_menu ()
3488 using namespace Menu_Helpers;
3490 if (!Profile->get_mixbus()) {
3491 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3492 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3493 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3494 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3495 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3496 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3497 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3498 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3499 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3500 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3501 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3502 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3503 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3505 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3506 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3507 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3508 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3509 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3510 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3511 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3512 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3513 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3514 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3516 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3517 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3518 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3519 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3520 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3521 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3522 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3523 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3524 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3525 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3526 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3531 Editor::set_zoom_preset (int64_t ms)
3534 temporal_zoom_session();
3538 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3539 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3543 Editor::set_visible_track_count (int32_t n)
3545 _visible_track_count = n;
3547 /* if the canvas hasn't really been allocated any size yet, just
3548 record the desired number of visible tracks and return. when canvas
3549 allocation happens, we will get called again and then we can do the
3553 if (_visible_canvas_height <= 1) {
3560 if (_visible_track_count > 0) {
3561 h = trackviews_height() / _visible_track_count;
3562 std::ostringstream s;
3563 s << _visible_track_count;
3565 } else if (_visible_track_count == 0) {
3567 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3568 if ((*i)->marked_for_display()) {
3572 h = trackviews_height() / n;
3575 /* negative value means that the visible track count has
3576 been overridden by explicit track height changes.
3578 visible_tracks_selector.set_text (X_("*"));
3582 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3583 (*i)->set_height (h);
3586 if (str != visible_tracks_selector.get_text()) {
3587 visible_tracks_selector.set_text (str);
3592 Editor::override_visible_track_count ()
3594 _visible_track_count = -_visible_track_count;
3595 visible_tracks_selector.set_text ( _("*") );
3599 Editor::edit_controls_button_release (GdkEventButton* ev)
3601 if (Keyboard::is_context_menu_event (ev)) {
3602 ARDOUR_UI::instance()->add_route (this);
3603 } else if (ev->button == 1) {
3604 selection->clear_tracks ();
3611 Editor::mouse_select_button_release (GdkEventButton* ev)
3613 /* this handles just right-clicks */
3615 if (ev->button != 3) {
3623 Editor::set_zoom_focus (ZoomFocus f)
3625 string str = zoom_focus_strings[(int)f];
3627 if (str != zoom_focus_selector.get_text()) {
3628 zoom_focus_selector.set_text (str);
3631 if (zoom_focus != f) {
3638 Editor::cycle_zoom_focus ()
3640 switch (zoom_focus) {
3642 set_zoom_focus (ZoomFocusRight);
3644 case ZoomFocusRight:
3645 set_zoom_focus (ZoomFocusCenter);
3647 case ZoomFocusCenter:
3648 set_zoom_focus (ZoomFocusPlayhead);
3650 case ZoomFocusPlayhead:
3651 set_zoom_focus (ZoomFocusMouse);
3653 case ZoomFocusMouse:
3654 set_zoom_focus (ZoomFocusEdit);
3657 set_zoom_focus (ZoomFocusLeft);
3663 Editor::ensure_float (Window& win)
3665 win.set_transient_for (*this);
3669 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3671 /* recover or initialize pane positions. do this here rather than earlier because
3672 we don't want the positions to change the child allocations, which they seem to do.
3678 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3687 XMLNode* geometry = find_named_node (*node, "geometry");
3689 if (which == static_cast<Paned*> (&edit_pane)) {
3691 if (done & Horizontal) {
3695 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3696 _notebook_shrunk = string_is_affirmative (prop->value ());
3699 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3700 /* initial allocation is 90% to canvas, 10% to notebook */
3701 pos = (int) floor (alloc.get_width() * 0.90f);
3702 snprintf (buf, sizeof(buf), "%d", pos);
3704 pos = atoi (prop->value());
3707 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3708 edit_pane.set_position (pos);
3711 done = (Pane) (done | Horizontal);
3713 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3715 if (done & Vertical) {
3719 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3720 /* initial allocation is 90% to canvas, 10% to summary */
3721 pos = (int) floor (alloc.get_height() * 0.90f);
3722 snprintf (buf, sizeof(buf), "%d", pos);
3725 pos = atoi (prop->value());
3728 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3729 editor_summary_pane.set_position (pos);
3732 done = (Pane) (done | Vertical);
3737 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3739 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3740 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3741 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3742 top_hbox.remove (toolbar_frame);
3747 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3749 if (toolbar_frame.get_parent() == 0) {
3750 top_hbox.pack_end (toolbar_frame);
3755 Editor::set_show_measures (bool yn)
3757 if (_show_measures != yn) {
3760 if ((_show_measures = yn) == true) {
3762 tempo_lines->show();
3765 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3766 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3768 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3769 draw_measures (begin, end);
3777 Editor::toggle_follow_playhead ()
3779 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3781 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3782 set_follow_playhead (tact->get_active());
3786 /** @param yn true to follow playhead, otherwise false.
3787 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3790 Editor::set_follow_playhead (bool yn, bool catch_up)
3792 if (_follow_playhead != yn) {
3793 if ((_follow_playhead = yn) == true && catch_up) {
3795 reset_x_origin_to_follow_playhead ();
3802 Editor::toggle_stationary_playhead ()
3804 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3806 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3807 set_stationary_playhead (tact->get_active());
3812 Editor::set_stationary_playhead (bool yn)
3814 if (_stationary_playhead != yn) {
3815 if ((_stationary_playhead = yn) == true) {
3817 // FIXME need a 3.0 equivalent of this 2.X call
3818 // update_current_screen ();
3825 Editor::playlist_selector () const
3827 return *_playlist_selector;
3831 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3835 switch (_snap_type) {
3840 case SnapToBeatDiv128:
3843 case SnapToBeatDiv64:
3846 case SnapToBeatDiv32:
3849 case SnapToBeatDiv28:
3852 case SnapToBeatDiv24:
3855 case SnapToBeatDiv20:
3858 case SnapToBeatDiv16:
3861 case SnapToBeatDiv14:
3864 case SnapToBeatDiv12:
3867 case SnapToBeatDiv10:
3870 case SnapToBeatDiv8:
3873 case SnapToBeatDiv7:
3876 case SnapToBeatDiv6:
3879 case SnapToBeatDiv5:
3882 case SnapToBeatDiv4:
3885 case SnapToBeatDiv3:
3888 case SnapToBeatDiv2:
3894 return _session->tempo_map().meter_at (position).divisions_per_bar();
3899 case SnapToTimecodeFrame:
3900 case SnapToTimecodeSeconds:
3901 case SnapToTimecodeMinutes:
3904 case SnapToRegionStart:
3905 case SnapToRegionEnd:
3906 case SnapToRegionSync:
3907 case SnapToRegionBoundary:
3917 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3921 ret = nudge_clock->current_duration (pos);
3922 next = ret + 1; /* XXXX fix me */
3928 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3930 ArdourDialog dialog (_("Playlist Deletion"));
3931 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3932 "If it is kept, its audio files will not be cleaned.\n"
3933 "If it is deleted, audio files used by it alone will be cleaned."),
3936 dialog.set_position (WIN_POS_CENTER);
3937 dialog.get_vbox()->pack_start (label);
3941 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3942 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3943 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3945 switch (dialog.run ()) {
3946 case RESPONSE_ACCEPT:
3947 /* delete the playlist */
3951 case RESPONSE_REJECT:
3952 /* keep the playlist */
3964 Editor::audio_region_selection_covers (framepos_t where)
3966 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3967 if ((*a)->region()->covers (where)) {
3976 Editor::prepare_for_cleanup ()
3978 cut_buffer->clear_regions ();
3979 cut_buffer->clear_playlists ();
3981 selection->clear_regions ();
3982 selection->clear_playlists ();
3984 _regions->suspend_redisplay ();
3988 Editor::finish_cleanup ()
3990 _regions->resume_redisplay ();
3994 Editor::transport_loop_location()
3997 return _session->locations()->auto_loop_location();
4004 Editor::transport_punch_location()
4007 return _session->locations()->auto_punch_location();
4014 Editor::control_layout_scroll (GdkEventScroll* ev)
4016 /* Just forward to the normal canvas scroll method. The coordinate
4017 systems are different but since the canvas is always larger than the
4018 track headers, and aligned with the trackview area, this will work.
4020 In the not too distant future this layout is going away anyway and
4021 headers will be on the canvas.
4023 return canvas_scroll_event (ev, false);
4027 Editor::session_state_saved (string)
4030 _snapshots->redisplay ();
4034 Editor::update_tearoff_visibility()
4036 bool visible = Config->get_keep_tearoffs();
4037 _mouse_mode_tearoff->set_visible (visible);
4038 _tools_tearoff->set_visible (visible);
4039 if (_zoom_tearoff) {
4040 _zoom_tearoff->set_visible (visible);
4045 Editor::maximise_editing_space ()
4057 Editor::restore_editing_space ()
4069 * Make new playlists for a given track and also any others that belong
4070 * to the same active route group with the `select' property.
4075 Editor::new_playlists (TimeAxisView* v)
4077 begin_reversible_command (_("new playlists"));
4078 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4079 _session->playlists->get (playlists);
4080 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4081 commit_reversible_command ();
4085 * Use a copy of the current playlist for a given track and also any others that belong
4086 * to the same active route group with the `select' property.
4091 Editor::copy_playlists (TimeAxisView* v)
4093 begin_reversible_command (_("copy playlists"));
4094 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4095 _session->playlists->get (playlists);
4096 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4097 commit_reversible_command ();
4100 /** Clear the current playlist for a given track and also any others that belong
4101 * to the same active route group with the `select' property.
4106 Editor::clear_playlists (TimeAxisView* v)
4108 begin_reversible_command (_("clear playlists"));
4109 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4110 _session->playlists->get (playlists);
4111 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4112 commit_reversible_command ();
4116 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4118 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4122 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4124 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4128 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4130 atv.clear_playlist ();
4134 Editor::on_key_press_event (GdkEventKey* ev)
4136 return key_press_focus_accelerator_handler (*this, ev);
4140 Editor::on_key_release_event (GdkEventKey* ev)
4142 return Gtk::Window::on_key_release_event (ev);
4143 // return key_press_focus_accelerator_handler (*this, ev);
4146 /** Queue up a change to the viewport x origin.
4147 * @param frame New x origin.
4150 Editor::reset_x_origin (framepos_t frame)
4152 pending_visual_change.add (VisualChange::TimeOrigin);
4153 pending_visual_change.time_origin = frame;
4154 ensure_visual_change_idle_handler ();
4158 Editor::reset_y_origin (double y)
4160 pending_visual_change.add (VisualChange::YOrigin);
4161 pending_visual_change.y_origin = y;
4162 ensure_visual_change_idle_handler ();
4166 Editor::reset_zoom (framecnt_t spp)
4168 if (spp == samples_per_pixel) {
4172 pending_visual_change.add (VisualChange::ZoomLevel);
4173 pending_visual_change.samples_per_pixel = spp;
4174 ensure_visual_change_idle_handler ();
4178 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4180 reset_x_origin (frame);
4183 if (!no_save_visual) {
4184 undo_visual_stack.push_back (current_visual_state(false));
4188 Editor::VisualState::VisualState (bool with_tracks)
4189 : gui_state (with_tracks ? new GUIObjectState : 0)
4193 Editor::VisualState::~VisualState ()
4198 Editor::VisualState*
4199 Editor::current_visual_state (bool with_tracks)
4201 VisualState* vs = new VisualState (with_tracks);
4202 vs->y_position = vertical_adjustment.get_value();
4203 vs->samples_per_pixel = samples_per_pixel;
4204 vs->leftmost_frame = leftmost_frame;
4205 vs->zoom_focus = zoom_focus;
4208 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4215 Editor::undo_visual_state ()
4217 if (undo_visual_stack.empty()) {
4221 VisualState* vs = undo_visual_stack.back();
4222 undo_visual_stack.pop_back();
4225 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4227 use_visual_state (*vs);
4231 Editor::redo_visual_state ()
4233 if (redo_visual_stack.empty()) {
4237 VisualState* vs = redo_visual_stack.back();
4238 redo_visual_stack.pop_back();
4240 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4242 use_visual_state (*vs);
4246 Editor::swap_visual_state ()
4248 if (undo_visual_stack.empty()) {
4249 redo_visual_state ();
4251 undo_visual_state ();
4256 Editor::use_visual_state (VisualState& vs)
4258 PBD::Unwinder<bool> nsv (no_save_visual, true);
4259 DisplaySuspender ds;
4261 vertical_adjustment.set_value (vs.y_position);
4263 set_zoom_focus (vs.zoom_focus);
4264 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4267 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4269 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4270 (*i)->reset_visual_state ();
4274 _routes->update_visibility ();
4277 /** This is the core function that controls the zoom level of the canvas. It is called
4278 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4279 * @param spp new number of samples per pixel
4282 Editor::set_samples_per_pixel (framecnt_t spp)
4288 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4289 const framecnt_t lots_of_pixels = 4000;
4291 /* if the zoom level is greater than what you'd get trying to display 3
4292 * days of audio on a really big screen, then it's too big.
4295 if (spp * lots_of_pixels > three_days) {
4299 samples_per_pixel = spp;
4302 tempo_lines->tempo_map_changed();
4305 bool const showing_time_selection = selection->time.length() > 0;
4307 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4308 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4309 (*i)->reshow_selection (selection->time);
4313 ZoomChanged (); /* EMIT_SIGNAL */
4315 ArdourCanvas::GtkCanvasViewport* c;
4317 c = get_track_canvas();
4319 c->canvas()->zoomed ();
4322 if (playhead_cursor) {
4323 playhead_cursor->set_position (playhead_cursor->current_frame ());
4326 refresh_location_display();
4327 _summary->set_overlays_dirty ();
4329 update_marker_labels ();
4335 Editor::queue_visual_videotimeline_update ()
4338 * pending_visual_change.add (VisualChange::VideoTimeline);
4339 * or maybe even more specific: which videotimeline-image
4340 * currently it calls update_video_timeline() to update
4341 * _all outdated_ images on the video-timeline.
4342 * see 'exposeimg()' in video_image_frame.cc
4344 ensure_visual_change_idle_handler ();
4348 Editor::ensure_visual_change_idle_handler ()
4350 if (pending_visual_change.idle_handler_id < 0) {
4351 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4352 pending_visual_change.being_handled = false;
4357 Editor::_idle_visual_changer (void* arg)
4359 return static_cast<Editor*>(arg)->idle_visual_changer ();
4363 Editor::idle_visual_changer ()
4365 /* set_horizontal_position() below (and maybe other calls) call
4366 gtk_main_iteration(), so it's possible that a signal will be handled
4367 half-way through this method. If this signal wants an
4368 idle_visual_changer we must schedule another one after this one, so
4369 mark the idle_handler_id as -1 here to allow that. Also make a note
4370 that we are doing the visual change, so that changes in response to
4371 super-rapid-screen-update can be dropped if we are still processing
4375 pending_visual_change.idle_handler_id = -1;
4376 pending_visual_change.being_handled = true;
4378 VisualChange vc = pending_visual_change;
4380 pending_visual_change.pending = (VisualChange::Type) 0;
4382 visual_changer (vc);
4384 pending_visual_change.being_handled = false;
4386 return 0; /* this is always a one-shot call */
4390 Editor::visual_changer (const VisualChange& vc)
4392 double const last_time_origin = horizontal_position ();
4394 if (vc.pending & VisualChange::ZoomLevel) {
4395 set_samples_per_pixel (vc.samples_per_pixel);
4397 compute_fixed_ruler_scale ();
4399 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4400 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4402 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4403 current_bbt_points_begin, current_bbt_points_end);
4404 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4405 current_bbt_points_begin, current_bbt_points_end);
4406 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4408 update_video_timeline();
4411 if (vc.pending & VisualChange::TimeOrigin) {
4412 set_horizontal_position (vc.time_origin / samples_per_pixel);
4415 if (vc.pending & VisualChange::YOrigin) {
4416 vertical_adjustment.set_value (vc.y_origin);
4419 if (last_time_origin == horizontal_position ()) {
4420 /* changed signal not emitted */
4421 update_fixed_rulers ();
4422 redisplay_tempo (true);
4425 if (!(vc.pending & VisualChange::ZoomLevel)) {
4426 update_video_timeline();
4429 _summary->set_overlays_dirty ();
4432 struct EditorOrderTimeAxisSorter {
4433 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4434 return a->order () < b->order ();
4439 Editor::sort_track_selection (TrackViewList& sel)
4441 EditorOrderTimeAxisSorter cmp;
4446 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4449 framepos_t where = 0;
4450 EditPoint ep = _edit_point;
4452 if(Profile->get_mixbus())
4453 if (ep == EditAtSelectedMarker)
4456 if (from_context_menu && (ep == EditAtMouse)) {
4457 return canvas_event_sample (&context_click_event, 0, 0);
4460 if (entered_marker) {
4461 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4462 return entered_marker->position();
4465 if (ignore_playhead && ep == EditAtPlayhead) {
4466 ep = EditAtSelectedMarker;
4470 case EditAtPlayhead:
4471 where = _session->audible_frame();
4472 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4475 case EditAtSelectedMarker:
4476 if (!selection->markers.empty()) {
4478 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4481 where = loc->start();
4485 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4493 if (!mouse_frame (where, ignored)) {
4494 /* XXX not right but what can we do ? */
4498 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4506 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4508 if (!_session) return;
4510 begin_reversible_command (cmd);
4514 if ((tll = transport_loop_location()) == 0) {
4515 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4516 XMLNode &before = _session->locations()->get_state();
4517 _session->locations()->add (loc, true);
4518 _session->set_auto_loop_location (loc);
4519 XMLNode &after = _session->locations()->get_state();
4520 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4522 XMLNode &before = tll->get_state();
4523 tll->set_hidden (false, this);
4524 tll->set (start, end);
4525 XMLNode &after = tll->get_state();
4526 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4529 commit_reversible_command ();
4533 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4535 if (!_session) return;
4537 begin_reversible_command (cmd);
4541 if ((tpl = transport_punch_location()) == 0) {
4542 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4543 XMLNode &before = _session->locations()->get_state();
4544 _session->locations()->add (loc, true);
4545 _session->set_auto_punch_location (loc);
4546 XMLNode &after = _session->locations()->get_state();
4547 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4550 XMLNode &before = tpl->get_state();
4551 tpl->set_hidden (false, this);
4552 tpl->set (start, end);
4553 XMLNode &after = tpl->get_state();
4554 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4557 commit_reversible_command ();
4560 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4561 * @param rs List to which found regions are added.
4562 * @param where Time to look at.
4563 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4566 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4568 const TrackViewList* tracks;
4571 tracks = &track_views;
4576 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4578 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4581 boost::shared_ptr<Track> tr;
4582 boost::shared_ptr<Playlist> pl;
4584 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4586 boost::shared_ptr<RegionList> regions = pl->regions_at (
4587 (framepos_t) floor ( (double) where * tr->speed()));
4589 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4590 RegionView* rv = rtv->view()->find_view (*i);
4601 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4603 const TrackViewList* tracks;
4606 tracks = &track_views;
4611 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4612 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4614 boost::shared_ptr<Track> tr;
4615 boost::shared_ptr<Playlist> pl;
4617 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4619 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4620 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4622 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4624 RegionView* rv = rtv->view()->find_view (*i);
4635 /** Get regions using the following method:
4637 * Make a region list using:
4638 * (a) any selected regions
4639 * (b) the intersection of any selected tracks and the edit point(*)
4640 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4642 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4644 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4648 Editor::get_regions_from_selection_and_edit_point ()
4650 RegionSelection regions;
4652 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4653 regions.add (entered_regionview);
4655 regions = selection->regions;
4658 if ( regions.empty() ) {
4659 TrackViewList tracks = selection->tracks;
4661 if (!tracks.empty()) {
4662 /* no region selected or entered, but some selected tracks:
4663 * act on all regions on the selected tracks at the edit point
4665 framepos_t const where = get_preferred_edit_position ();
4666 get_regions_at(regions, where, tracks);
4673 /** Get regions using the following method:
4675 * Make a region list using:
4676 * (a) any selected regions
4677 * (b) the intersection of any selected tracks and the edit point(*)
4678 * (c) if neither exists, then whatever region is under the mouse
4680 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4682 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4685 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4687 RegionSelection regions;
4689 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4690 regions.add (entered_regionview);
4692 regions = selection->regions;
4695 if ( regions.empty() ) {
4696 TrackViewList tracks = selection->tracks;
4698 if (!tracks.empty()) {
4699 /* no region selected or entered, but some selected tracks:
4700 * act on all regions on the selected tracks at the edit point
4702 get_regions_at(regions, pos, tracks);
4709 /** Start with regions that are selected, or the entered regionview if none are selected.
4710 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4711 * of the regions that we started with.
4715 Editor::get_regions_from_selection_and_entered ()
4717 RegionSelection regions = selection->regions;
4719 if (regions.empty() && entered_regionview) {
4720 regions.add (entered_regionview);
4727 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4729 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4731 RouteTimeAxisView* tatv;
4733 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4735 boost::shared_ptr<Playlist> pl;
4736 vector<boost::shared_ptr<Region> > results;
4738 boost::shared_ptr<Track> tr;
4740 if ((tr = tatv->track()) == 0) {
4745 if ((pl = (tr->playlist())) != 0) {
4746 if (src_comparison) {
4747 pl->get_source_equivalent_regions (region, results);
4749 pl->get_region_list_equivalent_regions (region, results);
4753 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4754 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4755 regions.push_back (marv);
4764 Editor::show_rhythm_ferret ()
4766 if (rhythm_ferret == 0) {
4767 rhythm_ferret = new RhythmFerret(*this);
4770 rhythm_ferret->set_session (_session);
4771 rhythm_ferret->show ();
4772 rhythm_ferret->present ();
4776 Editor::first_idle ()
4778 MessageDialog* dialog = 0;
4780 if (track_views.size() > 1) {
4781 dialog = new MessageDialog (
4783 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4787 ARDOUR_UI::instance()->flush_pending ();
4790 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4794 // first idle adds route children (automation tracks), so we need to redisplay here
4795 _routes->redisplay ();
4802 Editor::_idle_resize (gpointer arg)
4804 return ((Editor*)arg)->idle_resize ();
4808 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4810 if (resize_idle_id < 0) {
4811 resize_idle_id = g_idle_add (_idle_resize, this);
4812 _pending_resize_amount = 0;
4815 /* make a note of the smallest resulting height, so that we can clamp the
4816 lower limit at TimeAxisView::hSmall */
4818 int32_t min_resulting = INT32_MAX;
4820 _pending_resize_amount += h;
4821 _pending_resize_view = view;
4823 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4825 if (selection->tracks.contains (_pending_resize_view)) {
4826 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4827 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4831 if (min_resulting < 0) {
4836 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4837 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4841 /** Handle pending resizing of tracks */
4843 Editor::idle_resize ()
4845 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4847 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4848 selection->tracks.contains (_pending_resize_view)) {
4850 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4851 if (*i != _pending_resize_view) {
4852 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4857 _pending_resize_amount = 0;
4858 _group_tabs->set_dirty ();
4859 resize_idle_id = -1;
4867 ENSURE_GUI_THREAD (*this, &Editor::located);
4870 playhead_cursor->set_position (_session->audible_frame ());
4871 if (_follow_playhead && !_pending_initial_locate) {
4872 reset_x_origin_to_follow_playhead ();
4876 _pending_locate_request = false;
4877 _pending_initial_locate = false;
4881 Editor::region_view_added (RegionView *)
4883 _summary->set_background_dirty ();
4887 Editor::region_view_removed ()
4889 _summary->set_background_dirty ();
4893 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4895 TrackViewList::const_iterator j = track_views.begin ();
4896 while (j != track_views.end()) {
4897 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4898 if (rtv && rtv->route() == r) {
4909 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4913 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4914 TimeAxisView* tv = axis_view_from_route (*i);
4924 Editor::suspend_route_redisplay ()
4927 _routes->suspend_redisplay();
4932 Editor::resume_route_redisplay ()
4935 _routes->resume_redisplay();
4940 Editor::add_routes (RouteList& routes)
4942 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4944 RouteTimeAxisView *rtv;
4945 list<RouteTimeAxisView*> new_views;
4947 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4948 boost::shared_ptr<Route> route = (*x);
4950 if (route->is_auditioner() || route->is_monitor()) {
4954 DataType dt = route->input()->default_type();
4956 if (dt == ARDOUR::DataType::AUDIO) {
4957 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4958 rtv->set_route (route);
4959 } else if (dt == ARDOUR::DataType::MIDI) {
4960 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4961 rtv->set_route (route);
4963 throw unknown_type();
4966 new_views.push_back (rtv);
4967 track_views.push_back (rtv);
4969 rtv->effective_gain_display ();
4971 if (internal_editing()) {
4972 rtv->enter_internal_edit_mode ();
4974 rtv->leave_internal_edit_mode ();
4977 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4978 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4981 if (new_views.size() > 0) {
4982 _routes->routes_added (new_views);
4983 _summary->routes_added (new_views);
4986 if (show_editor_mixer_when_tracks_arrive) {
4987 show_editor_mixer (true);
4990 editor_list_button.set_sensitive (true);
4994 Editor::timeaxisview_deleted (TimeAxisView *tv)
4996 if (tv == entered_track) {
5000 if (_session && _session->deletion_in_progress()) {
5001 /* the situation is under control */
5005 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5007 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5009 _routes->route_removed (tv);
5011 TimeAxisView::Children c = tv->get_child_list ();
5012 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5013 if (entered_track == i->get()) {
5018 /* remove it from the list of track views */
5020 TrackViewList::iterator i;
5022 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5023 i = track_views.erase (i);
5026 /* update whatever the current mixer strip is displaying, if revelant */
5028 boost::shared_ptr<Route> route;
5031 route = rtav->route ();
5034 if (current_mixer_strip && current_mixer_strip->route() == route) {
5036 TimeAxisView* next_tv;
5038 if (track_views.empty()) {
5040 } else if (i == track_views.end()) {
5041 next_tv = track_views.front();
5048 set_selected_mixer_strip (*next_tv);
5050 /* make the editor mixer strip go away setting the
5051 * button to inactive (which also unticks the menu option)
5054 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5060 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5062 if (apply_to_selection) {
5063 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5065 TrackSelection::iterator j = i;
5068 hide_track_in_display (*i, false);
5073 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5075 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5076 // this will hide the mixer strip
5077 set_selected_mixer_strip (*tv);
5080 _routes->hide_track_in_display (*tv);
5085 Editor::sync_track_view_list_and_routes ()
5087 track_views = TrackViewList (_routes->views ());
5089 _summary->set_dirty ();
5090 _group_tabs->set_dirty ();
5092 return false; // do not call again (until needed)
5096 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5098 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5103 /** Find a RouteTimeAxisView by the ID of its route */
5105 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5107 RouteTimeAxisView* v;
5109 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5110 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5111 if(v->route()->id() == id) {
5121 Editor::fit_route_group (RouteGroup *g)
5123 TrackViewList ts = axis_views_from_routes (g->route_list ());
5128 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5130 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5133 _session->cancel_audition ();
5137 if (_session->is_auditioning()) {
5138 _session->cancel_audition ();
5139 if (r == last_audition_region) {
5144 _session->audition_region (r);
5145 last_audition_region = r;
5150 Editor::hide_a_region (boost::shared_ptr<Region> r)
5152 r->set_hidden (true);
5156 Editor::show_a_region (boost::shared_ptr<Region> r)
5158 r->set_hidden (false);
5162 Editor::audition_region_from_region_list ()
5164 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5168 Editor::hide_region_from_region_list ()
5170 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5174 Editor::show_region_in_region_list ()
5176 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5180 Editor::step_edit_status_change (bool yn)
5183 start_step_editing ();
5185 stop_step_editing ();
5190 Editor::start_step_editing ()
5192 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5196 Editor::stop_step_editing ()
5198 step_edit_connection.disconnect ();
5202 Editor::check_step_edit ()
5204 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5205 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5207 mtv->check_step_edit ();
5211 return true; // do it again, till we stop
5215 Editor::scroll_press (Direction dir)
5217 ++_scroll_callbacks;
5219 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5220 /* delay the first auto-repeat */
5226 scroll_backward (1);
5234 scroll_up_one_track ();
5238 scroll_down_one_track ();
5242 /* do hacky auto-repeat */
5243 if (!_scroll_connection.connected ()) {
5245 _scroll_connection = Glib::signal_timeout().connect (
5246 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5249 _scroll_callbacks = 0;
5256 Editor::scroll_release ()
5258 _scroll_connection.disconnect ();
5261 /** Queue a change for the Editor viewport x origin to follow the playhead */
5263 Editor::reset_x_origin_to_follow_playhead ()
5265 framepos_t const frame = playhead_cursor->current_frame ();
5267 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5269 if (_session->transport_speed() < 0) {
5271 if (frame > (current_page_samples() / 2)) {
5272 center_screen (frame-(current_page_samples()/2));
5274 center_screen (current_page_samples()/2);
5281 if (frame < leftmost_frame) {
5283 if (_session->transport_rolling()) {
5284 /* rolling; end up with the playhead at the right of the page */
5285 l = frame - current_page_samples ();
5287 /* not rolling: end up with the playhead 1/4 of the way along the page */
5288 l = frame - current_page_samples() / 4;
5292 if (_session->transport_rolling()) {
5293 /* rolling: end up with the playhead on the left of the page */
5296 /* not rolling: end up with the playhead 3/4 of the way along the page */
5297 l = frame - 3 * current_page_samples() / 4;
5305 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5311 Editor::super_rapid_screen_update ()
5313 if (!_session || !_session->engine().running()) {
5317 /* METERING / MIXER STRIPS */
5319 /* update track meters, if required */
5320 if (is_mapped() && meters_running) {
5321 RouteTimeAxisView* rtv;
5322 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5323 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5324 rtv->fast_update ();
5329 /* and any current mixer strip */
5330 if (current_mixer_strip) {
5331 current_mixer_strip->fast_update ();
5334 /* PLAYHEAD AND VIEWPORT */
5336 framepos_t const frame = _session->audible_frame();
5338 /* There are a few reasons why we might not update the playhead / viewport stuff:
5340 * 1. we don't update things when there's a pending locate request, otherwise
5341 * when the editor requests a locate there is a chance that this method
5342 * will move the playhead before the locate request is processed, causing
5344 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5345 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5348 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5350 last_update_frame = frame;
5352 if (!_dragging_playhead) {
5353 playhead_cursor->set_position (frame);
5356 if (!_stationary_playhead) {
5358 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5359 /* We only do this if we aren't already
5360 handling a visual change (ie if
5361 pending_visual_change.being_handled is
5362 false) so that these requests don't stack
5363 up there are too many of them to handle in
5366 reset_x_origin_to_follow_playhead ();
5371 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5375 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5376 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5377 if (target <= 0.0) {
5380 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5381 target = (target * 0.15) + (current * 0.85);
5387 set_horizontal_position (current);
5396 Editor::session_going_away ()
5398 _have_idled = false;
5400 _session_connections.drop_connections ();
5402 super_rapid_screen_update_connection.disconnect ();
5404 selection->clear ();
5405 cut_buffer->clear ();
5407 clicked_regionview = 0;
5408 clicked_axisview = 0;
5409 clicked_routeview = 0;
5410 entered_regionview = 0;
5412 last_update_frame = 0;
5415 playhead_cursor->hide ();
5417 /* rip everything out of the list displays */
5421 _route_groups->clear ();
5423 /* do this first so that deleting a track doesn't reset cms to null
5424 and thus cause a leak.
5427 if (current_mixer_strip) {
5428 if (current_mixer_strip->get_parent() != 0) {
5429 global_hpacker.remove (*current_mixer_strip);
5431 delete current_mixer_strip;
5432 current_mixer_strip = 0;
5435 /* delete all trackviews */
5437 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5440 track_views.clear ();
5442 nudge_clock->set_session (0);
5444 editor_list_button.set_active(false);
5445 editor_list_button.set_sensitive(false);
5447 /* clear tempo/meter rulers */
5448 remove_metric_marks ();
5450 clear_marker_display ();
5452 stop_step_editing ();
5454 /* get rid of any existing editor mixer strip */
5456 WindowTitle title(Glib::get_application_name());
5457 title += _("Editor");
5459 set_title (title.get_string());
5461 SessionHandlePtr::session_going_away ();
5466 Editor::show_editor_list (bool yn)
5469 _the_notebook.show ();
5471 _the_notebook.hide ();
5476 Editor::change_region_layering_order (bool from_context_menu)
5478 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5480 if (!clicked_routeview) {
5481 if (layering_order_editor) {
5482 layering_order_editor->hide ();
5487 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5493 boost::shared_ptr<Playlist> pl = track->playlist();
5499 if (layering_order_editor == 0) {
5500 layering_order_editor = new RegionLayeringOrderEditor (*this);
5503 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5504 layering_order_editor->maybe_present ();
5508 Editor::update_region_layering_order_editor ()
5510 if (layering_order_editor && layering_order_editor->is_visible ()) {
5511 change_region_layering_order (true);
5516 Editor::setup_fade_images ()
5518 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5519 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5520 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5521 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5522 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5524 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5525 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5526 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5527 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5528 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5530 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5531 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5532 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5533 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5534 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5536 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5537 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5538 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5539 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5540 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5544 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5546 Editor::action_menu_item (std::string const & name)
5548 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5551 return *manage (a->create_menu_item ());
5555 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5557 EventBox* b = manage (new EventBox);
5558 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5559 Label* l = manage (new Label (name));
5563 _the_notebook.append_page (widget, *b);
5567 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5569 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5570 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5573 if (ev->type == GDK_2BUTTON_PRESS) {
5575 /* double-click on a notebook tab shrinks or expands the notebook */
5577 if (_notebook_shrunk) {
5578 if (pre_notebook_shrink_pane_width) {
5579 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5581 _notebook_shrunk = false;
5583 pre_notebook_shrink_pane_width = edit_pane.get_position();
5585 /* this expands the LHS of the edit pane to cover the notebook
5586 PAGE but leaves the tabs visible.
5588 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5589 _notebook_shrunk = true;
5597 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5599 using namespace Menu_Helpers;
5601 MenuList& items = _control_point_context_menu.items ();
5604 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5605 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5606 if (!can_remove_control_point (item)) {
5607 items.back().set_sensitive (false);
5610 _control_point_context_menu.popup (event->button.button, event->button.time);
5614 Editor::zoom_vertical_modifier_released()
5616 _stepping_axis_view = 0;
5620 Editor::ui_parameter_changed (string parameter)
5622 if (parameter == "icon-set") {
5623 while (!_cursor_stack.empty()) {
5624 _cursor_stack.pop();
5626 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5627 } else if (parameter == "draggable-playhead") {
5628 if (_verbose_cursor) {
5629 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());