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"),
223 pane_size_watcher (Paned* pane)
225 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
229 Quartz: impossible to access
231 so stop that by preventing it from ever getting too narrow. 35
232 pixels is basically a rough guess at the tab width.
237 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
239 gint pos = pane->get_position ();
241 if (pos > max_width_of_lhs) {
242 pane->set_position (max_width_of_lhs);
247 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
249 /* time display buttons */
250 , minsec_label (_("Mins:Secs"))
251 , bbt_label (_("Bars:Beats"))
252 , timecode_label (_("Timecode"))
253 , samples_label (_("Samples"))
254 , tempo_label (_("Tempo"))
255 , meter_label (_("Meter"))
256 , mark_label (_("Location Markers"))
257 , range_mark_label (_("Range Markers"))
258 , transport_mark_label (_("Loop/Punch Ranges"))
259 , cd_mark_label (_("CD Markers"))
260 , videotl_label (_("Video Timeline"))
261 , edit_packer (4, 4, true)
263 /* the values here don't matter: layout widgets
264 reset them as needed.
267 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
268 , horizontal_adjustment (0.0, 0.0, 1e16)
269 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
271 , controls_layout (unused_adjustment, vertical_adjustment)
273 /* tool bar related */
275 , toolbar_selection_clock_table (2,3)
276 , _mouse_mode_tearoff (0)
277 , automation_mode_button (_("mode"))
281 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
285 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
286 , meters_running(false)
287 , _pending_locate_request (false)
288 , _pending_initial_locate (false)
289 , _last_cut_copy_source_track (0)
291 , _region_selection_change_updates_region_list (true)
292 , _following_mixer_selection (false)
293 , _control_point_toggled_on_press (false)
294 , _stepping_axis_view (0)
298 /* we are a singleton */
300 PublicEditor::_instance = this;
304 selection = new Selection (this);
305 cut_buffer = new Selection (this);
307 clicked_regionview = 0;
308 clicked_axisview = 0;
309 clicked_routeview = 0;
310 clicked_control_point = 0;
311 last_update_frame = 0;
312 pre_press_cursor = 0;
313 _drags = new DragManager (this);
316 current_mixer_strip = 0;
319 snap_type_strings = I18N (_snap_type_strings);
320 snap_mode_strings = I18N (_snap_mode_strings);
321 zoom_focus_strings = I18N (_zoom_focus_strings);
322 edit_mode_strings = I18N (_edit_mode_strings);
323 edit_point_strings = I18N (_edit_point_strings);
324 #ifdef USE_RUBBERBAND
325 rb_opt_strings = I18N (_rb_opt_strings);
329 build_edit_mode_menu();
330 build_zoom_focus_menu();
331 build_track_count_menu();
332 build_snap_mode_menu();
333 build_snap_type_menu();
334 build_edit_point_menu();
336 snap_threshold = 5.0;
337 bbt_beat_subdivision = 4;
338 _visible_canvas_width = 0;
339 _visible_canvas_height = 0;
340 autoscroll_horizontal_allowed = false;
341 autoscroll_vertical_allowed = false;
346 current_interthread_info = 0;
347 _show_measures = true;
349 show_gain_after_trim = false;
351 have_pending_keyboard_selection = false;
352 _follow_playhead = true;
353 _stationary_playhead = false;
354 editor_ruler_menu = 0;
355 no_ruler_shown_update = false;
357 range_marker_menu = 0;
358 marker_menu_item = 0;
359 tempo_or_meter_marker_menu = 0;
360 transport_marker_menu = 0;
361 new_transport_marker_menu = 0;
362 editor_mixer_strip_width = Wide;
363 show_editor_mixer_when_tracks_arrive = false;
364 region_edit_menu_split_multichannel_item = 0;
365 region_edit_menu_split_item = 0;
368 current_stepping_trackview = 0;
370 entered_regionview = 0;
372 clear_entered_track = false;
375 button_release_can_deselect = true;
376 _dragging_playhead = false;
377 _dragging_edit_point = false;
378 select_new_marker = false;
380 layering_order_editor = 0;
381 no_save_visual = false;
383 within_track_canvas = false;
385 scrubbing_direction = 0;
389 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
390 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
391 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
392 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
393 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
395 zoom_focus = ZoomFocusLeft;
396 _edit_point = EditAtMouse;
397 _internal_editing = false;
398 current_canvas_cursor = 0;
399 _visible_track_count = 16;
401 samples_per_pixel = 2048; /* too early to use reset_zoom () */
403 _scroll_callbacks = 0;
405 bbt_label.set_name ("EditorRulerLabel");
406 bbt_label.set_size_request (-1, (int)timebar_height);
407 bbt_label.set_alignment (1.0, 0.5);
408 bbt_label.set_padding (5,0);
410 bbt_label.set_no_show_all();
411 minsec_label.set_name ("EditorRulerLabel");
412 minsec_label.set_size_request (-1, (int)timebar_height);
413 minsec_label.set_alignment (1.0, 0.5);
414 minsec_label.set_padding (5,0);
415 minsec_label.hide ();
416 minsec_label.set_no_show_all();
417 timecode_label.set_name ("EditorRulerLabel");
418 timecode_label.set_size_request (-1, (int)timebar_height);
419 timecode_label.set_alignment (1.0, 0.5);
420 timecode_label.set_padding (5,0);
421 timecode_label.hide ();
422 timecode_label.set_no_show_all();
423 samples_label.set_name ("EditorRulerLabel");
424 samples_label.set_size_request (-1, (int)timebar_height);
425 samples_label.set_alignment (1.0, 0.5);
426 samples_label.set_padding (5,0);
427 samples_label.hide ();
428 samples_label.set_no_show_all();
430 tempo_label.set_name ("EditorRulerLabel");
431 tempo_label.set_size_request (-1, (int)timebar_height);
432 tempo_label.set_alignment (1.0, 0.5);
433 tempo_label.set_padding (5,0);
435 tempo_label.set_no_show_all();
437 meter_label.set_name ("EditorRulerLabel");
438 meter_label.set_size_request (-1, (int)timebar_height);
439 meter_label.set_alignment (1.0, 0.5);
440 meter_label.set_padding (5,0);
442 meter_label.set_no_show_all();
444 if (Profile->get_trx()) {
445 mark_label.set_text (_("Markers"));
447 mark_label.set_name ("EditorRulerLabel");
448 mark_label.set_size_request (-1, (int)timebar_height);
449 mark_label.set_alignment (1.0, 0.5);
450 mark_label.set_padding (5,0);
452 mark_label.set_no_show_all();
454 cd_mark_label.set_name ("EditorRulerLabel");
455 cd_mark_label.set_size_request (-1, (int)timebar_height);
456 cd_mark_label.set_alignment (1.0, 0.5);
457 cd_mark_label.set_padding (5,0);
458 cd_mark_label.hide();
459 cd_mark_label.set_no_show_all();
461 videotl_bar_height = 4;
462 videotl_label.set_name ("EditorRulerLabel");
463 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
464 videotl_label.set_alignment (1.0, 0.5);
465 videotl_label.set_padding (5,0);
466 videotl_label.hide();
467 videotl_label.set_no_show_all();
469 range_mark_label.set_name ("EditorRulerLabel");
470 range_mark_label.set_size_request (-1, (int)timebar_height);
471 range_mark_label.set_alignment (1.0, 0.5);
472 range_mark_label.set_padding (5,0);
473 range_mark_label.hide();
474 range_mark_label.set_no_show_all();
476 transport_mark_label.set_name ("EditorRulerLabel");
477 transport_mark_label.set_size_request (-1, (int)timebar_height);
478 transport_mark_label.set_alignment (1.0, 0.5);
479 transport_mark_label.set_padding (5,0);
480 transport_mark_label.hide();
481 transport_mark_label.set_no_show_all();
483 initialize_canvas ();
485 _summary = new EditorSummary (this);
487 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
488 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
490 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
492 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
493 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
495 edit_controls_vbox.set_spacing (0);
496 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
497 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
499 HBox* h = manage (new HBox);
500 _group_tabs = new EditorGroupTabs (this);
501 if (!ARDOUR::Profile->get_trx()) {
502 h->pack_start (*_group_tabs, PACK_SHRINK);
504 h->pack_start (edit_controls_vbox);
505 controls_layout.add (*h);
507 controls_layout.set_name ("EditControlsBase");
508 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
509 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
510 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
512 _cursors = new MouseCursors;
513 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
514 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
516 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
518 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
519 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
520 pad_line_1->set_outline_color (0xFF0000FF);
526 edit_packer.set_col_spacings (0);
527 edit_packer.set_row_spacings (0);
528 edit_packer.set_homogeneous (false);
529 edit_packer.set_border_width (0);
530 edit_packer.set_name ("EditorWindow");
532 time_bars_event_box.add (time_bars_vbox);
533 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
534 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
536 /* labels for the time bars */
537 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
539 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
541 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
543 bottom_hbox.set_border_width (2);
544 bottom_hbox.set_spacing (3);
546 _route_groups = new EditorRouteGroups (this);
547 _routes = new EditorRoutes (this);
548 _regions = new EditorRegions (this);
549 _snapshots = new EditorSnapshots (this);
550 _locations = new EditorLocations (this);
552 add_notebook_page (_("Regions"), _regions->widget ());
553 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
554 add_notebook_page (_("Snapshots"), _snapshots->widget ());
555 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
556 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
558 _the_notebook.set_show_tabs (true);
559 _the_notebook.set_scrollable (true);
560 _the_notebook.popup_disable ();
561 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
562 _the_notebook.show_all ();
564 _notebook_shrunk = false;
566 editor_summary_pane.pack1(edit_packer);
568 Button* summary_arrows_left_left = manage (new Button);
569 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
570 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
571 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
573 Button* summary_arrows_left_right = manage (new Button);
574 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
575 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
576 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 VBox* summary_arrows_left = manage (new VBox);
579 summary_arrows_left->pack_start (*summary_arrows_left_left);
580 summary_arrows_left->pack_start (*summary_arrows_left_right);
582 Button* summary_arrows_right_up = manage (new Button);
583 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
584 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
585 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
587 Button* summary_arrows_right_down = manage (new Button);
588 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
589 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
590 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
592 VBox* summary_arrows_right = manage (new VBox);
593 summary_arrows_right->pack_start (*summary_arrows_right_up);
594 summary_arrows_right->pack_start (*summary_arrows_right_down);
596 Frame* summary_frame = manage (new Frame);
597 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
599 summary_frame->add (*_summary);
600 summary_frame->show ();
602 _summary_hbox.pack_start (*summary_arrows_left, false, false);
603 _summary_hbox.pack_start (*summary_frame, true, true);
604 _summary_hbox.pack_start (*summary_arrows_right, false, false);
606 if (!ARDOUR::Profile->get_trx()) {
607 editor_summary_pane.pack2 (_summary_hbox);
610 edit_pane.pack1 (editor_summary_pane, true, true);
611 if (!ARDOUR::Profile->get_trx()) {
612 edit_pane.pack2 (_the_notebook, false, true);
615 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
617 /* XXX: editor_summary_pane might need similar to the edit_pane */
619 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
621 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
622 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
624 top_hbox.pack_start (toolbar_frame);
626 HBox *hbox = manage (new HBox);
627 hbox->pack_start (edit_pane, true, true);
629 global_vpacker.pack_start (top_hbox, false, false);
630 global_vpacker.pack_start (*hbox, true, true);
632 global_hpacker.pack_start (global_vpacker, true, true);
634 set_name ("EditorWindow");
635 add_accel_group (ActionManager::ui_manager->get_accel_group());
637 status_bar_hpacker.show ();
639 vpacker.pack_end (status_bar_hpacker, false, false);
640 vpacker.pack_end (global_hpacker, true, true);
642 /* register actions now so that set_state() can find them and set toggles/checks etc */
645 /* when we start using our own keybinding system for the editor, this
646 * will be uncommented
652 set_zoom_focus (zoom_focus);
653 set_visible_track_count (_visible_track_count);
654 _snap_type = SnapToBeat;
655 set_snap_to (_snap_type);
656 _snap_mode = SnapOff;
657 set_snap_mode (_snap_mode);
658 set_mouse_mode (MouseObject, true);
659 pre_internal_mouse_mode = MouseObject;
660 pre_internal_snap_type = _snap_type;
661 pre_internal_snap_mode = _snap_mode;
662 internal_snap_type = _snap_type;
663 internal_snap_mode = _snap_mode;
664 set_edit_point_preference (EditAtMouse, true);
666 _playlist_selector = new PlaylistSelector();
667 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
669 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
673 nudge_forward_button.set_name ("nudge button");
674 // nudge_forward_button.add_elements (ArdourButton::Inset);
675 nudge_forward_button.set_image(::get_icon("nudge_right"));
677 nudge_backward_button.set_name ("nudge button");
678 // nudge_backward_button.add_elements (ArdourButton::Inset);
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 ()) {
898 /* XXX: this is a bit unfortunate; it would probably
899 be nicer if we could just call show () above rather
900 than needing the show_all ()
903 /* re-hide stuff if necessary */
904 editor_list_button_toggled ();
905 parameter_changed ("show-summary");
906 parameter_changed ("show-group-tabs");
907 parameter_changed ("show-zoom-tools");
909 /* now reset all audio_time_axis heights, because widgets might need
915 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
916 tv = (static_cast<TimeAxisView*>(*i));
920 if (current_mixer_strip) {
921 current_mixer_strip->hide_things ();
922 current_mixer_strip->parameter_changed ("mixer-element-visibility");
930 Editor::instant_save ()
932 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
937 _session->add_instant_xml(get_state());
939 Config->add_instant_xml(get_state());
944 Editor::control_vertical_zoom_in_all ()
946 tav_zoom_smooth (false, true);
950 Editor::control_vertical_zoom_out_all ()
952 tav_zoom_smooth (true, true);
956 Editor::control_vertical_zoom_in_selected ()
958 tav_zoom_smooth (false, false);
962 Editor::control_vertical_zoom_out_selected ()
964 tav_zoom_smooth (true, false);
968 Editor::control_view (uint32_t view)
970 goto_visual_state (view);
974 Editor::control_unselect ()
976 selection->clear_tracks ();
980 Editor::control_select (uint32_t rid, Selection::Operation op)
982 /* handles the (static) signal from the ControlProtocol class that
983 * requests setting the selected track to a given RID
990 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
996 TimeAxisView* tav = axis_view_from_route (r);
1000 case Selection::Add:
1001 selection->add (tav);
1003 case Selection::Toggle:
1004 selection->toggle (tav);
1006 case Selection::Extend:
1008 case Selection::Set:
1009 selection->set (tav);
1013 selection->clear_tracks ();
1018 Editor::control_step_tracks_up ()
1020 scroll_tracks_up_line ();
1024 Editor::control_step_tracks_down ()
1026 scroll_tracks_down_line ();
1030 Editor::control_scroll (float fraction)
1032 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1038 double step = fraction * current_page_samples();
1041 _control_scroll_target is an optional<T>
1043 it acts like a pointer to an framepos_t, with
1044 a operator conversion to boolean to check
1045 that it has a value could possibly use
1046 playhead_cursor->current_frame to store the
1047 value and a boolean in the class to know
1048 when it's out of date
1051 if (!_control_scroll_target) {
1052 _control_scroll_target = _session->transport_frame();
1053 _dragging_playhead = true;
1056 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1057 *_control_scroll_target = 0;
1058 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1059 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1061 *_control_scroll_target += (framepos_t) floor (step);
1064 /* move visuals, we'll catch up with it later */
1066 playhead_cursor->set_position (*_control_scroll_target);
1067 UpdateAllTransportClocks (*_control_scroll_target);
1069 if (*_control_scroll_target > (current_page_samples() / 2)) {
1070 /* try to center PH in window */
1071 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1077 Now we do a timeout to actually bring the session to the right place
1078 according to the playhead. This is to avoid reading disk buffers on every
1079 call to control_scroll, which is driven by ScrollTimeline and therefore
1080 probably by a control surface wheel which can generate lots of events.
1082 /* cancel the existing timeout */
1084 control_scroll_connection.disconnect ();
1086 /* add the next timeout */
1088 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1092 Editor::deferred_control_scroll (framepos_t /*target*/)
1094 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1095 // reset for next stream
1096 _control_scroll_target = boost::none;
1097 _dragging_playhead = false;
1102 Editor::access_action (std::string action_group, std::string action_item)
1108 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1111 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1119 Editor::on_realize ()
1121 Window::on_realize ();
1124 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1125 start_lock_event_timing ();
1128 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1132 Editor::start_lock_event_timing ()
1134 /* check if we should lock the GUI every 30 seconds */
1136 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1140 Editor::generic_event_handler (GdkEvent* ev)
1143 case GDK_BUTTON_PRESS:
1144 case GDK_BUTTON_RELEASE:
1145 case GDK_MOTION_NOTIFY:
1147 case GDK_KEY_RELEASE:
1148 gettimeofday (&last_event_time, 0);
1157 Editor::lock_timeout_callback ()
1159 struct timeval now, delta;
1161 gettimeofday (&now, 0);
1163 timersub (&now, &last_event_time, &delta);
1165 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1167 /* don't call again. Returning false will effectively
1168 disconnect us from the timer callback.
1170 unlock() will call start_lock_event_timing() to get things
1180 Editor::map_position_change (framepos_t frame)
1182 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1184 if (_session == 0) {
1188 if (_follow_playhead) {
1189 center_screen (frame);
1192 playhead_cursor->set_position (frame);
1196 Editor::center_screen (framepos_t frame)
1198 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1200 /* if we're off the page, then scroll.
1203 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1204 center_screen_internal (frame, page);
1209 Editor::center_screen_internal (framepos_t frame, float page)
1214 frame -= (framepos_t) page;
1219 reset_x_origin (frame);
1224 Editor::update_title ()
1226 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1229 bool dirty = _session->dirty();
1231 string session_name;
1233 if (_session->snap_name() != _session->name()) {
1234 session_name = _session->snap_name();
1236 session_name = _session->name();
1240 session_name = "*" + session_name;
1243 WindowTitle title(session_name);
1244 title += Glib::get_application_name();
1245 set_title (title.get_string());
1247 /* ::session_going_away() will have taken care of it */
1252 Editor::set_session (Session *t)
1254 SessionHandlePtr::set_session (t);
1260 _playlist_selector->set_session (_session);
1261 nudge_clock->set_session (_session);
1262 _summary->set_session (_session);
1263 _group_tabs->set_session (_session);
1264 _route_groups->set_session (_session);
1265 _regions->set_session (_session);
1266 _snapshots->set_session (_session);
1267 _routes->set_session (_session);
1268 _locations->set_session (_session);
1270 if (rhythm_ferret) {
1271 rhythm_ferret->set_session (_session);
1274 if (analysis_window) {
1275 analysis_window->set_session (_session);
1279 sfbrowser->set_session (_session);
1282 compute_fixed_ruler_scale ();
1284 /* Make sure we have auto loop and auto punch ranges */
1286 Location* loc = _session->locations()->auto_loop_location();
1288 loc->set_name (_("Loop"));
1291 loc = _session->locations()->auto_punch_location();
1294 loc->set_name (_("Punch"));
1297 refresh_location_display ();
1299 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1300 the selected Marker; this needs the LocationMarker list to be available.
1302 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1303 set_state (*node, Stateful::loading_state_version);
1305 /* catch up with the playhead */
1307 _session->request_locate (playhead_cursor->current_frame ());
1308 _pending_initial_locate = true;
1312 /* These signals can all be emitted by a non-GUI thread. Therefore the
1313 handlers for them must not attempt to directly interact with the GUI,
1314 but use PBD::Signal<T>::connect() which accepts an event loop
1315 ("context") where the handler will be asked to run.
1318 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1319 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1320 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1321 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1322 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1323 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1324 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1325 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1326 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1327 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1328 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1329 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1330 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1331 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1333 playhead_cursor->show ();
1335 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1336 Config->map_parameters (pc);
1337 _session->config.map_parameters (pc);
1339 restore_ruler_visibility ();
1340 //tempo_map_changed (PropertyChange (0));
1341 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1343 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1344 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1347 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1348 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1351 switch (_snap_type) {
1352 case SnapToRegionStart:
1353 case SnapToRegionEnd:
1354 case SnapToRegionSync:
1355 case SnapToRegionBoundary:
1356 build_region_boundary_cache ();
1363 /* register for undo history */
1364 _session->register_with_memento_command_factory(id(), this);
1366 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1368 start_updating_meters ();
1372 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1374 if (a->get_name() == "RegionMenu") {
1375 /* When the main menu's region menu is opened, we setup the actions so that they look right
1376 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1377 so we resensitize all region actions when the entered regionview or the region selection
1378 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1379 happens after the region context menu is opened. So we set a flag here, too.
1383 sensitize_the_right_region_actions ();
1384 _last_region_menu_was_main = true;
1389 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1391 using namespace Menu_Helpers;
1393 void (Editor::*emf)(FadeShape);
1394 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1397 images = &_xfade_in_images;
1398 emf = &Editor::set_fade_in_shape;
1400 images = &_xfade_out_images;
1401 emf = &Editor::set_fade_out_shape;
1406 _("Linear (for highly correlated material)"),
1407 *(*images)[FadeLinear],
1408 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1412 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1416 _("Constant power"),
1417 *(*images)[FadeConstantPower],
1418 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1421 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1426 *(*images)[FadeSymmetric],
1427 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1431 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1436 *(*images)[FadeSlow],
1437 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1440 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1445 *(*images)[FadeFast],
1446 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1449 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1452 /** Pop up a context menu for when the user clicks on a start crossfade */
1454 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1456 using namespace Menu_Helpers;
1457 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1460 MenuList& items (xfade_in_context_menu.items());
1463 if (arv->audio_region()->fade_in_active()) {
1464 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1466 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1469 items.push_back (SeparatorElem());
1470 fill_xfade_menu (items, true);
1472 xfade_in_context_menu.popup (button, time);
1475 /** Pop up a context menu for when the user clicks on an end crossfade */
1477 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1479 using namespace Menu_Helpers;
1480 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1483 MenuList& items (xfade_out_context_menu.items());
1486 if (arv->audio_region()->fade_out_active()) {
1487 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1489 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1492 items.push_back (SeparatorElem());
1493 fill_xfade_menu (items, false);
1495 xfade_out_context_menu.popup (button, time);
1499 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1501 using namespace Menu_Helpers;
1502 Menu* (Editor::*build_menu_function)();
1505 switch (item_type) {
1507 case RegionViewName:
1508 case RegionViewNameHighlight:
1509 case LeftFrameHandle:
1510 case RightFrameHandle:
1511 if (with_selection) {
1512 build_menu_function = &Editor::build_track_selection_context_menu;
1514 build_menu_function = &Editor::build_track_region_context_menu;
1519 if (with_selection) {
1520 build_menu_function = &Editor::build_track_selection_context_menu;
1522 build_menu_function = &Editor::build_track_context_menu;
1527 if (clicked_routeview->track()) {
1528 build_menu_function = &Editor::build_track_context_menu;
1530 build_menu_function = &Editor::build_track_bus_context_menu;
1535 /* probably shouldn't happen but if it does, we don't care */
1539 menu = (this->*build_menu_function)();
1540 menu->set_name ("ArdourContextMenu");
1542 /* now handle specific situations */
1544 switch (item_type) {
1546 case RegionViewName:
1547 case RegionViewNameHighlight:
1548 case LeftFrameHandle:
1549 case RightFrameHandle:
1550 if (!with_selection) {
1551 if (region_edit_menu_split_item) {
1552 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1553 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1555 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1558 if (region_edit_menu_split_multichannel_item) {
1559 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1560 region_edit_menu_split_multichannel_item->set_sensitive (true);
1562 region_edit_menu_split_multichannel_item->set_sensitive (false);
1575 /* probably shouldn't happen but if it does, we don't care */
1579 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1581 /* Bounce to disk */
1583 using namespace Menu_Helpers;
1584 MenuList& edit_items = menu->items();
1586 edit_items.push_back (SeparatorElem());
1588 switch (clicked_routeview->audio_track()->freeze_state()) {
1589 case AudioTrack::NoFreeze:
1590 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1593 case AudioTrack::Frozen:
1594 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1597 case AudioTrack::UnFrozen:
1598 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1604 if (item_type == StreamItem && clicked_routeview) {
1605 clicked_routeview->build_underlay_menu(menu);
1608 /* When the region menu is opened, we setup the actions so that they look right
1611 sensitize_the_right_region_actions ();
1612 _last_region_menu_was_main = false;
1614 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1615 menu->popup (button, time);
1619 Editor::build_track_context_menu ()
1621 using namespace Menu_Helpers;
1623 MenuList& edit_items = track_context_menu.items();
1626 add_dstream_context_items (edit_items);
1627 return &track_context_menu;
1631 Editor::build_track_bus_context_menu ()
1633 using namespace Menu_Helpers;
1635 MenuList& edit_items = track_context_menu.items();
1638 add_bus_context_items (edit_items);
1639 return &track_context_menu;
1643 Editor::build_track_region_context_menu ()
1645 using namespace Menu_Helpers;
1646 MenuList& edit_items = track_region_context_menu.items();
1649 /* we've just cleared the track region context menu, so the menu that these
1650 two items were on will have disappeared; stop them dangling.
1652 region_edit_menu_split_item = 0;
1653 region_edit_menu_split_multichannel_item = 0;
1655 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1658 boost::shared_ptr<Track> tr;
1659 boost::shared_ptr<Playlist> pl;
1661 if ((tr = rtv->track())) {
1662 add_region_context_items (edit_items, tr);
1666 add_dstream_context_items (edit_items);
1668 return &track_region_context_menu;
1672 Editor::analyze_region_selection ()
1674 if (analysis_window == 0) {
1675 analysis_window = new AnalysisWindow();
1678 analysis_window->set_session(_session);
1680 analysis_window->show_all();
1683 analysis_window->set_regionmode();
1684 analysis_window->analyze();
1686 analysis_window->present();
1690 Editor::analyze_range_selection()
1692 if (analysis_window == 0) {
1693 analysis_window = new AnalysisWindow();
1696 analysis_window->set_session(_session);
1698 analysis_window->show_all();
1701 analysis_window->set_rangemode();
1702 analysis_window->analyze();
1704 analysis_window->present();
1708 Editor::build_track_selection_context_menu ()
1710 using namespace Menu_Helpers;
1711 MenuList& edit_items = track_selection_context_menu.items();
1712 edit_items.clear ();
1714 add_selection_context_items (edit_items);
1715 // edit_items.push_back (SeparatorElem());
1716 // add_dstream_context_items (edit_items);
1718 return &track_selection_context_menu;
1722 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1724 using namespace Menu_Helpers;
1726 /* OK, stick the region submenu at the top of the list, and then add
1730 RegionSelection rs = get_regions_from_selection_and_entered ();
1732 string::size_type pos = 0;
1733 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1735 /* we have to hack up the region name because "_" has a special
1736 meaning for menu titles.
1739 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1740 menu_item_name.replace (pos, 1, "__");
1744 if (_popup_region_menu_item == 0) {
1745 _popup_region_menu_item = new MenuItem (menu_item_name);
1746 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1747 _popup_region_menu_item->show ();
1749 _popup_region_menu_item->set_label (menu_item_name);
1752 const framepos_t position = get_preferred_edit_position (false, true);
1754 edit_items.push_back (*_popup_region_menu_item);
1755 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1756 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1758 edit_items.push_back (SeparatorElem());
1761 /** Add context menu items relevant to selection ranges.
1762 * @param edit_items List to add the items to.
1765 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1767 using namespace Menu_Helpers;
1769 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1770 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1772 edit_items.push_back (SeparatorElem());
1773 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1775 edit_items.push_back (SeparatorElem());
1776 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1778 edit_items.push_back (SeparatorElem());
1780 edit_items.push_back (
1782 _("Move Range Start to Previous Region Boundary"),
1783 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1787 edit_items.push_back (
1789 _("Move Range Start to Next Region Boundary"),
1790 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1794 edit_items.push_back (
1796 _("Move Range End to Previous Region Boundary"),
1797 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1801 edit_items.push_back (
1803 _("Move Range End to Next Region Boundary"),
1804 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1808 edit_items.push_back (SeparatorElem());
1809 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1810 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1812 edit_items.push_back (SeparatorElem());
1813 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1815 edit_items.push_back (SeparatorElem());
1816 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1817 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1819 edit_items.push_back (SeparatorElem());
1820 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1822 edit_items.push_back (SeparatorElem());
1823 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1824 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1825 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1827 edit_items.push_back (SeparatorElem());
1828 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1829 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1830 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1831 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1832 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1833 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1834 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1840 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1842 using namespace Menu_Helpers;
1846 Menu *play_menu = manage (new Menu);
1847 MenuList& play_items = play_menu->items();
1848 play_menu->set_name ("ArdourContextMenu");
1850 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1851 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1852 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1853 play_items.push_back (SeparatorElem());
1854 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1856 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1860 Menu *select_menu = manage (new Menu);
1861 MenuList& select_items = select_menu->items();
1862 select_menu->set_name ("ArdourContextMenu");
1864 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1865 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1866 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1867 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1868 select_items.push_back (SeparatorElem());
1869 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1870 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1871 select_items.push_back (SeparatorElem());
1872 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1873 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1874 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1875 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1876 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1877 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1878 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1880 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1884 Menu *cutnpaste_menu = manage (new Menu);
1885 MenuList& cutnpaste_items = cutnpaste_menu->items();
1886 cutnpaste_menu->set_name ("ArdourContextMenu");
1888 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1889 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1890 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1892 cutnpaste_items.push_back (SeparatorElem());
1894 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1895 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1897 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1899 /* Adding new material */
1901 edit_items.push_back (SeparatorElem());
1902 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1903 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1907 Menu *nudge_menu = manage (new Menu());
1908 MenuList& nudge_items = nudge_menu->items();
1909 nudge_menu->set_name ("ArdourContextMenu");
1911 edit_items.push_back (SeparatorElem());
1912 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1913 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1914 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1915 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1917 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1921 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1923 using namespace Menu_Helpers;
1927 Menu *play_menu = manage (new Menu);
1928 MenuList& play_items = play_menu->items();
1929 play_menu->set_name ("ArdourContextMenu");
1931 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1932 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1933 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1937 Menu *select_menu = manage (new Menu);
1938 MenuList& select_items = select_menu->items();
1939 select_menu->set_name ("ArdourContextMenu");
1941 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1942 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1943 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1944 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1945 select_items.push_back (SeparatorElem());
1946 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1947 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1948 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1949 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1951 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1955 Menu *cutnpaste_menu = manage (new Menu);
1956 MenuList& cutnpaste_items = cutnpaste_menu->items();
1957 cutnpaste_menu->set_name ("ArdourContextMenu");
1959 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1960 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1961 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1963 Menu *nudge_menu = manage (new Menu());
1964 MenuList& nudge_items = nudge_menu->items();
1965 nudge_menu->set_name ("ArdourContextMenu");
1967 edit_items.push_back (SeparatorElem());
1968 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1969 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1970 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1971 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1973 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1977 Editor::snap_type() const
1983 Editor::snap_mode() const
1989 Editor::set_snap_to (SnapType st)
1991 unsigned int snap_ind = (unsigned int)st;
1995 if (snap_ind > snap_type_strings.size() - 1) {
1997 _snap_type = (SnapType)snap_ind;
2000 string str = snap_type_strings[snap_ind];
2002 if (str != snap_type_selector.get_text()) {
2003 snap_type_selector.set_text (str);
2008 switch (_snap_type) {
2009 case SnapToBeatDiv128:
2010 case SnapToBeatDiv64:
2011 case SnapToBeatDiv32:
2012 case SnapToBeatDiv28:
2013 case SnapToBeatDiv24:
2014 case SnapToBeatDiv20:
2015 case SnapToBeatDiv16:
2016 case SnapToBeatDiv14:
2017 case SnapToBeatDiv12:
2018 case SnapToBeatDiv10:
2019 case SnapToBeatDiv8:
2020 case SnapToBeatDiv7:
2021 case SnapToBeatDiv6:
2022 case SnapToBeatDiv5:
2023 case SnapToBeatDiv4:
2024 case SnapToBeatDiv3:
2025 case SnapToBeatDiv2: {
2026 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2027 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2029 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2030 current_bbt_points_begin, current_bbt_points_end);
2031 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2032 current_bbt_points_begin, current_bbt_points_end);
2033 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2037 case SnapToRegionStart:
2038 case SnapToRegionEnd:
2039 case SnapToRegionSync:
2040 case SnapToRegionBoundary:
2041 build_region_boundary_cache ();
2049 SnapChanged (); /* EMIT SIGNAL */
2053 Editor::set_snap_mode (SnapMode mode)
2055 string str = snap_mode_strings[(int)mode];
2057 if (_internal_editing) {
2058 internal_snap_mode = mode;
2060 pre_internal_snap_mode = mode;
2065 if (str != snap_mode_selector.get_text ()) {
2066 snap_mode_selector.set_text (str);
2072 Editor::set_edit_point_preference (EditPoint ep, bool force)
2074 bool changed = (_edit_point != ep);
2077 string str = edit_point_strings[(int)ep];
2079 if (Profile->get_mixbus())
2080 if (ep == EditAtSelectedMarker)
2081 ep = EditAtPlayhead;
2083 if (str != edit_point_selector.get_text ()) {
2084 edit_point_selector.set_text (str);
2087 reset_canvas_cursor ();
2089 if (!force && !changed) {
2093 const char* action=NULL;
2095 switch (_edit_point) {
2096 case EditAtPlayhead:
2097 action = "edit-at-playhead";
2099 case EditAtSelectedMarker:
2100 action = "edit-at-marker";
2103 action = "edit-at-mouse";
2107 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2109 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2113 bool in_track_canvas;
2115 if (!mouse_frame (foo, in_track_canvas)) {
2116 in_track_canvas = false;
2119 reset_canvas_action_sensitivity (in_track_canvas);
2125 Editor::set_state (const XMLNode& node, int /*version*/)
2127 const XMLProperty* prop;
2134 g.base_width = default_width;
2135 g.base_height = default_height;
2139 if ((geometry = find_named_node (node, "geometry")) != 0) {
2143 if ((prop = geometry->property("x_size")) == 0) {
2144 prop = geometry->property ("x-size");
2147 g.base_width = atoi(prop->value());
2149 if ((prop = geometry->property("y_size")) == 0) {
2150 prop = geometry->property ("y-size");
2153 g.base_height = atoi(prop->value());
2156 if ((prop = geometry->property ("x_pos")) == 0) {
2157 prop = geometry->property ("x-pos");
2160 x = atoi (prop->value());
2163 if ((prop = geometry->property ("y_pos")) == 0) {
2164 prop = geometry->property ("y-pos");
2167 y = atoi (prop->value());
2171 set_default_size (g.base_width, g.base_height);
2174 if (_session && (prop = node.property ("playhead"))) {
2176 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2177 playhead_cursor->set_position (pos);
2179 playhead_cursor->set_position (0);
2182 if ((prop = node.property ("mixer-width"))) {
2183 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2186 if ((prop = node.property ("zoom-focus"))) {
2187 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2190 if ((prop = node.property ("zoom"))) {
2191 /* older versions of ardour used floating point samples_per_pixel */
2192 double f = PBD::atof (prop->value());
2193 reset_zoom (llrintf (f));
2195 reset_zoom (samples_per_pixel);
2198 if ((prop = node.property ("visible-track-count"))) {
2199 set_visible_track_count (PBD::atoi (prop->value()));
2202 if ((prop = node.property ("snap-to"))) {
2203 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2206 if ((prop = node.property ("snap-mode"))) {
2207 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2210 if ((prop = node.property ("internal-snap-to"))) {
2211 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2214 if ((prop = node.property ("internal-snap-mode"))) {
2215 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2218 if ((prop = node.property ("pre-internal-snap-to"))) {
2219 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2223 if ((prop = node.property ("pre-internal-snap-mode"))) {
2224 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2227 if ((prop = node.property ("mouse-mode"))) {
2228 MouseMode m = str2mousemode(prop->value());
2229 set_mouse_mode (m, true);
2231 set_mouse_mode (MouseObject, true);
2234 if ((prop = node.property ("left-frame")) != 0) {
2236 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2240 reset_x_origin (pos);
2244 if ((prop = node.property ("y-origin")) != 0) {
2245 reset_y_origin (atof (prop->value ()));
2248 if ((prop = node.property ("internal-edit"))) {
2249 bool yn = string_is_affirmative (prop->value());
2250 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2252 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2253 tact->set_active (!yn);
2254 tact->set_active (yn);
2258 if ((prop = node.property ("join-object-range"))) {
2259 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2260 bool yn = string_is_affirmative (prop->value());
2262 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2263 tact->set_active (!yn);
2264 tact->set_active (yn);
2266 set_mouse_mode(mouse_mode, true);
2269 if ((prop = node.property ("edit-point"))) {
2270 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2273 if ((prop = node.property ("show-measures"))) {
2274 bool yn = string_is_affirmative (prop->value());
2275 _show_measures = yn;
2276 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2278 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2279 /* do it twice to force the change */
2280 tact->set_active (!yn);
2281 tact->set_active (yn);
2285 if ((prop = node.property ("follow-playhead"))) {
2286 bool yn = string_is_affirmative (prop->value());
2287 set_follow_playhead (yn);
2288 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2290 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2291 if (tact->get_active() != yn) {
2292 tact->set_active (yn);
2297 if ((prop = node.property ("stationary-playhead"))) {
2298 bool yn = string_is_affirmative (prop->value());
2299 set_stationary_playhead (yn);
2300 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2302 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2303 if (tact->get_active() != yn) {
2304 tact->set_active (yn);
2309 if ((prop = node.property ("region-list-sort-type"))) {
2310 RegionListSortType st;
2311 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2314 if ((prop = node.property ("show-editor-mixer"))) {
2316 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2319 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2320 bool yn = string_is_affirmative (prop->value());
2322 /* do it twice to force the change */
2324 tact->set_active (!yn);
2325 tact->set_active (yn);
2328 if ((prop = node.property ("show-editor-list"))) {
2330 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2333 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2334 bool yn = string_is_affirmative (prop->value());
2336 /* do it twice to force the change */
2338 tact->set_active (!yn);
2339 tact->set_active (yn);
2342 if ((prop = node.property (X_("editor-list-page")))) {
2343 _the_notebook.set_current_page (atoi (prop->value ()));
2346 if ((prop = node.property (X_("show-marker-lines")))) {
2347 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2349 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2350 bool yn = string_is_affirmative (prop->value ());
2352 tact->set_active (!yn);
2353 tact->set_active (yn);
2356 XMLNodeList children = node.children ();
2357 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2358 selection->set_state (**i, Stateful::current_state_version);
2359 _regions->set_state (**i);
2362 if ((prop = node.property ("maximised"))) {
2363 bool yn = string_is_affirmative (prop->value());
2364 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2366 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2367 bool fs = tact && tact->get_active();
2369 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2373 if ((prop = node.property ("nudge-clock-value"))) {
2375 sscanf (prop->value().c_str(), "%" PRId64, &f);
2376 nudge_clock->set (f);
2378 nudge_clock->set_mode (AudioClock::Timecode);
2379 nudge_clock->set (_session->frame_rate() * 5, true);
2386 Editor::get_state ()
2388 XMLNode* node = new XMLNode ("Editor");
2391 id().print (buf, sizeof (buf));
2392 node->add_property ("id", buf);
2394 if (is_realized()) {
2395 Glib::RefPtr<Gdk::Window> win = get_window();
2397 int x, y, width, height;
2398 win->get_root_origin(x, y);
2399 win->get_size(width, height);
2401 XMLNode* geometry = new XMLNode ("geometry");
2403 snprintf(buf, sizeof(buf), "%d", width);
2404 geometry->add_property("x-size", string(buf));
2405 snprintf(buf, sizeof(buf), "%d", height);
2406 geometry->add_property("y-size", string(buf));
2407 snprintf(buf, sizeof(buf), "%d", x);
2408 geometry->add_property("x-pos", string(buf));
2409 snprintf(buf, sizeof(buf), "%d", y);
2410 geometry->add_property("y-pos", string(buf));
2411 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2412 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2413 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2414 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2415 geometry->add_property("edit-vertical-pane-pos", string(buf));
2417 node->add_child_nocopy (*geometry);
2420 maybe_add_mixer_strip_width (*node);
2422 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2424 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2425 node->add_property ("zoom", buf);
2426 node->add_property ("snap-to", enum_2_string (_snap_type));
2427 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2428 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2429 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2430 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2431 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2432 node->add_property ("edit-point", enum_2_string (_edit_point));
2433 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2434 node->add_property ("visible-track-count", buf);
2436 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2437 node->add_property ("playhead", buf);
2438 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2439 node->add_property ("left-frame", buf);
2440 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2441 node->add_property ("y-origin", buf);
2443 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2444 node->add_property ("maximised", _maximised ? "yes" : "no");
2445 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2446 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2447 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2448 node->add_property ("mouse-mode", enum2str(mouse_mode));
2449 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2450 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2452 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2454 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2455 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2458 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2460 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2461 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2464 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2465 node->add_property (X_("editor-list-page"), buf);
2467 if (button_bindings) {
2468 XMLNode* bb = new XMLNode (X_("Buttons"));
2469 button_bindings->save (*bb);
2470 node->add_child_nocopy (*bb);
2473 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2475 node->add_child_nocopy (selection->get_state ());
2476 node->add_child_nocopy (_regions->get_state ());
2478 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2479 node->add_property ("nudge-clock-value", buf);
2484 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2485 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2487 * @return pair: TimeAxisView that y is over, layer index.
2489 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2490 * in stacked or expanded region display mode, otherwise 0.
2492 std::pair<TimeAxisView *, double>
2493 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2495 if (!trackview_relative_offset) {
2496 y -= _trackview_group->canvas_origin().y;
2500 return std::make_pair ( (TimeAxisView *) 0, 0);
2503 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2505 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2512 return std::make_pair ( (TimeAxisView *) 0, 0);
2515 /** Snap a position to the grid, if appropriate, taking into account current
2516 * grid settings and also the state of any snap modifier keys that may be pressed.
2517 * @param start Position to snap.
2518 * @param event Event to get current key modifier information from, or 0.
2521 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2523 if (!_session || !event) {
2527 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2528 if (_snap_mode == SnapOff) {
2529 snap_to_internal (start, direction, for_mark);
2532 if (_snap_mode != SnapOff) {
2533 snap_to_internal (start, direction, for_mark);
2539 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2541 if (!_session || _snap_mode == SnapOff) {
2545 snap_to_internal (start, direction, for_mark);
2549 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2551 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2552 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2554 switch (_snap_type) {
2555 case SnapToTimecodeFrame:
2556 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2557 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2559 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2563 case SnapToTimecodeSeconds:
2564 if (_session->config.get_timecode_offset_negative()) {
2565 start += _session->config.get_timecode_offset ();
2567 start -= _session->config.get_timecode_offset ();
2569 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2570 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2572 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2575 if (_session->config.get_timecode_offset_negative()) {
2576 start -= _session->config.get_timecode_offset ();
2578 start += _session->config.get_timecode_offset ();
2582 case SnapToTimecodeMinutes:
2583 if (_session->config.get_timecode_offset_negative()) {
2584 start += _session->config.get_timecode_offset ();
2586 start -= _session->config.get_timecode_offset ();
2588 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2589 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2591 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2593 if (_session->config.get_timecode_offset_negative()) {
2594 start -= _session->config.get_timecode_offset ();
2596 start += _session->config.get_timecode_offset ();
2600 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2606 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2608 const framepos_t one_second = _session->frame_rate();
2609 const framepos_t one_minute = _session->frame_rate() * 60;
2610 framepos_t presnap = start;
2614 switch (_snap_type) {
2615 case SnapToTimecodeFrame:
2616 case SnapToTimecodeSeconds:
2617 case SnapToTimecodeMinutes:
2618 return timecode_snap_to_internal (start, direction, for_mark);
2621 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2622 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2624 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2629 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2630 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2632 start = (framepos_t) floor ((double) start / one_second) * one_second;
2637 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2638 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2640 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2645 start = _session->tempo_map().round_to_bar (start, direction);
2649 start = _session->tempo_map().round_to_beat (start, direction);
2652 case SnapToBeatDiv128:
2653 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2655 case SnapToBeatDiv64:
2656 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2658 case SnapToBeatDiv32:
2659 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2661 case SnapToBeatDiv28:
2662 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2664 case SnapToBeatDiv24:
2665 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2667 case SnapToBeatDiv20:
2668 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2670 case SnapToBeatDiv16:
2671 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2673 case SnapToBeatDiv14:
2674 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2676 case SnapToBeatDiv12:
2677 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2679 case SnapToBeatDiv10:
2680 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2682 case SnapToBeatDiv8:
2683 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2685 case SnapToBeatDiv7:
2686 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2688 case SnapToBeatDiv6:
2689 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2691 case SnapToBeatDiv5:
2692 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2694 case SnapToBeatDiv4:
2695 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2697 case SnapToBeatDiv3:
2698 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2700 case SnapToBeatDiv2:
2701 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2709 _session->locations()->marks_either_side (start, before, after);
2711 if (before == max_framepos && after == max_framepos) {
2712 /* No marks to snap to, so just don't snap */
2714 } else if (before == max_framepos) {
2716 } else if (after == max_framepos) {
2718 } else if (before != max_framepos && after != max_framepos) {
2719 /* have before and after */
2720 if ((start - before) < (after - start)) {
2729 case SnapToRegionStart:
2730 case SnapToRegionEnd:
2731 case SnapToRegionSync:
2732 case SnapToRegionBoundary:
2733 if (!region_boundary_cache.empty()) {
2735 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2736 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2738 if (direction > 0) {
2739 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2741 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2744 if (next != region_boundary_cache.begin ()) {
2749 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2750 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2752 if (start > (p + n) / 2) {
2761 switch (_snap_mode) {
2767 if (presnap > start) {
2768 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2772 } else if (presnap < start) {
2773 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2779 /* handled at entry */
2787 Editor::setup_toolbar ()
2789 HBox* mode_box = manage(new HBox);
2790 mode_box->set_border_width (2);
2791 mode_box->set_spacing(2);
2793 HBox* mouse_mode_box = manage (new HBox);
2794 HBox* mouse_mode_hbox = manage (new HBox);
2795 VBox* mouse_mode_vbox = manage (new VBox);
2796 Alignment* mouse_mode_align = manage (new Alignment);
2798 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2799 //mouse_mode_size_group->add_widget (smart_mode_button);
2800 mouse_mode_size_group->add_widget (mouse_move_button);
2801 mouse_mode_size_group->add_widget (mouse_cut_button);
2802 mouse_mode_size_group->add_widget (mouse_select_button);
2803 mouse_mode_size_group->add_widget (mouse_zoom_button);
2804 mouse_mode_size_group->add_widget (mouse_gain_button);
2805 mouse_mode_size_group->add_widget (mouse_timefx_button);
2806 mouse_mode_size_group->add_widget (mouse_audition_button);
2807 mouse_mode_size_group->add_widget (mouse_draw_button);
2808 mouse_mode_size_group->add_widget (internal_edit_button);
2810 if (!ARDOUR::Profile->get_small_screen()) {
2811 /* make them just a bit bigger */
2812 mouse_move_button.set_size_request (24, 30);
2814 /* make them just a bit taller */
2815 mouse_move_button.set_size_request (-1, 30);
2817 mouse_mode_hbox->set_spacing (2);
2819 if (!ARDOUR::Profile->get_trx()) {
2820 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2823 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2824 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2826 if (!ARDOUR::Profile->get_mixbus()) {
2827 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2828 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2831 if (!ARDOUR::Profile->get_trx()) {
2832 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2833 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2834 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2835 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2836 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 4);
2839 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2841 mouse_mode_align->add (*mouse_mode_vbox);
2842 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2844 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2846 edit_mode_selector.set_name ("mouse mode button");
2847 edit_mode_selector.add_elements (ArdourButton::Inset);
2849 if (!ARDOUR::Profile->get_trx()) {
2850 mode_box->pack_start (edit_mode_selector, false, false);
2852 mode_box->pack_start (*mouse_mode_box, false, false);
2854 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2855 _mouse_mode_tearoff->set_name ("MouseModeBase");
2856 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2858 if (Profile->get_sae() || Profile->get_mixbus() ) {
2859 _mouse_mode_tearoff->set_can_be_torn_off (false);
2862 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2863 &_mouse_mode_tearoff->tearoff_window()));
2864 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2865 &_mouse_mode_tearoff->tearoff_window(), 1));
2866 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2867 &_mouse_mode_tearoff->tearoff_window()));
2868 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2869 &_mouse_mode_tearoff->tearoff_window(), 1));
2873 _zoom_box.set_spacing (2);
2874 _zoom_box.set_border_width (2);
2878 zoom_preset_selector.set_name ("zoom button");
2879 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2880 zoom_preset_selector.set_size_request (42, -1);
2882 zoom_in_button.set_name ("zoom button");
2883 // zoom_in_button.add_elements ( ArdourButton::Inset );
2884 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2885 zoom_in_button.set_image(::get_icon ("zoom_in"));
2886 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2887 zoom_in_button.set_related_action (act);
2889 zoom_out_button.set_name ("zoom button");
2890 // zoom_out_button.add_elements ( ArdourButton::Inset );
2891 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2892 zoom_out_button.set_image(::get_icon ("zoom_out"));
2893 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2894 zoom_out_button.set_related_action (act);
2896 zoom_out_full_button.set_name ("zoom button");
2897 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2898 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2899 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2900 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2901 zoom_out_full_button.set_related_action (act);
2903 zoom_focus_selector.set_name ("zoom button");
2904 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2906 if (ARDOUR::Profile->get_mixbus()) {
2907 _zoom_box.pack_start (zoom_preset_selector, false, false);
2908 } else if (ARDOUR::Profile->get_trx()) {
2909 mode_box->pack_start (zoom_out_button, false, false);
2910 mode_box->pack_start (zoom_in_button, false, false);
2912 _zoom_box.pack_start (zoom_out_button, false, false);
2913 _zoom_box.pack_start (zoom_in_button, false, false);
2914 _zoom_box.pack_start (zoom_out_full_button, false, false);
2915 _zoom_box.pack_start (zoom_focus_selector, false, false);
2918 /* Track zoom buttons */
2919 visible_tracks_selector.set_name ("zoom button");
2920 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2921 if (Profile->get_mixbus()) {
2922 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2923 visible_tracks_selector.set_size_request (42, -1);
2925 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 40, 2);
2928 tav_expand_button.set_name ("zoom button");
2929 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2930 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2931 tav_expand_button.set_size_request (-1, 20);
2932 tav_expand_button.set_image(::get_icon ("tav_exp"));
2933 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2934 tav_expand_button.set_related_action (act);
2936 tav_shrink_button.set_name ("zoom button");
2937 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2938 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2939 tav_shrink_button.set_size_request (-1, 20);
2940 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2941 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2942 tav_shrink_button.set_related_action (act);
2944 if (ARDOUR::Profile->get_mixbus()) {
2945 _zoom_box.pack_start (visible_tracks_selector);
2946 } else if (ARDOUR::Profile->get_trx()) {
2947 _zoom_box.pack_start (tav_shrink_button);
2948 _zoom_box.pack_start (tav_expand_button);
2950 _zoom_box.pack_start (visible_tracks_selector);
2951 _zoom_box.pack_start (tav_shrink_button);
2952 _zoom_box.pack_start (tav_expand_button);
2955 if (!ARDOUR::Profile->get_trx()) {
2956 _zoom_tearoff = manage (new TearOff (_zoom_box));
2958 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2959 &_zoom_tearoff->tearoff_window()));
2960 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2961 &_zoom_tearoff->tearoff_window(), 0));
2962 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2963 &_zoom_tearoff->tearoff_window()));
2964 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2965 &_zoom_tearoff->tearoff_window(), 0));
2968 if (Profile->get_sae() || Profile->get_mixbus() ) {
2969 _zoom_tearoff->set_can_be_torn_off (false);
2972 snap_box.set_spacing (2);
2973 snap_box.set_border_width (2);
2975 snap_type_selector.set_name ("mouse mode button");
2976 snap_type_selector.add_elements (ArdourButton::Inset);
2978 snap_mode_selector.set_name ("mouse mode button");
2979 snap_mode_selector.add_elements (ArdourButton::Inset);
2981 edit_point_selector.set_name ("mouse mode button");
2982 edit_point_selector.add_elements (ArdourButton::Inset);
2984 snap_box.pack_start (snap_mode_selector, false, false);
2985 snap_box.pack_start (snap_type_selector, false, false);
2986 snap_box.pack_start (edit_point_selector, false, false);
2990 HBox *nudge_box = manage (new HBox);
2991 nudge_box->set_spacing (2);
2992 nudge_box->set_border_width (2);
2994 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2995 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2997 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2998 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3000 nudge_box->pack_start (nudge_backward_button, false, false);
3001 nudge_box->pack_start (nudge_forward_button, false, false);
3002 nudge_box->pack_start (*nudge_clock, false, false);
3005 /* Pack everything in... */
3007 HBox* hbox = manage (new HBox);
3008 hbox->set_spacing(2);
3010 _tools_tearoff = manage (new TearOff (*hbox));
3011 _tools_tearoff->set_name ("MouseModeBase");
3012 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3014 if (Profile->get_sae() || Profile->get_mixbus()) {
3015 _tools_tearoff->set_can_be_torn_off (false);
3018 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3019 &_tools_tearoff->tearoff_window()));
3020 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3021 &_tools_tearoff->tearoff_window(), 0));
3022 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3023 &_tools_tearoff->tearoff_window()));
3024 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3025 &_tools_tearoff->tearoff_window(), 0));
3027 toolbar_hbox.set_spacing (2);
3028 toolbar_hbox.set_border_width (1);
3030 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3031 if (!ARDOUR::Profile->get_trx()) {
3032 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3033 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3036 if (!ARDOUR::Profile->get_trx()) {
3037 hbox->pack_start (snap_box, false, false);
3038 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3039 hbox->pack_start (*nudge_box, false, false);
3041 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3044 hbox->pack_start (panic_box, false, false);
3048 toolbar_base.set_name ("ToolBarBase");
3049 toolbar_base.add (toolbar_hbox);
3051 _toolbar_viewport.add (toolbar_base);
3052 /* stick to the required height but allow width to vary if there's not enough room */
3053 _toolbar_viewport.set_size_request (1, -1);
3055 toolbar_frame.set_shadow_type (SHADOW_OUT);
3056 toolbar_frame.set_name ("BaseFrame");
3057 toolbar_frame.add (_toolbar_viewport);
3061 Editor::build_edit_point_menu ()
3063 using namespace Menu_Helpers;
3065 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3066 if(!Profile->get_mixbus())
3067 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3068 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3070 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, 30, 2);
3074 Editor::build_edit_mode_menu ()
3076 using namespace Menu_Helpers;
3078 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3079 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3080 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3081 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3083 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, 30, 2);
3087 Editor::build_snap_mode_menu ()
3089 using namespace Menu_Helpers;
3091 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3092 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3093 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3095 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, 34, 2);
3099 Editor::build_snap_type_menu ()
3101 using namespace Menu_Helpers;
3103 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3104 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3105 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3106 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3107 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3108 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3109 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3110 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3111 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3112 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3113 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3114 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3115 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3116 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3117 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3118 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3119 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3120 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3121 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3122 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3123 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3124 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3125 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3126 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3134 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, 34, 2);
3139 Editor::setup_tooltips ()
3141 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3142 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3143 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3144 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3145 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3146 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3147 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3148 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3149 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3150 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3151 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3152 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3153 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3154 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3155 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3156 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3157 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3158 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3159 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3160 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3161 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3162 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3163 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3164 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3165 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3166 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3170 Editor::convert_drop_to_paths (
3171 vector<string>& paths,
3172 const RefPtr<Gdk::DragContext>& /*context*/,
3175 const SelectionData& data,
3179 if (_session == 0) {
3183 vector<string> uris = data.get_uris();
3187 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3188 are actually URI lists. So do it by hand.
3191 if (data.get_target() != "text/plain") {
3195 /* Parse the "uri-list" format that Nautilus provides,
3196 where each pathname is delimited by \r\n.
3198 THERE MAY BE NO NULL TERMINATING CHAR!!!
3201 string txt = data.get_text();
3205 p = (char *) malloc (txt.length() + 1);
3206 txt.copy (p, txt.length(), 0);
3207 p[txt.length()] = '\0';
3213 while (g_ascii_isspace (*p))
3217 while (*q && (*q != '\n') && (*q != '\r')) {
3224 while (q > p && g_ascii_isspace (*q))
3229 uris.push_back (string (p, q - p + 1));
3233 p = strchr (p, '\n');
3245 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3246 if ((*i).substr (0,7) == "file://") {
3247 paths.push_back (Glib::filename_from_uri (*i));
3255 Editor::new_tempo_section ()
3260 Editor::map_transport_state ()
3262 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3264 if (_session && _session->transport_stopped()) {
3265 have_pending_keyboard_selection = false;
3268 update_loop_range_view ();
3274 Editor::begin_reversible_command (string name)
3277 _session->begin_reversible_command (name);
3282 Editor::begin_reversible_command (GQuark q)
3285 _session->begin_reversible_command (q);
3290 Editor::commit_reversible_command ()
3293 _session->commit_reversible_command ();
3298 Editor::history_changed ()
3302 if (undo_action && _session) {
3303 if (_session->undo_depth() == 0) {
3304 label = S_("Command|Undo");
3306 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3308 undo_action->property_label() = label;
3311 if (redo_action && _session) {
3312 if (_session->redo_depth() == 0) {
3315 label = string_compose(_("Redo (%1)"), _session->next_redo());
3317 redo_action->property_label() = label;
3322 Editor::duplicate_range (bool with_dialog)
3326 RegionSelection rs = get_regions_from_selection_and_entered ();
3328 if ( selection->time.length() == 0 && rs.empty()) {
3334 ArdourDialog win (_("Duplicate"));
3335 Label label (_("Number of duplications:"));
3336 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3337 SpinButton spinner (adjustment, 0.0, 1);
3340 win.get_vbox()->set_spacing (12);
3341 win.get_vbox()->pack_start (hbox);
3342 hbox.set_border_width (6);
3343 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3345 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3346 place, visually. so do this by hand.
3349 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3350 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3351 spinner.grab_focus();
3357 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3358 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3359 win.set_default_response (RESPONSE_ACCEPT);
3361 spinner.grab_focus ();
3363 switch (win.run ()) {
3364 case RESPONSE_ACCEPT:
3370 times = adjustment.get_value();
3373 if ((current_mouse_mode() == Editing::MouseRange)) {
3374 if (selection->time.length()) {
3375 duplicate_selection (times);
3377 } else if (get_smart_mode()) {
3378 if (selection->time.length()) {
3379 duplicate_selection (times);
3381 duplicate_some_regions (rs, times);
3383 duplicate_some_regions (rs, times);
3388 Editor::set_edit_mode (EditMode m)
3390 Config->set_edit_mode (m);
3394 Editor::cycle_edit_mode ()
3396 switch (Config->get_edit_mode()) {
3398 if (Profile->get_sae()) {
3399 Config->set_edit_mode (Lock);
3401 Config->set_edit_mode (Ripple);
3406 Config->set_edit_mode (Lock);
3409 Config->set_edit_mode (Slide);
3415 Editor::edit_mode_selection_done ( EditMode m )
3417 Config->set_edit_mode ( m );
3421 Editor::snap_type_selection_done (SnapType snaptype)
3423 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3425 ract->set_active ();
3430 Editor::snap_mode_selection_done (SnapMode mode)
3432 RefPtr<RadioAction> ract = snap_mode_action (mode);
3435 ract->set_active (true);
3440 Editor::cycle_edit_point (bool with_marker)
3442 if(Profile->get_mixbus())
3443 with_marker = false;
3445 switch (_edit_point) {
3447 set_edit_point_preference (EditAtPlayhead);
3449 case EditAtPlayhead:
3451 set_edit_point_preference (EditAtSelectedMarker);
3453 set_edit_point_preference (EditAtMouse);
3456 case EditAtSelectedMarker:
3457 set_edit_point_preference (EditAtMouse);
3463 Editor::edit_point_selection_done (EditPoint ep)
3465 set_edit_point_preference ( ep );
3469 Editor::build_zoom_focus_menu ()
3471 using namespace Menu_Helpers;
3473 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3474 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3475 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3476 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3477 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3478 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3480 set_size_request_to_display_given_text (zoom_focus_selector, longest (zoom_focus_strings), 30, 2);
3484 Editor::zoom_focus_selection_done ( ZoomFocus f )
3486 RefPtr<RadioAction> ract = zoom_focus_action (f);
3488 ract->set_active ();
3493 Editor::build_track_count_menu ()
3495 using namespace Menu_Helpers;
3497 if (!Profile->get_mixbus()) {
3498 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3499 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3500 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3501 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3502 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3503 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3504 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3505 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3506 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3507 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3508 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3509 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3510 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3512 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3513 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3514 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3515 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3516 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3517 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3518 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3519 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3520 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3521 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3523 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3524 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3525 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3526 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3527 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3528 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3529 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3530 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3531 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3532 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3533 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3538 Editor::set_zoom_preset (int64_t ms)
3541 temporal_zoom_session();
3545 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3546 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3550 Editor::set_visible_track_count (int32_t n)
3552 _visible_track_count = n;
3554 /* if the canvas hasn't really been allocated any size yet, just
3555 record the desired number of visible tracks and return. when canvas
3556 allocation happens, we will get called again and then we can do the
3560 if (_visible_canvas_height <= 1) {
3567 if (_visible_track_count > 0) {
3568 h = trackviews_height() / _visible_track_count;
3569 std::ostringstream s;
3570 s << _visible_track_count;
3572 } else if (_visible_track_count == 0) {
3574 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3575 if ((*i)->marked_for_display()) {
3579 h = trackviews_height() / n;
3582 /* negative value means that the visible track count has
3583 been overridden by explicit track height changes.
3585 visible_tracks_selector.set_text (X_("*"));
3589 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3590 (*i)->set_height (h);
3593 if (str != visible_tracks_selector.get_text()) {
3594 visible_tracks_selector.set_text (str);
3599 Editor::override_visible_track_count ()
3601 _visible_track_count = -_visible_track_count;
3602 visible_tracks_selector.set_text ( _("*") );
3606 Editor::edit_controls_button_release (GdkEventButton* ev)
3608 if (Keyboard::is_context_menu_event (ev)) {
3609 ARDOUR_UI::instance()->add_route (this);
3610 } else if (ev->button == 1) {
3611 selection->clear_tracks ();
3618 Editor::mouse_select_button_release (GdkEventButton* ev)
3620 /* this handles just right-clicks */
3622 if (ev->button != 3) {
3630 Editor::set_zoom_focus (ZoomFocus f)
3632 string str = zoom_focus_strings[(int)f];
3634 if (str != zoom_focus_selector.get_text()) {
3635 zoom_focus_selector.set_text (str);
3638 if (zoom_focus != f) {
3645 Editor::cycle_zoom_focus ()
3647 switch (zoom_focus) {
3649 set_zoom_focus (ZoomFocusRight);
3651 case ZoomFocusRight:
3652 set_zoom_focus (ZoomFocusCenter);
3654 case ZoomFocusCenter:
3655 set_zoom_focus (ZoomFocusPlayhead);
3657 case ZoomFocusPlayhead:
3658 set_zoom_focus (ZoomFocusMouse);
3660 case ZoomFocusMouse:
3661 set_zoom_focus (ZoomFocusEdit);
3664 set_zoom_focus (ZoomFocusLeft);
3670 Editor::ensure_float (Window& win)
3672 win.set_transient_for (*this);
3676 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3678 /* recover or initialize pane positions. do this here rather than earlier because
3679 we don't want the positions to change the child allocations, which they seem to do.
3685 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3694 XMLNode* geometry = find_named_node (*node, "geometry");
3696 if (which == static_cast<Paned*> (&edit_pane)) {
3698 if (done & Horizontal) {
3702 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3703 _notebook_shrunk = string_is_affirmative (prop->value ());
3706 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3707 /* initial allocation is 90% to canvas, 10% to notebook */
3708 pos = (int) floor (alloc.get_width() * 0.90f);
3709 snprintf (buf, sizeof(buf), "%d", pos);
3711 pos = atoi (prop->value());
3714 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3715 edit_pane.set_position (pos);
3718 done = (Pane) (done | Horizontal);
3720 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3722 if (done & Vertical) {
3726 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3727 /* initial allocation is 90% to canvas, 10% to summary */
3728 pos = (int) floor (alloc.get_height() * 0.90f);
3729 snprintf (buf, sizeof(buf), "%d", pos);
3732 pos = atoi (prop->value());
3735 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3736 editor_summary_pane.set_position (pos);
3739 done = (Pane) (done | Vertical);
3744 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3746 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3747 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3748 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3749 top_hbox.remove (toolbar_frame);
3754 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3756 if (toolbar_frame.get_parent() == 0) {
3757 top_hbox.pack_end (toolbar_frame);
3762 Editor::set_show_measures (bool yn)
3764 if (_show_measures != yn) {
3767 if ((_show_measures = yn) == true) {
3769 tempo_lines->show();
3772 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3773 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3775 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3776 draw_measures (begin, end);
3784 Editor::toggle_follow_playhead ()
3786 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3788 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3789 set_follow_playhead (tact->get_active());
3793 /** @param yn true to follow playhead, otherwise false.
3794 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3797 Editor::set_follow_playhead (bool yn, bool catch_up)
3799 if (_follow_playhead != yn) {
3800 if ((_follow_playhead = yn) == true && catch_up) {
3802 reset_x_origin_to_follow_playhead ();
3809 Editor::toggle_stationary_playhead ()
3811 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3813 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3814 set_stationary_playhead (tact->get_active());
3819 Editor::set_stationary_playhead (bool yn)
3821 if (_stationary_playhead != yn) {
3822 if ((_stationary_playhead = yn) == true) {
3824 // FIXME need a 3.0 equivalent of this 2.X call
3825 // update_current_screen ();
3832 Editor::playlist_selector () const
3834 return *_playlist_selector;
3838 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3842 switch (_snap_type) {
3847 case SnapToBeatDiv128:
3850 case SnapToBeatDiv64:
3853 case SnapToBeatDiv32:
3856 case SnapToBeatDiv28:
3859 case SnapToBeatDiv24:
3862 case SnapToBeatDiv20:
3865 case SnapToBeatDiv16:
3868 case SnapToBeatDiv14:
3871 case SnapToBeatDiv12:
3874 case SnapToBeatDiv10:
3877 case SnapToBeatDiv8:
3880 case SnapToBeatDiv7:
3883 case SnapToBeatDiv6:
3886 case SnapToBeatDiv5:
3889 case SnapToBeatDiv4:
3892 case SnapToBeatDiv3:
3895 case SnapToBeatDiv2:
3901 return _session->tempo_map().meter_at (position).divisions_per_bar();
3906 case SnapToTimecodeFrame:
3907 case SnapToTimecodeSeconds:
3908 case SnapToTimecodeMinutes:
3911 case SnapToRegionStart:
3912 case SnapToRegionEnd:
3913 case SnapToRegionSync:
3914 case SnapToRegionBoundary:
3924 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3928 ret = nudge_clock->current_duration (pos);
3929 next = ret + 1; /* XXXX fix me */
3935 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3937 ArdourDialog dialog (_("Playlist Deletion"));
3938 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3939 "If it is kept, its audio files will not be cleaned.\n"
3940 "If it is deleted, audio files used by it alone will be cleaned."),
3943 dialog.set_position (WIN_POS_CENTER);
3944 dialog.get_vbox()->pack_start (label);
3948 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3949 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3950 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3952 switch (dialog.run ()) {
3953 case RESPONSE_ACCEPT:
3954 /* delete the playlist */
3958 case RESPONSE_REJECT:
3959 /* keep the playlist */
3971 Editor::audio_region_selection_covers (framepos_t where)
3973 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3974 if ((*a)->region()->covers (where)) {
3983 Editor::prepare_for_cleanup ()
3985 cut_buffer->clear_regions ();
3986 cut_buffer->clear_playlists ();
3988 selection->clear_regions ();
3989 selection->clear_playlists ();
3991 _regions->suspend_redisplay ();
3995 Editor::finish_cleanup ()
3997 _regions->resume_redisplay ();
4001 Editor::transport_loop_location()
4004 return _session->locations()->auto_loop_location();
4011 Editor::transport_punch_location()
4014 return _session->locations()->auto_punch_location();
4021 Editor::control_layout_scroll (GdkEventScroll* ev)
4023 /* Just forward to the normal canvas scroll method. The coordinate
4024 systems are different but since the canvas is always larger than the
4025 track headers, and aligned with the trackview area, this will work.
4027 In the not too distant future this layout is going away anyway and
4028 headers will be on the canvas.
4030 return canvas_scroll_event (ev, false);
4034 Editor::session_state_saved (string)
4037 _snapshots->redisplay ();
4041 Editor::update_tearoff_visibility()
4043 bool visible = Config->get_keep_tearoffs();
4044 _mouse_mode_tearoff->set_visible (visible);
4045 _tools_tearoff->set_visible (visible);
4046 if (_zoom_tearoff) {
4047 _zoom_tearoff->set_visible (visible);
4052 Editor::maximise_editing_space ()
4064 Editor::restore_editing_space ()
4076 * Make new playlists for a given track and also any others that belong
4077 * to the same active route group with the `select' property.
4082 Editor::new_playlists (TimeAxisView* v)
4084 begin_reversible_command (_("new playlists"));
4085 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4086 _session->playlists->get (playlists);
4087 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4088 commit_reversible_command ();
4092 * Use a copy of the current playlist for a given track and also any others that belong
4093 * to the same active route group with the `select' property.
4098 Editor::copy_playlists (TimeAxisView* v)
4100 begin_reversible_command (_("copy playlists"));
4101 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4102 _session->playlists->get (playlists);
4103 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4104 commit_reversible_command ();
4107 /** Clear the current playlist for a given track and also any others that belong
4108 * to the same active route group with the `select' property.
4113 Editor::clear_playlists (TimeAxisView* v)
4115 begin_reversible_command (_("clear playlists"));
4116 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4117 _session->playlists->get (playlists);
4118 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4119 commit_reversible_command ();
4123 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4125 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4129 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4131 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4135 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4137 atv.clear_playlist ();
4141 Editor::on_key_press_event (GdkEventKey* ev)
4143 return key_press_focus_accelerator_handler (*this, ev);
4147 Editor::on_key_release_event (GdkEventKey* ev)
4149 return Gtk::Window::on_key_release_event (ev);
4150 // return key_press_focus_accelerator_handler (*this, ev);
4153 /** Queue up a change to the viewport x origin.
4154 * @param frame New x origin.
4157 Editor::reset_x_origin (framepos_t frame)
4159 pending_visual_change.add (VisualChange::TimeOrigin);
4160 pending_visual_change.time_origin = frame;
4161 ensure_visual_change_idle_handler ();
4165 Editor::reset_y_origin (double y)
4167 pending_visual_change.add (VisualChange::YOrigin);
4168 pending_visual_change.y_origin = y;
4169 ensure_visual_change_idle_handler ();
4173 Editor::reset_zoom (framecnt_t spp)
4175 if (spp == samples_per_pixel) {
4179 pending_visual_change.add (VisualChange::ZoomLevel);
4180 pending_visual_change.samples_per_pixel = spp;
4181 ensure_visual_change_idle_handler ();
4185 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4187 reset_x_origin (frame);
4190 if (!no_save_visual) {
4191 undo_visual_stack.push_back (current_visual_state(false));
4195 Editor::VisualState::VisualState (bool with_tracks)
4196 : gui_state (with_tracks ? new GUIObjectState : 0)
4200 Editor::VisualState::~VisualState ()
4205 Editor::VisualState*
4206 Editor::current_visual_state (bool with_tracks)
4208 VisualState* vs = new VisualState (with_tracks);
4209 vs->y_position = vertical_adjustment.get_value();
4210 vs->samples_per_pixel = samples_per_pixel;
4211 vs->leftmost_frame = leftmost_frame;
4212 vs->zoom_focus = zoom_focus;
4215 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4222 Editor::undo_visual_state ()
4224 if (undo_visual_stack.empty()) {
4228 VisualState* vs = undo_visual_stack.back();
4229 undo_visual_stack.pop_back();
4232 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4234 use_visual_state (*vs);
4238 Editor::redo_visual_state ()
4240 if (redo_visual_stack.empty()) {
4244 VisualState* vs = redo_visual_stack.back();
4245 redo_visual_stack.pop_back();
4247 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4249 use_visual_state (*vs);
4253 Editor::swap_visual_state ()
4255 if (undo_visual_stack.empty()) {
4256 redo_visual_state ();
4258 undo_visual_state ();
4263 Editor::use_visual_state (VisualState& vs)
4265 PBD::Unwinder<bool> nsv (no_save_visual, true);
4266 DisplaySuspender ds;
4268 vertical_adjustment.set_value (vs.y_position);
4270 set_zoom_focus (vs.zoom_focus);
4271 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4274 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4276 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4277 (*i)->reset_visual_state ();
4281 _routes->update_visibility ();
4284 /** This is the core function that controls the zoom level of the canvas. It is called
4285 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4286 * @param spp new number of samples per pixel
4289 Editor::set_samples_per_pixel (framecnt_t spp)
4295 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4296 const framecnt_t lots_of_pixels = 4000;
4298 /* if the zoom level is greater than what you'd get trying to display 3
4299 * days of audio on a really big screen, then it's too big.
4302 if (spp * lots_of_pixels > three_days) {
4306 samples_per_pixel = spp;
4309 tempo_lines->tempo_map_changed();
4312 bool const showing_time_selection = selection->time.length() > 0;
4314 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4315 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4316 (*i)->reshow_selection (selection->time);
4320 ZoomChanged (); /* EMIT_SIGNAL */
4322 ArdourCanvas::GtkCanvasViewport* c;
4324 c = get_track_canvas();
4326 c->canvas()->zoomed ();
4329 if (playhead_cursor) {
4330 playhead_cursor->set_position (playhead_cursor->current_frame ());
4333 refresh_location_display();
4334 _summary->set_overlays_dirty ();
4336 update_marker_labels ();
4342 Editor::queue_visual_videotimeline_update ()
4345 * pending_visual_change.add (VisualChange::VideoTimeline);
4346 * or maybe even more specific: which videotimeline-image
4347 * currently it calls update_video_timeline() to update
4348 * _all outdated_ images on the video-timeline.
4349 * see 'exposeimg()' in video_image_frame.cc
4351 ensure_visual_change_idle_handler ();
4355 Editor::ensure_visual_change_idle_handler ()
4357 if (pending_visual_change.idle_handler_id < 0) {
4358 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4359 pending_visual_change.being_handled = false;
4364 Editor::_idle_visual_changer (void* arg)
4366 return static_cast<Editor*>(arg)->idle_visual_changer ();
4370 Editor::idle_visual_changer ()
4372 /* set_horizontal_position() below (and maybe other calls) call
4373 gtk_main_iteration(), so it's possible that a signal will be handled
4374 half-way through this method. If this signal wants an
4375 idle_visual_changer we must schedule another one after this one, so
4376 mark the idle_handler_id as -1 here to allow that. Also make a note
4377 that we are doing the visual change, so that changes in response to
4378 super-rapid-screen-update can be dropped if we are still processing
4382 pending_visual_change.idle_handler_id = -1;
4383 pending_visual_change.being_handled = true;
4385 VisualChange vc = pending_visual_change;
4387 pending_visual_change.pending = (VisualChange::Type) 0;
4389 visual_changer (vc);
4391 pending_visual_change.being_handled = false;
4393 return 0; /* this is always a one-shot call */
4397 Editor::visual_changer (const VisualChange& vc)
4399 double const last_time_origin = horizontal_position ();
4401 if (vc.pending & VisualChange::ZoomLevel) {
4402 set_samples_per_pixel (vc.samples_per_pixel);
4404 compute_fixed_ruler_scale ();
4406 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4407 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4409 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4410 current_bbt_points_begin, current_bbt_points_end);
4411 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4412 current_bbt_points_begin, current_bbt_points_end);
4413 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4415 update_video_timeline();
4418 if (vc.pending & VisualChange::TimeOrigin) {
4419 set_horizontal_position (vc.time_origin / samples_per_pixel);
4422 if (vc.pending & VisualChange::YOrigin) {
4423 vertical_adjustment.set_value (vc.y_origin);
4426 if (last_time_origin == horizontal_position ()) {
4427 /* changed signal not emitted */
4428 update_fixed_rulers ();
4429 redisplay_tempo (true);
4432 if (!(vc.pending & VisualChange::ZoomLevel)) {
4433 update_video_timeline();
4436 _summary->set_overlays_dirty ();
4439 struct EditorOrderTimeAxisSorter {
4440 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4441 return a->order () < b->order ();
4446 Editor::sort_track_selection (TrackViewList& sel)
4448 EditorOrderTimeAxisSorter cmp;
4453 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4456 framepos_t where = 0;
4457 EditPoint ep = _edit_point;
4459 if(Profile->get_mixbus())
4460 if (ep == EditAtSelectedMarker)
4463 if (from_context_menu && (ep == EditAtMouse)) {
4464 return canvas_event_sample (&context_click_event, 0, 0);
4467 if (entered_marker) {
4468 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4469 return entered_marker->position();
4472 if (ignore_playhead && ep == EditAtPlayhead) {
4473 ep = EditAtSelectedMarker;
4477 case EditAtPlayhead:
4478 where = _session->audible_frame();
4479 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4482 case EditAtSelectedMarker:
4483 if (!selection->markers.empty()) {
4485 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4488 where = loc->start();
4492 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4500 if (!mouse_frame (where, ignored)) {
4501 /* XXX not right but what can we do ? */
4505 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4513 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4515 if (!_session) return;
4517 begin_reversible_command (cmd);
4521 if ((tll = transport_loop_location()) == 0) {
4522 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4523 XMLNode &before = _session->locations()->get_state();
4524 _session->locations()->add (loc, true);
4525 _session->set_auto_loop_location (loc);
4526 XMLNode &after = _session->locations()->get_state();
4527 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4529 XMLNode &before = tll->get_state();
4530 tll->set_hidden (false, this);
4531 tll->set (start, end);
4532 XMLNode &after = tll->get_state();
4533 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4536 commit_reversible_command ();
4540 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4542 if (!_session) return;
4544 begin_reversible_command (cmd);
4548 if ((tpl = transport_punch_location()) == 0) {
4549 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4550 XMLNode &before = _session->locations()->get_state();
4551 _session->locations()->add (loc, true);
4552 _session->set_auto_punch_location (loc);
4553 XMLNode &after = _session->locations()->get_state();
4554 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4557 XMLNode &before = tpl->get_state();
4558 tpl->set_hidden (false, this);
4559 tpl->set (start, end);
4560 XMLNode &after = tpl->get_state();
4561 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4564 commit_reversible_command ();
4567 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4568 * @param rs List to which found regions are added.
4569 * @param where Time to look at.
4570 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4573 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4575 const TrackViewList* tracks;
4578 tracks = &track_views;
4583 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4585 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4588 boost::shared_ptr<Track> tr;
4589 boost::shared_ptr<Playlist> pl;
4591 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4593 boost::shared_ptr<RegionList> regions = pl->regions_at (
4594 (framepos_t) floor ( (double) where * tr->speed()));
4596 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4597 RegionView* rv = rtv->view()->find_view (*i);
4608 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4610 const TrackViewList* tracks;
4613 tracks = &track_views;
4618 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4619 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4621 boost::shared_ptr<Track> tr;
4622 boost::shared_ptr<Playlist> pl;
4624 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4626 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4627 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4629 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4631 RegionView* rv = rtv->view()->find_view (*i);
4642 /** Get regions using the following method:
4644 * Make a region list using:
4645 * (a) any selected regions
4646 * (b) the intersection of any selected tracks and the edit point(*)
4647 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4649 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4651 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4655 Editor::get_regions_from_selection_and_edit_point ()
4657 RegionSelection regions;
4659 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4660 regions.add (entered_regionview);
4662 regions = selection->regions;
4665 if ( regions.empty() ) {
4666 TrackViewList tracks = selection->tracks;
4668 if (!tracks.empty()) {
4669 /* no region selected or entered, but some selected tracks:
4670 * act on all regions on the selected tracks at the edit point
4672 framepos_t const where = get_preferred_edit_position ();
4673 get_regions_at(regions, where, tracks);
4680 /** Get regions using the following method:
4682 * Make a region list using:
4683 * (a) any selected regions
4684 * (b) the intersection of any selected tracks and the edit point(*)
4685 * (c) if neither exists, then whatever region is under the mouse
4687 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4689 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4692 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4694 RegionSelection regions;
4696 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4697 regions.add (entered_regionview);
4699 regions = selection->regions;
4702 if ( regions.empty() ) {
4703 TrackViewList tracks = selection->tracks;
4705 if (!tracks.empty()) {
4706 /* no region selected or entered, but some selected tracks:
4707 * act on all regions on the selected tracks at the edit point
4709 get_regions_at(regions, pos, tracks);
4716 /** Start with regions that are selected, or the entered regionview if none are selected.
4717 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4718 * of the regions that we started with.
4722 Editor::get_regions_from_selection_and_entered ()
4724 RegionSelection regions = selection->regions;
4726 if (regions.empty() && entered_regionview) {
4727 regions.add (entered_regionview);
4734 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4736 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4738 RouteTimeAxisView* tatv;
4740 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4742 boost::shared_ptr<Playlist> pl;
4743 vector<boost::shared_ptr<Region> > results;
4745 boost::shared_ptr<Track> tr;
4747 if ((tr = tatv->track()) == 0) {
4752 if ((pl = (tr->playlist())) != 0) {
4753 if (src_comparison) {
4754 pl->get_source_equivalent_regions (region, results);
4756 pl->get_region_list_equivalent_regions (region, results);
4760 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4761 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4762 regions.push_back (marv);
4771 Editor::show_rhythm_ferret ()
4773 if (rhythm_ferret == 0) {
4774 rhythm_ferret = new RhythmFerret(*this);
4777 rhythm_ferret->set_session (_session);
4778 rhythm_ferret->show ();
4779 rhythm_ferret->present ();
4783 Editor::first_idle ()
4785 MessageDialog* dialog = 0;
4787 if (track_views.size() > 1) {
4788 dialog = new MessageDialog (
4790 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4794 ARDOUR_UI::instance()->flush_pending ();
4797 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4801 // first idle adds route children (automation tracks), so we need to redisplay here
4802 _routes->redisplay ();
4809 Editor::_idle_resize (gpointer arg)
4811 return ((Editor*)arg)->idle_resize ();
4815 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4817 if (resize_idle_id < 0) {
4818 resize_idle_id = g_idle_add (_idle_resize, this);
4819 _pending_resize_amount = 0;
4822 /* make a note of the smallest resulting height, so that we can clamp the
4823 lower limit at TimeAxisView::hSmall */
4825 int32_t min_resulting = INT32_MAX;
4827 _pending_resize_amount += h;
4828 _pending_resize_view = view;
4830 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4832 if (selection->tracks.contains (_pending_resize_view)) {
4833 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4834 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4838 if (min_resulting < 0) {
4843 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4844 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4848 /** Handle pending resizing of tracks */
4850 Editor::idle_resize ()
4852 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4854 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4855 selection->tracks.contains (_pending_resize_view)) {
4857 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4858 if (*i != _pending_resize_view) {
4859 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4864 _pending_resize_amount = 0;
4865 _group_tabs->set_dirty ();
4866 resize_idle_id = -1;
4874 ENSURE_GUI_THREAD (*this, &Editor::located);
4877 playhead_cursor->set_position (_session->audible_frame ());
4878 if (_follow_playhead && !_pending_initial_locate) {
4879 reset_x_origin_to_follow_playhead ();
4883 _pending_locate_request = false;
4884 _pending_initial_locate = false;
4888 Editor::region_view_added (RegionView *)
4890 _summary->set_background_dirty ();
4894 Editor::region_view_removed ()
4896 _summary->set_background_dirty ();
4900 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4902 TrackViewList::const_iterator j = track_views.begin ();
4903 while (j != track_views.end()) {
4904 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4905 if (rtv && rtv->route() == r) {
4916 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4920 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4921 TimeAxisView* tv = axis_view_from_route (*i);
4931 Editor::suspend_route_redisplay ()
4934 _routes->suspend_redisplay();
4939 Editor::resume_route_redisplay ()
4942 _routes->resume_redisplay();
4947 Editor::add_routes (RouteList& routes)
4949 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4951 RouteTimeAxisView *rtv;
4952 list<RouteTimeAxisView*> new_views;
4954 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4955 boost::shared_ptr<Route> route = (*x);
4957 if (route->is_auditioner() || route->is_monitor()) {
4961 DataType dt = route->input()->default_type();
4963 if (dt == ARDOUR::DataType::AUDIO) {
4964 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4965 rtv->set_route (route);
4966 } else if (dt == ARDOUR::DataType::MIDI) {
4967 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4968 rtv->set_route (route);
4970 throw unknown_type();
4973 new_views.push_back (rtv);
4974 track_views.push_back (rtv);
4976 rtv->effective_gain_display ();
4978 if (internal_editing()) {
4979 rtv->enter_internal_edit_mode ();
4981 rtv->leave_internal_edit_mode ();
4984 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4985 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4988 if (new_views.size() > 0) {
4989 _routes->routes_added (new_views);
4990 _summary->routes_added (new_views);
4993 if (show_editor_mixer_when_tracks_arrive) {
4994 show_editor_mixer (true);
4997 editor_list_button.set_sensitive (true);
5001 Editor::timeaxisview_deleted (TimeAxisView *tv)
5003 if (tv == entered_track) {
5007 if (_session && _session->deletion_in_progress()) {
5008 /* the situation is under control */
5012 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5014 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5016 _routes->route_removed (tv);
5018 TimeAxisView::Children c = tv->get_child_list ();
5019 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5020 if (entered_track == i->get()) {
5025 /* remove it from the list of track views */
5027 TrackViewList::iterator i;
5029 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5030 i = track_views.erase (i);
5033 /* update whatever the current mixer strip is displaying, if revelant */
5035 boost::shared_ptr<Route> route;
5038 route = rtav->route ();
5041 if (current_mixer_strip && current_mixer_strip->route() == route) {
5043 TimeAxisView* next_tv;
5045 if (track_views.empty()) {
5047 } else if (i == track_views.end()) {
5048 next_tv = track_views.front();
5055 set_selected_mixer_strip (*next_tv);
5057 /* make the editor mixer strip go away setting the
5058 * button to inactive (which also unticks the menu option)
5061 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5067 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5069 if (apply_to_selection) {
5070 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5072 TrackSelection::iterator j = i;
5075 hide_track_in_display (*i, false);
5080 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5082 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5083 // this will hide the mixer strip
5084 set_selected_mixer_strip (*tv);
5087 _routes->hide_track_in_display (*tv);
5092 Editor::sync_track_view_list_and_routes ()
5094 track_views = TrackViewList (_routes->views ());
5096 _summary->set_dirty ();
5097 _group_tabs->set_dirty ();
5099 return false; // do not call again (until needed)
5103 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5105 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5110 /** Find a RouteTimeAxisView by the ID of its route */
5112 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5114 RouteTimeAxisView* v;
5116 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5117 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5118 if(v->route()->id() == id) {
5128 Editor::fit_route_group (RouteGroup *g)
5130 TrackViewList ts = axis_views_from_routes (g->route_list ());
5135 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5137 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5140 _session->cancel_audition ();
5144 if (_session->is_auditioning()) {
5145 _session->cancel_audition ();
5146 if (r == last_audition_region) {
5151 _session->audition_region (r);
5152 last_audition_region = r;
5157 Editor::hide_a_region (boost::shared_ptr<Region> r)
5159 r->set_hidden (true);
5163 Editor::show_a_region (boost::shared_ptr<Region> r)
5165 r->set_hidden (false);
5169 Editor::audition_region_from_region_list ()
5171 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5175 Editor::hide_region_from_region_list ()
5177 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5181 Editor::show_region_in_region_list ()
5183 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5187 Editor::step_edit_status_change (bool yn)
5190 start_step_editing ();
5192 stop_step_editing ();
5197 Editor::start_step_editing ()
5199 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5203 Editor::stop_step_editing ()
5205 step_edit_connection.disconnect ();
5209 Editor::check_step_edit ()
5211 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5212 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5214 mtv->check_step_edit ();
5218 return true; // do it again, till we stop
5222 Editor::scroll_press (Direction dir)
5224 ++_scroll_callbacks;
5226 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5227 /* delay the first auto-repeat */
5233 scroll_backward (1);
5241 scroll_up_one_track ();
5245 scroll_down_one_track ();
5249 /* do hacky auto-repeat */
5250 if (!_scroll_connection.connected ()) {
5252 _scroll_connection = Glib::signal_timeout().connect (
5253 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5256 _scroll_callbacks = 0;
5263 Editor::scroll_release ()
5265 _scroll_connection.disconnect ();
5268 /** Queue a change for the Editor viewport x origin to follow the playhead */
5270 Editor::reset_x_origin_to_follow_playhead ()
5272 framepos_t const frame = playhead_cursor->current_frame ();
5274 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5276 if (_session->transport_speed() < 0) {
5278 if (frame > (current_page_samples() / 2)) {
5279 center_screen (frame-(current_page_samples()/2));
5281 center_screen (current_page_samples()/2);
5288 if (frame < leftmost_frame) {
5290 if (_session->transport_rolling()) {
5291 /* rolling; end up with the playhead at the right of the page */
5292 l = frame - current_page_samples ();
5294 /* not rolling: end up with the playhead 1/4 of the way along the page */
5295 l = frame - current_page_samples() / 4;
5299 if (_session->transport_rolling()) {
5300 /* rolling: end up with the playhead on the left of the page */
5303 /* not rolling: end up with the playhead 3/4 of the way along the page */
5304 l = frame - 3 * current_page_samples() / 4;
5312 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5318 Editor::super_rapid_screen_update ()
5320 if (!_session || !_session->engine().running()) {
5324 /* METERING / MIXER STRIPS */
5326 /* update track meters, if required */
5327 if (is_mapped() && meters_running) {
5328 RouteTimeAxisView* rtv;
5329 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5330 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5331 rtv->fast_update ();
5336 /* and any current mixer strip */
5337 if (current_mixer_strip) {
5338 current_mixer_strip->fast_update ();
5341 /* PLAYHEAD AND VIEWPORT */
5343 framepos_t const frame = _session->audible_frame();
5345 /* There are a few reasons why we might not update the playhead / viewport stuff:
5347 * 1. we don't update things when there's a pending locate request, otherwise
5348 * when the editor requests a locate there is a chance that this method
5349 * will move the playhead before the locate request is processed, causing
5351 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5352 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5355 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5357 last_update_frame = frame;
5359 if (!_dragging_playhead) {
5360 playhead_cursor->set_position (frame);
5363 if (!_stationary_playhead) {
5365 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5366 /* We only do this if we aren't already
5367 handling a visual change (ie if
5368 pending_visual_change.being_handled is
5369 false) so that these requests don't stack
5370 up there are too many of them to handle in
5373 reset_x_origin_to_follow_playhead ();
5378 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5382 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5383 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5384 if (target <= 0.0) {
5387 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5388 target = (target * 0.15) + (current * 0.85);
5394 set_horizontal_position (current);
5403 Editor::session_going_away ()
5405 _have_idled = false;
5407 _session_connections.drop_connections ();
5409 super_rapid_screen_update_connection.disconnect ();
5411 selection->clear ();
5412 cut_buffer->clear ();
5414 clicked_regionview = 0;
5415 clicked_axisview = 0;
5416 clicked_routeview = 0;
5417 entered_regionview = 0;
5419 last_update_frame = 0;
5422 playhead_cursor->hide ();
5424 /* rip everything out of the list displays */
5428 _route_groups->clear ();
5430 /* do this first so that deleting a track doesn't reset cms to null
5431 and thus cause a leak.
5434 if (current_mixer_strip) {
5435 if (current_mixer_strip->get_parent() != 0) {
5436 global_hpacker.remove (*current_mixer_strip);
5438 delete current_mixer_strip;
5439 current_mixer_strip = 0;
5442 /* delete all trackviews */
5444 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5447 track_views.clear ();
5449 nudge_clock->set_session (0);
5451 editor_list_button.set_active(false);
5452 editor_list_button.set_sensitive(false);
5454 /* clear tempo/meter rulers */
5455 remove_metric_marks ();
5457 clear_marker_display ();
5459 stop_step_editing ();
5461 /* get rid of any existing editor mixer strip */
5463 WindowTitle title(Glib::get_application_name());
5464 title += _("Editor");
5466 set_title (title.get_string());
5468 SessionHandlePtr::session_going_away ();
5473 Editor::show_editor_list (bool yn)
5476 _the_notebook.show ();
5478 _the_notebook.hide ();
5483 Editor::change_region_layering_order (bool from_context_menu)
5485 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5487 if (!clicked_routeview) {
5488 if (layering_order_editor) {
5489 layering_order_editor->hide ();
5494 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5500 boost::shared_ptr<Playlist> pl = track->playlist();
5506 if (layering_order_editor == 0) {
5507 layering_order_editor = new RegionLayeringOrderEditor (*this);
5510 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5511 layering_order_editor->maybe_present ();
5515 Editor::update_region_layering_order_editor ()
5517 if (layering_order_editor && layering_order_editor->is_visible ()) {
5518 change_region_layering_order (true);
5523 Editor::setup_fade_images ()
5525 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5526 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5527 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5528 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5529 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5531 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5532 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5533 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5534 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5535 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5537 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5538 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5539 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5540 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5541 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5543 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5544 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5545 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5546 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5547 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5551 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5553 Editor::action_menu_item (std::string const & name)
5555 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5558 return *manage (a->create_menu_item ());
5562 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5564 EventBox* b = manage (new EventBox);
5565 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5566 Label* l = manage (new Label (name));
5570 _the_notebook.append_page (widget, *b);
5574 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5576 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5577 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5580 if (ev->type == GDK_2BUTTON_PRESS) {
5582 /* double-click on a notebook tab shrinks or expands the notebook */
5584 if (_notebook_shrunk) {
5585 if (pre_notebook_shrink_pane_width) {
5586 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5588 _notebook_shrunk = false;
5590 pre_notebook_shrink_pane_width = edit_pane.get_position();
5592 /* this expands the LHS of the edit pane to cover the notebook
5593 PAGE but leaves the tabs visible.
5595 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5596 _notebook_shrunk = true;
5604 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5606 using namespace Menu_Helpers;
5608 MenuList& items = _control_point_context_menu.items ();
5611 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5612 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5613 if (!can_remove_control_point (item)) {
5614 items.back().set_sensitive (false);
5617 _control_point_context_menu.popup (event->button.button, event->button.time);
5621 Editor::zoom_vertical_modifier_released()
5623 _stepping_axis_view = 0;
5627 Editor::ui_parameter_changed (string parameter)
5629 if (parameter == "icon-set") {
5630 while (!_cursor_stack.empty()) {
5631 _cursor_stack.pop();
5633 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5634 } else if (parameter == "draggable-playhead") {
5635 if (_verbose_cursor) {
5636 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());