2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
124 #include "verbose_cursor.h"
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_edit_mode_strings[] = {
199 static const gchar *_zoom_focus_strings[] = {
209 #ifdef USE_RUBBERBAND
210 static const gchar *_rb_opt_strings[] = {
213 N_("Balanced multitimbral mixture"),
214 N_("Unpitched percussion with stable notes"),
215 N_("Crisp monophonic instrumental"),
216 N_("Unpitched solo percussion"),
217 N_("Resample without preserving pitch"),
222 static const gchar *_combo_pad_string = "mm"; ///< ~2em
225 pane_size_watcher (Paned* pane)
227 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
231 Quartz: impossible to access
233 so stop that by preventing it from ever getting too narrow. 35
234 pixels is basically a rough guess at the tab width.
239 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
241 gint pos = pane->get_position ();
243 if (pos > max_width_of_lhs) {
244 pane->set_position (max_width_of_lhs);
249 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
251 /* time display buttons */
252 , minsec_label (_("Mins:Secs"))
253 , bbt_label (_("Bars:Beats"))
254 , timecode_label (_("Timecode"))
255 , samples_label (_("Samples"))
256 , tempo_label (_("Tempo"))
257 , meter_label (_("Meter"))
258 , mark_label (_("Location Markers"))
259 , range_mark_label (_("Range Markers"))
260 , transport_mark_label (_("Loop/Punch Ranges"))
261 , cd_mark_label (_("CD Markers"))
262 , videotl_label (_("Video Timeline"))
263 , edit_packer (4, 4, true)
265 /* the values here don't matter: layout widgets
266 reset them as needed.
269 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
270 , horizontal_adjustment (0.0, 0.0, 1e16)
271 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
273 , controls_layout (unused_adjustment, vertical_adjustment)
275 /* tool bar related */
277 , toolbar_selection_clock_table (2,3)
278 , _mouse_mode_tearoff (0)
279 , automation_mode_button (_("mode"))
283 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
288 , meters_running(false)
289 , _pending_locate_request (false)
290 , _pending_initial_locate (false)
291 , _last_cut_copy_source_track (0)
293 , _region_selection_change_updates_region_list (true)
294 , _following_mixer_selection (false)
295 , _control_point_toggled_on_press (false)
296 , _stepping_axis_view (0)
300 /* we are a singleton */
302 PublicEditor::_instance = this;
306 selection = new Selection (this);
307 cut_buffer = new Selection (this);
309 clicked_regionview = 0;
310 clicked_axisview = 0;
311 clicked_routeview = 0;
312 clicked_control_point = 0;
313 last_update_frame = 0;
314 pre_press_cursor = 0;
315 _drags = new DragManager (this);
318 current_mixer_strip = 0;
321 snap_type_strings = I18N (_snap_type_strings);
322 snap_mode_strings = I18N (_snap_mode_strings);
323 zoom_focus_strings = I18N (_zoom_focus_strings);
324 edit_mode_strings = I18N (_edit_mode_strings);
325 edit_point_strings = I18N (_edit_point_strings);
326 #ifdef USE_RUBBERBAND
327 rb_opt_strings = I18N (_rb_opt_strings);
331 build_edit_mode_menu();
332 build_zoom_focus_menu();
333 build_track_count_menu();
334 build_snap_mode_menu();
335 build_snap_type_menu();
336 build_edit_point_menu();
338 snap_threshold = 5.0;
339 bbt_beat_subdivision = 4;
340 _visible_canvas_width = 0;
341 _visible_canvas_height = 0;
342 autoscroll_horizontal_allowed = false;
343 autoscroll_vertical_allowed = false;
348 current_interthread_info = 0;
349 _show_measures = true;
351 show_gain_after_trim = false;
353 have_pending_keyboard_selection = false;
354 _follow_playhead = true;
355 _stationary_playhead = false;
356 editor_ruler_menu = 0;
357 no_ruler_shown_update = false;
359 range_marker_menu = 0;
360 marker_menu_item = 0;
361 tempo_or_meter_marker_menu = 0;
362 transport_marker_menu = 0;
363 new_transport_marker_menu = 0;
364 editor_mixer_strip_width = Wide;
365 show_editor_mixer_when_tracks_arrive = false;
366 region_edit_menu_split_multichannel_item = 0;
367 region_edit_menu_split_item = 0;
370 current_stepping_trackview = 0;
372 entered_regionview = 0;
374 clear_entered_track = false;
377 button_release_can_deselect = true;
378 _dragging_playhead = false;
379 _dragging_edit_point = false;
380 select_new_marker = false;
382 layering_order_editor = 0;
383 no_save_visual = false;
385 within_track_canvas = false;
387 scrubbing_direction = 0;
391 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
392 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
393 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
394 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
395 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
397 zoom_focus = ZoomFocusLeft;
398 _edit_point = EditAtMouse;
399 _internal_editing = false;
400 current_canvas_cursor = 0;
401 _visible_track_count = 16;
403 samples_per_pixel = 2048; /* too early to use reset_zoom () */
405 _scroll_callbacks = 0;
407 bbt_label.set_name ("EditorRulerLabel");
408 bbt_label.set_size_request (-1, (int)timebar_height);
409 bbt_label.set_alignment (1.0, 0.5);
410 bbt_label.set_padding (5,0);
412 bbt_label.set_no_show_all();
413 minsec_label.set_name ("EditorRulerLabel");
414 minsec_label.set_size_request (-1, (int)timebar_height);
415 minsec_label.set_alignment (1.0, 0.5);
416 minsec_label.set_padding (5,0);
417 minsec_label.hide ();
418 minsec_label.set_no_show_all();
419 timecode_label.set_name ("EditorRulerLabel");
420 timecode_label.set_size_request (-1, (int)timebar_height);
421 timecode_label.set_alignment (1.0, 0.5);
422 timecode_label.set_padding (5,0);
423 timecode_label.hide ();
424 timecode_label.set_no_show_all();
425 samples_label.set_name ("EditorRulerLabel");
426 samples_label.set_size_request (-1, (int)timebar_height);
427 samples_label.set_alignment (1.0, 0.5);
428 samples_label.set_padding (5,0);
429 samples_label.hide ();
430 samples_label.set_no_show_all();
432 tempo_label.set_name ("EditorRulerLabel");
433 tempo_label.set_size_request (-1, (int)timebar_height);
434 tempo_label.set_alignment (1.0, 0.5);
435 tempo_label.set_padding (5,0);
437 tempo_label.set_no_show_all();
439 meter_label.set_name ("EditorRulerLabel");
440 meter_label.set_size_request (-1, (int)timebar_height);
441 meter_label.set_alignment (1.0, 0.5);
442 meter_label.set_padding (5,0);
444 meter_label.set_no_show_all();
446 if (Profile->get_trx()) {
447 mark_label.set_text (_("Markers"));
449 mark_label.set_name ("EditorRulerLabel");
450 mark_label.set_size_request (-1, (int)timebar_height);
451 mark_label.set_alignment (1.0, 0.5);
452 mark_label.set_padding (5,0);
454 mark_label.set_no_show_all();
456 cd_mark_label.set_name ("EditorRulerLabel");
457 cd_mark_label.set_size_request (-1, (int)timebar_height);
458 cd_mark_label.set_alignment (1.0, 0.5);
459 cd_mark_label.set_padding (5,0);
460 cd_mark_label.hide();
461 cd_mark_label.set_no_show_all();
463 videotl_bar_height = 4;
464 videotl_label.set_name ("EditorRulerLabel");
465 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
466 videotl_label.set_alignment (1.0, 0.5);
467 videotl_label.set_padding (5,0);
468 videotl_label.hide();
469 videotl_label.set_no_show_all();
471 range_mark_label.set_name ("EditorRulerLabel");
472 range_mark_label.set_size_request (-1, (int)timebar_height);
473 range_mark_label.set_alignment (1.0, 0.5);
474 range_mark_label.set_padding (5,0);
475 range_mark_label.hide();
476 range_mark_label.set_no_show_all();
478 transport_mark_label.set_name ("EditorRulerLabel");
479 transport_mark_label.set_size_request (-1, (int)timebar_height);
480 transport_mark_label.set_alignment (1.0, 0.5);
481 transport_mark_label.set_padding (5,0);
482 transport_mark_label.hide();
483 transport_mark_label.set_no_show_all();
485 initialize_canvas ();
487 _summary = new EditorSummary (this);
489 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
490 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
492 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
494 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
495 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
497 edit_controls_vbox.set_spacing (0);
498 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
499 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
501 HBox* h = manage (new HBox);
502 _group_tabs = new EditorGroupTabs (this);
503 if (!ARDOUR::Profile->get_trx()) {
504 h->pack_start (*_group_tabs, PACK_SHRINK);
506 h->pack_start (edit_controls_vbox);
507 controls_layout.add (*h);
509 controls_layout.set_name ("EditControlsBase");
510 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
511 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
512 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
514 _cursors = new MouseCursors;
515 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
516 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
518 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
520 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
521 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
522 pad_line_1->set_outline_color (0xFF0000FF);
528 edit_packer.set_col_spacings (0);
529 edit_packer.set_row_spacings (0);
530 edit_packer.set_homogeneous (false);
531 edit_packer.set_border_width (0);
532 edit_packer.set_name ("EditorWindow");
534 time_bars_event_box.add (time_bars_vbox);
535 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
536 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
538 /* labels for the time bars */
539 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
541 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
543 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
545 bottom_hbox.set_border_width (2);
546 bottom_hbox.set_spacing (3);
548 _route_groups = new EditorRouteGroups (this);
549 _routes = new EditorRoutes (this);
550 _regions = new EditorRegions (this);
551 _snapshots = new EditorSnapshots (this);
552 _locations = new EditorLocations (this);
554 add_notebook_page (_("Regions"), _regions->widget ());
555 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
556 add_notebook_page (_("Snapshots"), _snapshots->widget ());
557 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
558 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
560 _the_notebook.set_show_tabs (true);
561 _the_notebook.set_scrollable (true);
562 _the_notebook.popup_disable ();
563 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
564 _the_notebook.show_all ();
566 _notebook_shrunk = false;
568 editor_summary_pane.pack1(edit_packer);
570 Button* summary_arrows_left_left = manage (new Button);
571 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
572 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
573 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
575 Button* summary_arrows_left_right = manage (new Button);
576 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
577 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
578 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
580 VBox* summary_arrows_left = manage (new VBox);
581 summary_arrows_left->pack_start (*summary_arrows_left_left);
582 summary_arrows_left->pack_start (*summary_arrows_left_right);
584 Button* summary_arrows_right_up = manage (new Button);
585 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
586 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
587 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
589 Button* summary_arrows_right_down = manage (new Button);
590 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
591 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
592 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
594 VBox* summary_arrows_right = manage (new VBox);
595 summary_arrows_right->pack_start (*summary_arrows_right_up);
596 summary_arrows_right->pack_start (*summary_arrows_right_down);
598 Frame* summary_frame = manage (new Frame);
599 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
601 summary_frame->add (*_summary);
602 summary_frame->show ();
604 _summary_hbox.pack_start (*summary_arrows_left, false, false);
605 _summary_hbox.pack_start (*summary_frame, true, true);
606 _summary_hbox.pack_start (*summary_arrows_right, false, false);
608 if (!ARDOUR::Profile->get_trx()) {
609 editor_summary_pane.pack2 (_summary_hbox);
612 edit_pane.pack1 (editor_summary_pane, true, true);
613 if (!ARDOUR::Profile->get_trx()) {
614 edit_pane.pack2 (_the_notebook, false, true);
617 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
619 /* XXX: editor_summary_pane might need similar to the edit_pane */
621 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
623 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
624 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
626 top_hbox.pack_start (toolbar_frame);
628 HBox *hbox = manage (new HBox);
629 hbox->pack_start (edit_pane, true, true);
631 global_vpacker.pack_start (top_hbox, false, false);
632 global_vpacker.pack_start (*hbox, true, true);
634 global_hpacker.pack_start (global_vpacker, true, true);
636 set_name ("EditorWindow");
637 add_accel_group (ActionManager::ui_manager->get_accel_group());
639 status_bar_hpacker.show ();
641 vpacker.pack_end (status_bar_hpacker, false, false);
642 vpacker.pack_end (global_hpacker, true, true);
644 /* register actions now so that set_state() can find them and set toggles/checks etc */
647 /* when we start using our own keybinding system for the editor, this
648 * will be uncommented
654 set_zoom_focus (zoom_focus);
655 set_visible_track_count (_visible_track_count);
656 _snap_type = SnapToBeat;
657 set_snap_to (_snap_type);
658 _snap_mode = SnapOff;
659 set_snap_mode (_snap_mode);
660 set_mouse_mode (MouseObject, true);
661 pre_internal_mouse_mode = MouseObject;
662 pre_internal_snap_type = _snap_type;
663 pre_internal_snap_mode = _snap_mode;
664 internal_snap_type = _snap_type;
665 internal_snap_mode = _snap_mode;
666 set_edit_point_preference (EditAtMouse, true);
668 _playlist_selector = new PlaylistSelector();
669 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
671 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
675 nudge_forward_button.set_name ("nudge button");
676 // nudge_forward_button.add_elements (ArdourButton::Inset);
677 nudge_forward_button.set_image(::get_icon("nudge_right"));
679 nudge_backward_button.set_name ("nudge button");
680 // nudge_backward_button.add_elements (ArdourButton::Inset);
681 nudge_backward_button.set_image(::get_icon("nudge_left"));
683 fade_context_menu.set_name ("ArdourContextMenu");
685 /* icons, titles, WM stuff */
687 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
688 Glib::RefPtr<Gdk::Pixbuf> icon;
690 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
691 window_icons.push_back (icon);
693 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
694 window_icons.push_back (icon);
696 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
697 window_icons.push_back (icon);
699 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
700 window_icons.push_back (icon);
702 if (!window_icons.empty()) {
703 // set_icon_list (window_icons);
704 set_default_icon_list (window_icons);
707 WindowTitle title(Glib::get_application_name());
708 title += _("Editor");
709 set_title (title.get_string());
710 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
713 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
715 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
716 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
718 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
720 /* allow external control surfaces/protocols to do various things */
722 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
723 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
724 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
725 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
726 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
727 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
728 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
729 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
730 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
731 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
732 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
733 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
734 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
735 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
737 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
738 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
739 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
740 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
741 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
743 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
745 /* problematic: has to return a value and thus cannot be x-thread */
747 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
749 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
750 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
752 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
754 _ignore_region_action = false;
755 _last_region_menu_was_main = false;
756 _popup_region_menu_item = 0;
758 _ignore_follow_edits = false;
760 _show_marker_lines = false;
762 /* Button bindings */
764 button_bindings = new Bindings;
766 XMLNode* node = button_settings();
768 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
769 button_bindings->load (**i);
775 /* grab current parameter state */
776 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
777 ARDOUR_UI::config()->map_parameters (pc);
779 setup_fade_images ();
786 delete button_bindings;
788 delete _route_groups;
789 delete _track_canvas_viewport;
794 Editor::button_settings () const
796 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
797 XMLNode* node = find_named_node (*settings, X_("Buttons"));
800 node = new XMLNode (X_("Buttons"));
807 Editor::add_toplevel_menu (Container& cont)
809 vpacker.pack_start (cont, false, false);
814 Editor::add_transport_frame (Container& cont)
816 if(ARDOUR::Profile->get_mixbus()) {
817 global_vpacker.pack_start (cont, false, false);
818 global_vpacker.reorder_child (cont, 0);
821 vpacker.pack_start (cont, false, false);
826 Editor::get_smart_mode () const
828 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
832 Editor::catch_vanishing_regionview (RegionView *rv)
834 /* note: the selection will take care of the vanishing
835 audioregionview by itself.
838 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
842 if (clicked_regionview == rv) {
843 clicked_regionview = 0;
846 if (entered_regionview == rv) {
847 set_entered_regionview (0);
850 if (!_all_region_actions_sensitized) {
851 sensitize_all_region_actions (true);
856 Editor::set_entered_regionview (RegionView* rv)
858 if (rv == entered_regionview) {
862 if (entered_regionview) {
863 entered_regionview->exited ();
866 entered_regionview = rv;
868 if (entered_regionview != 0) {
869 entered_regionview->entered (internal_editing ());
872 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
873 /* This RegionView entry might have changed what region actions
874 are allowed, so sensitize them all in case a key is pressed.
876 sensitize_all_region_actions (true);
881 Editor::set_entered_track (TimeAxisView* tav)
884 entered_track->exited ();
890 entered_track->entered ();
895 Editor::show_window ()
897 if (!is_visible ()) {
900 /* XXX: this is a bit unfortunate; it would probably
901 be nicer if we could just call show () above rather
902 than needing the show_all ()
905 /* re-hide stuff if necessary */
906 editor_list_button_toggled ();
907 parameter_changed ("show-summary");
908 parameter_changed ("show-group-tabs");
909 parameter_changed ("show-zoom-tools");
911 /* now reset all audio_time_axis heights, because widgets might need
917 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
918 tv = (static_cast<TimeAxisView*>(*i));
922 if (current_mixer_strip) {
923 current_mixer_strip->hide_things ();
924 current_mixer_strip->parameter_changed ("mixer-element-visibility");
932 Editor::instant_save ()
934 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
939 _session->add_instant_xml(get_state());
941 Config->add_instant_xml(get_state());
946 Editor::control_vertical_zoom_in_all ()
948 tav_zoom_smooth (false, true);
952 Editor::control_vertical_zoom_out_all ()
954 tav_zoom_smooth (true, true);
958 Editor::control_vertical_zoom_in_selected ()
960 tav_zoom_smooth (false, false);
964 Editor::control_vertical_zoom_out_selected ()
966 tav_zoom_smooth (true, false);
970 Editor::control_view (uint32_t view)
972 goto_visual_state (view);
976 Editor::control_unselect ()
978 selection->clear_tracks ();
982 Editor::control_select (uint32_t rid, Selection::Operation op)
984 /* handles the (static) signal from the ControlProtocol class that
985 * requests setting the selected track to a given RID
992 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
998 TimeAxisView* tav = axis_view_from_route (r);
1002 case Selection::Add:
1003 selection->add (tav);
1005 case Selection::Toggle:
1006 selection->toggle (tav);
1008 case Selection::Extend:
1010 case Selection::Set:
1011 selection->set (tav);
1015 selection->clear_tracks ();
1020 Editor::control_step_tracks_up ()
1022 scroll_tracks_up_line ();
1026 Editor::control_step_tracks_down ()
1028 scroll_tracks_down_line ();
1032 Editor::control_scroll (float fraction)
1034 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1040 double step = fraction * current_page_samples();
1043 _control_scroll_target is an optional<T>
1045 it acts like a pointer to an framepos_t, with
1046 a operator conversion to boolean to check
1047 that it has a value could possibly use
1048 playhead_cursor->current_frame to store the
1049 value and a boolean in the class to know
1050 when it's out of date
1053 if (!_control_scroll_target) {
1054 _control_scroll_target = _session->transport_frame();
1055 _dragging_playhead = true;
1058 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1059 *_control_scroll_target = 0;
1060 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1061 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1063 *_control_scroll_target += (framepos_t) floor (step);
1066 /* move visuals, we'll catch up with it later */
1068 playhead_cursor->set_position (*_control_scroll_target);
1069 UpdateAllTransportClocks (*_control_scroll_target);
1071 if (*_control_scroll_target > (current_page_samples() / 2)) {
1072 /* try to center PH in window */
1073 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1079 Now we do a timeout to actually bring the session to the right place
1080 according to the playhead. This is to avoid reading disk buffers on every
1081 call to control_scroll, which is driven by ScrollTimeline and therefore
1082 probably by a control surface wheel which can generate lots of events.
1084 /* cancel the existing timeout */
1086 control_scroll_connection.disconnect ();
1088 /* add the next timeout */
1090 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1094 Editor::deferred_control_scroll (framepos_t /*target*/)
1096 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1097 // reset for next stream
1098 _control_scroll_target = boost::none;
1099 _dragging_playhead = false;
1104 Editor::access_action (std::string action_group, std::string action_item)
1110 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1113 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1121 Editor::on_realize ()
1123 Window::on_realize ();
1126 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1127 start_lock_event_timing ();
1130 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1134 Editor::start_lock_event_timing ()
1136 /* check if we should lock the GUI every 30 seconds */
1138 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1142 Editor::generic_event_handler (GdkEvent* ev)
1145 case GDK_BUTTON_PRESS:
1146 case GDK_BUTTON_RELEASE:
1147 case GDK_MOTION_NOTIFY:
1149 case GDK_KEY_RELEASE:
1150 gettimeofday (&last_event_time, 0);
1159 Editor::lock_timeout_callback ()
1161 struct timeval now, delta;
1163 gettimeofday (&now, 0);
1165 timersub (&now, &last_event_time, &delta);
1167 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1169 /* don't call again. Returning false will effectively
1170 disconnect us from the timer callback.
1172 unlock() will call start_lock_event_timing() to get things
1182 Editor::map_position_change (framepos_t frame)
1184 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1186 if (_session == 0) {
1190 if (_follow_playhead) {
1191 center_screen (frame);
1194 playhead_cursor->set_position (frame);
1198 Editor::center_screen (framepos_t frame)
1200 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1202 /* if we're off the page, then scroll.
1205 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1206 center_screen_internal (frame, page);
1211 Editor::center_screen_internal (framepos_t frame, float page)
1216 frame -= (framepos_t) page;
1221 reset_x_origin (frame);
1226 Editor::update_title ()
1228 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1231 bool dirty = _session->dirty();
1233 string session_name;
1235 if (_session->snap_name() != _session->name()) {
1236 session_name = _session->snap_name();
1238 session_name = _session->name();
1242 session_name = "*" + session_name;
1245 WindowTitle title(session_name);
1246 title += Glib::get_application_name();
1247 set_title (title.get_string());
1249 /* ::session_going_away() will have taken care of it */
1254 Editor::set_session (Session *t)
1256 SessionHandlePtr::set_session (t);
1262 _playlist_selector->set_session (_session);
1263 nudge_clock->set_session (_session);
1264 _summary->set_session (_session);
1265 _group_tabs->set_session (_session);
1266 _route_groups->set_session (_session);
1267 _regions->set_session (_session);
1268 _snapshots->set_session (_session);
1269 _routes->set_session (_session);
1270 _locations->set_session (_session);
1272 if (rhythm_ferret) {
1273 rhythm_ferret->set_session (_session);
1276 if (analysis_window) {
1277 analysis_window->set_session (_session);
1281 sfbrowser->set_session (_session);
1284 compute_fixed_ruler_scale ();
1286 /* Make sure we have auto loop and auto punch ranges */
1288 Location* loc = _session->locations()->auto_loop_location();
1290 loc->set_name (_("Loop"));
1293 loc = _session->locations()->auto_punch_location();
1296 loc->set_name (_("Punch"));
1299 refresh_location_display ();
1301 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1302 the selected Marker; this needs the LocationMarker list to be available.
1304 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1305 set_state (*node, Stateful::loading_state_version);
1307 /* catch up with the playhead */
1309 _session->request_locate (playhead_cursor->current_frame ());
1310 _pending_initial_locate = true;
1314 /* These signals can all be emitted by a non-GUI thread. Therefore the
1315 handlers for them must not attempt to directly interact with the GUI,
1316 but use PBD::Signal<T>::connect() which accepts an event loop
1317 ("context") where the handler will be asked to run.
1320 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1321 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1322 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1323 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1324 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1325 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1326 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1327 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1328 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1329 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1330 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1331 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1332 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1333 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1335 playhead_cursor->show ();
1337 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1338 Config->map_parameters (pc);
1339 _session->config.map_parameters (pc);
1341 restore_ruler_visibility ();
1342 //tempo_map_changed (PropertyChange (0));
1343 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1345 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1346 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1349 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1350 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1353 switch (_snap_type) {
1354 case SnapToRegionStart:
1355 case SnapToRegionEnd:
1356 case SnapToRegionSync:
1357 case SnapToRegionBoundary:
1358 build_region_boundary_cache ();
1365 /* register for undo history */
1366 _session->register_with_memento_command_factory(id(), this);
1368 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1370 start_updating_meters ();
1374 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1376 if (a->get_name() == "RegionMenu") {
1377 /* When the main menu's region menu is opened, we setup the actions so that they look right
1378 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1379 so we resensitize all region actions when the entered regionview or the region selection
1380 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1381 happens after the region context menu is opened. So we set a flag here, too.
1385 sensitize_the_right_region_actions ();
1386 _last_region_menu_was_main = true;
1391 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1393 using namespace Menu_Helpers;
1395 void (Editor::*emf)(FadeShape);
1396 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1399 images = &_xfade_in_images;
1400 emf = &Editor::set_fade_in_shape;
1402 images = &_xfade_out_images;
1403 emf = &Editor::set_fade_out_shape;
1408 _("Linear (for highly correlated material)"),
1409 *(*images)[FadeLinear],
1410 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1414 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1418 _("Constant power"),
1419 *(*images)[FadeConstantPower],
1420 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1423 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1428 *(*images)[FadeSymmetric],
1429 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1433 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1438 *(*images)[FadeSlow],
1439 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1442 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1447 *(*images)[FadeFast],
1448 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1451 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1454 /** Pop up a context menu for when the user clicks on a start crossfade */
1456 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1458 using namespace Menu_Helpers;
1459 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1462 MenuList& items (xfade_in_context_menu.items());
1465 if (arv->audio_region()->fade_in_active()) {
1466 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1468 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1471 items.push_back (SeparatorElem());
1472 fill_xfade_menu (items, true);
1474 xfade_in_context_menu.popup (button, time);
1477 /** Pop up a context menu for when the user clicks on an end crossfade */
1479 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1481 using namespace Menu_Helpers;
1482 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1485 MenuList& items (xfade_out_context_menu.items());
1488 if (arv->audio_region()->fade_out_active()) {
1489 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1491 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1494 items.push_back (SeparatorElem());
1495 fill_xfade_menu (items, false);
1497 xfade_out_context_menu.popup (button, time);
1501 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1503 using namespace Menu_Helpers;
1504 Menu* (Editor::*build_menu_function)();
1507 switch (item_type) {
1509 case RegionViewName:
1510 case RegionViewNameHighlight:
1511 case LeftFrameHandle:
1512 case RightFrameHandle:
1513 if (with_selection) {
1514 build_menu_function = &Editor::build_track_selection_context_menu;
1516 build_menu_function = &Editor::build_track_region_context_menu;
1521 if (with_selection) {
1522 build_menu_function = &Editor::build_track_selection_context_menu;
1524 build_menu_function = &Editor::build_track_context_menu;
1529 if (clicked_routeview->track()) {
1530 build_menu_function = &Editor::build_track_context_menu;
1532 build_menu_function = &Editor::build_track_bus_context_menu;
1537 /* probably shouldn't happen but if it does, we don't care */
1541 menu = (this->*build_menu_function)();
1542 menu->set_name ("ArdourContextMenu");
1544 /* now handle specific situations */
1546 switch (item_type) {
1548 case RegionViewName:
1549 case RegionViewNameHighlight:
1550 case LeftFrameHandle:
1551 case RightFrameHandle:
1552 if (!with_selection) {
1553 if (region_edit_menu_split_item) {
1554 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1555 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1557 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1560 if (region_edit_menu_split_multichannel_item) {
1561 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1562 region_edit_menu_split_multichannel_item->set_sensitive (true);
1564 region_edit_menu_split_multichannel_item->set_sensitive (false);
1577 /* probably shouldn't happen but if it does, we don't care */
1581 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1583 /* Bounce to disk */
1585 using namespace Menu_Helpers;
1586 MenuList& edit_items = menu->items();
1588 edit_items.push_back (SeparatorElem());
1590 switch (clicked_routeview->audio_track()->freeze_state()) {
1591 case AudioTrack::NoFreeze:
1592 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1595 case AudioTrack::Frozen:
1596 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1599 case AudioTrack::UnFrozen:
1600 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1606 if (item_type == StreamItem && clicked_routeview) {
1607 clicked_routeview->build_underlay_menu(menu);
1610 /* When the region menu is opened, we setup the actions so that they look right
1613 sensitize_the_right_region_actions ();
1614 _last_region_menu_was_main = false;
1616 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1617 menu->popup (button, time);
1621 Editor::build_track_context_menu ()
1623 using namespace Menu_Helpers;
1625 MenuList& edit_items = track_context_menu.items();
1628 add_dstream_context_items (edit_items);
1629 return &track_context_menu;
1633 Editor::build_track_bus_context_menu ()
1635 using namespace Menu_Helpers;
1637 MenuList& edit_items = track_context_menu.items();
1640 add_bus_context_items (edit_items);
1641 return &track_context_menu;
1645 Editor::build_track_region_context_menu ()
1647 using namespace Menu_Helpers;
1648 MenuList& edit_items = track_region_context_menu.items();
1651 /* we've just cleared the track region context menu, so the menu that these
1652 two items were on will have disappeared; stop them dangling.
1654 region_edit_menu_split_item = 0;
1655 region_edit_menu_split_multichannel_item = 0;
1657 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1660 boost::shared_ptr<Track> tr;
1661 boost::shared_ptr<Playlist> pl;
1663 if ((tr = rtv->track())) {
1664 add_region_context_items (edit_items, tr);
1668 add_dstream_context_items (edit_items);
1670 return &track_region_context_menu;
1674 Editor::analyze_region_selection ()
1676 if (analysis_window == 0) {
1677 analysis_window = new AnalysisWindow();
1680 analysis_window->set_session(_session);
1682 analysis_window->show_all();
1685 analysis_window->set_regionmode();
1686 analysis_window->analyze();
1688 analysis_window->present();
1692 Editor::analyze_range_selection()
1694 if (analysis_window == 0) {
1695 analysis_window = new AnalysisWindow();
1698 analysis_window->set_session(_session);
1700 analysis_window->show_all();
1703 analysis_window->set_rangemode();
1704 analysis_window->analyze();
1706 analysis_window->present();
1710 Editor::build_track_selection_context_menu ()
1712 using namespace Menu_Helpers;
1713 MenuList& edit_items = track_selection_context_menu.items();
1714 edit_items.clear ();
1716 add_selection_context_items (edit_items);
1717 // edit_items.push_back (SeparatorElem());
1718 // add_dstream_context_items (edit_items);
1720 return &track_selection_context_menu;
1724 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1726 using namespace Menu_Helpers;
1728 /* OK, stick the region submenu at the top of the list, and then add
1732 RegionSelection rs = get_regions_from_selection_and_entered ();
1734 string::size_type pos = 0;
1735 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1737 /* we have to hack up the region name because "_" has a special
1738 meaning for menu titles.
1741 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1742 menu_item_name.replace (pos, 1, "__");
1746 if (_popup_region_menu_item == 0) {
1747 _popup_region_menu_item = new MenuItem (menu_item_name);
1748 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1749 _popup_region_menu_item->show ();
1751 _popup_region_menu_item->set_label (menu_item_name);
1754 const framepos_t position = get_preferred_edit_position (false, true);
1756 edit_items.push_back (*_popup_region_menu_item);
1757 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1758 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1760 edit_items.push_back (SeparatorElem());
1763 /** Add context menu items relevant to selection ranges.
1764 * @param edit_items List to add the items to.
1767 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1769 using namespace Menu_Helpers;
1771 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1772 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1774 edit_items.push_back (SeparatorElem());
1775 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1777 edit_items.push_back (SeparatorElem());
1778 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1780 edit_items.push_back (SeparatorElem());
1782 edit_items.push_back (
1784 _("Move Range Start to Previous Region Boundary"),
1785 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1789 edit_items.push_back (
1791 _("Move Range Start to Next Region Boundary"),
1792 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1796 edit_items.push_back (
1798 _("Move Range End to Previous Region Boundary"),
1799 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1803 edit_items.push_back (
1805 _("Move Range End to Next Region Boundary"),
1806 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1810 edit_items.push_back (SeparatorElem());
1811 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1812 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1814 edit_items.push_back (SeparatorElem());
1815 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1817 edit_items.push_back (SeparatorElem());
1818 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1819 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1821 edit_items.push_back (SeparatorElem());
1822 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1824 edit_items.push_back (SeparatorElem());
1825 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1826 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1827 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1829 edit_items.push_back (SeparatorElem());
1830 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1831 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1832 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1833 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1834 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1835 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1836 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1842 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1844 using namespace Menu_Helpers;
1848 Menu *play_menu = manage (new Menu);
1849 MenuList& play_items = play_menu->items();
1850 play_menu->set_name ("ArdourContextMenu");
1852 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1853 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1854 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1855 play_items.push_back (SeparatorElem());
1856 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1858 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1862 Menu *select_menu = manage (new Menu);
1863 MenuList& select_items = select_menu->items();
1864 select_menu->set_name ("ArdourContextMenu");
1866 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1867 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1868 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1869 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1870 select_items.push_back (SeparatorElem());
1871 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1872 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1873 select_items.push_back (SeparatorElem());
1874 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1875 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1876 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1877 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1878 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1879 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1880 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1882 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1886 Menu *cutnpaste_menu = manage (new Menu);
1887 MenuList& cutnpaste_items = cutnpaste_menu->items();
1888 cutnpaste_menu->set_name ("ArdourContextMenu");
1890 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1891 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1892 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1894 cutnpaste_items.push_back (SeparatorElem());
1896 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1897 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1899 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1901 /* Adding new material */
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1905 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1909 Menu *nudge_menu = manage (new Menu());
1910 MenuList& nudge_items = nudge_menu->items();
1911 nudge_menu->set_name ("ArdourContextMenu");
1913 edit_items.push_back (SeparatorElem());
1914 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1915 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1916 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1917 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1919 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1923 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1925 using namespace Menu_Helpers;
1929 Menu *play_menu = manage (new Menu);
1930 MenuList& play_items = play_menu->items();
1931 play_menu->set_name ("ArdourContextMenu");
1933 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1934 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1935 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1939 Menu *select_menu = manage (new Menu);
1940 MenuList& select_items = select_menu->items();
1941 select_menu->set_name ("ArdourContextMenu");
1943 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1944 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1945 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1946 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1947 select_items.push_back (SeparatorElem());
1948 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1949 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1950 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1951 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1953 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1957 Menu *cutnpaste_menu = manage (new Menu);
1958 MenuList& cutnpaste_items = cutnpaste_menu->items();
1959 cutnpaste_menu->set_name ("ArdourContextMenu");
1961 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1962 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1963 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1965 Menu *nudge_menu = manage (new Menu());
1966 MenuList& nudge_items = nudge_menu->items();
1967 nudge_menu->set_name ("ArdourContextMenu");
1969 edit_items.push_back (SeparatorElem());
1970 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1971 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1972 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1973 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1975 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1979 Editor::snap_type() const
1985 Editor::snap_mode() const
1991 Editor::set_snap_to (SnapType st)
1993 unsigned int snap_ind = (unsigned int)st;
1997 if (snap_ind > snap_type_strings.size() - 1) {
1999 _snap_type = (SnapType)snap_ind;
2002 string str = snap_type_strings[snap_ind];
2004 if (str != snap_type_selector.get_text()) {
2005 snap_type_selector.set_text (str);
2010 switch (_snap_type) {
2011 case SnapToBeatDiv128:
2012 case SnapToBeatDiv64:
2013 case SnapToBeatDiv32:
2014 case SnapToBeatDiv28:
2015 case SnapToBeatDiv24:
2016 case SnapToBeatDiv20:
2017 case SnapToBeatDiv16:
2018 case SnapToBeatDiv14:
2019 case SnapToBeatDiv12:
2020 case SnapToBeatDiv10:
2021 case SnapToBeatDiv8:
2022 case SnapToBeatDiv7:
2023 case SnapToBeatDiv6:
2024 case SnapToBeatDiv5:
2025 case SnapToBeatDiv4:
2026 case SnapToBeatDiv3:
2027 case SnapToBeatDiv2: {
2028 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2029 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2031 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2032 current_bbt_points_begin, current_bbt_points_end);
2033 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2034 current_bbt_points_begin, current_bbt_points_end);
2035 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2039 case SnapToRegionStart:
2040 case SnapToRegionEnd:
2041 case SnapToRegionSync:
2042 case SnapToRegionBoundary:
2043 build_region_boundary_cache ();
2051 SnapChanged (); /* EMIT SIGNAL */
2055 Editor::set_snap_mode (SnapMode mode)
2057 string str = snap_mode_strings[(int)mode];
2059 if (_internal_editing) {
2060 internal_snap_mode = mode;
2062 pre_internal_snap_mode = mode;
2067 if (str != snap_mode_selector.get_text ()) {
2068 snap_mode_selector.set_text (str);
2074 Editor::set_edit_point_preference (EditPoint ep, bool force)
2076 bool changed = (_edit_point != ep);
2079 string str = edit_point_strings[(int)ep];
2081 if (Profile->get_mixbus())
2082 if (ep == EditAtSelectedMarker)
2083 ep = EditAtPlayhead;
2085 if (str != edit_point_selector.get_text ()) {
2086 edit_point_selector.set_text (str);
2089 reset_canvas_cursor ();
2091 if (!force && !changed) {
2095 const char* action=NULL;
2097 switch (_edit_point) {
2098 case EditAtPlayhead:
2099 action = "edit-at-playhead";
2101 case EditAtSelectedMarker:
2102 action = "edit-at-marker";
2105 action = "edit-at-mouse";
2109 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2111 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2115 bool in_track_canvas;
2117 if (!mouse_frame (foo, in_track_canvas)) {
2118 in_track_canvas = false;
2121 reset_canvas_action_sensitivity (in_track_canvas);
2127 Editor::set_state (const XMLNode& node, int /*version*/)
2129 const XMLProperty* prop;
2136 g.base_width = default_width;
2137 g.base_height = default_height;
2141 if ((geometry = find_named_node (node, "geometry")) != 0) {
2145 if ((prop = geometry->property("x_size")) == 0) {
2146 prop = geometry->property ("x-size");
2149 g.base_width = atoi(prop->value());
2151 if ((prop = geometry->property("y_size")) == 0) {
2152 prop = geometry->property ("y-size");
2155 g.base_height = atoi(prop->value());
2158 if ((prop = geometry->property ("x_pos")) == 0) {
2159 prop = geometry->property ("x-pos");
2162 x = atoi (prop->value());
2165 if ((prop = geometry->property ("y_pos")) == 0) {
2166 prop = geometry->property ("y-pos");
2169 y = atoi (prop->value());
2173 set_default_size (g.base_width, g.base_height);
2176 if (_session && (prop = node.property ("playhead"))) {
2178 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2179 playhead_cursor->set_position (pos);
2181 playhead_cursor->set_position (0);
2184 if ((prop = node.property ("mixer-width"))) {
2185 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2188 if ((prop = node.property ("zoom-focus"))) {
2189 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2192 if ((prop = node.property ("zoom"))) {
2193 /* older versions of ardour used floating point samples_per_pixel */
2194 double f = PBD::atof (prop->value());
2195 reset_zoom (llrintf (f));
2197 reset_zoom (samples_per_pixel);
2200 if ((prop = node.property ("visible-track-count"))) {
2201 set_visible_track_count (PBD::atoi (prop->value()));
2204 if ((prop = node.property ("snap-to"))) {
2205 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2208 if ((prop = node.property ("snap-mode"))) {
2209 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2212 if ((prop = node.property ("internal-snap-to"))) {
2213 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2216 if ((prop = node.property ("internal-snap-mode"))) {
2217 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2220 if ((prop = node.property ("pre-internal-snap-to"))) {
2221 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2225 if ((prop = node.property ("pre-internal-snap-mode"))) {
2226 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2229 if ((prop = node.property ("mouse-mode"))) {
2230 MouseMode m = str2mousemode(prop->value());
2231 set_mouse_mode (m, true);
2233 set_mouse_mode (MouseObject, true);
2236 if ((prop = node.property ("left-frame")) != 0) {
2238 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2242 reset_x_origin (pos);
2246 if ((prop = node.property ("y-origin")) != 0) {
2247 reset_y_origin (atof (prop->value ()));
2250 if ((prop = node.property ("internal-edit"))) {
2251 bool yn = string_is_affirmative (prop->value());
2252 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2254 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2255 tact->set_active (!yn);
2256 tact->set_active (yn);
2260 if ((prop = node.property ("join-object-range"))) {
2261 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2262 bool yn = string_is_affirmative (prop->value());
2264 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2265 tact->set_active (!yn);
2266 tact->set_active (yn);
2268 set_mouse_mode(mouse_mode, true);
2271 if ((prop = node.property ("edit-point"))) {
2272 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2275 if ((prop = node.property ("show-measures"))) {
2276 bool yn = string_is_affirmative (prop->value());
2277 _show_measures = yn;
2278 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2280 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2281 /* do it twice to force the change */
2282 tact->set_active (!yn);
2283 tact->set_active (yn);
2287 if ((prop = node.property ("follow-playhead"))) {
2288 bool yn = string_is_affirmative (prop->value());
2289 set_follow_playhead (yn);
2290 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2292 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2293 if (tact->get_active() != yn) {
2294 tact->set_active (yn);
2299 if ((prop = node.property ("stationary-playhead"))) {
2300 bool yn = string_is_affirmative (prop->value());
2301 set_stationary_playhead (yn);
2302 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2304 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2305 if (tact->get_active() != yn) {
2306 tact->set_active (yn);
2311 if ((prop = node.property ("region-list-sort-type"))) {
2312 RegionListSortType st;
2313 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2316 if ((prop = node.property ("show-editor-mixer"))) {
2318 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2321 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2322 bool yn = string_is_affirmative (prop->value());
2324 /* do it twice to force the change */
2326 tact->set_active (!yn);
2327 tact->set_active (yn);
2330 if ((prop = node.property ("show-editor-list"))) {
2332 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2335 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2336 bool yn = string_is_affirmative (prop->value());
2338 /* do it twice to force the change */
2340 tact->set_active (!yn);
2341 tact->set_active (yn);
2344 if ((prop = node.property (X_("editor-list-page")))) {
2345 _the_notebook.set_current_page (atoi (prop->value ()));
2348 if ((prop = node.property (X_("show-marker-lines")))) {
2349 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2351 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2352 bool yn = string_is_affirmative (prop->value ());
2354 tact->set_active (!yn);
2355 tact->set_active (yn);
2358 XMLNodeList children = node.children ();
2359 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2360 selection->set_state (**i, Stateful::current_state_version);
2361 _regions->set_state (**i);
2364 if ((prop = node.property ("maximised"))) {
2365 bool yn = string_is_affirmative (prop->value());
2366 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2368 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2369 bool fs = tact && tact->get_active();
2371 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2375 if ((prop = node.property ("nudge-clock-value"))) {
2377 sscanf (prop->value().c_str(), "%" PRId64, &f);
2378 nudge_clock->set (f);
2380 nudge_clock->set_mode (AudioClock::Timecode);
2381 nudge_clock->set (_session->frame_rate() * 5, true);
2388 Editor::get_state ()
2390 XMLNode* node = new XMLNode ("Editor");
2393 id().print (buf, sizeof (buf));
2394 node->add_property ("id", buf);
2396 if (is_realized()) {
2397 Glib::RefPtr<Gdk::Window> win = get_window();
2399 int x, y, width, height;
2400 win->get_root_origin(x, y);
2401 win->get_size(width, height);
2403 XMLNode* geometry = new XMLNode ("geometry");
2405 snprintf(buf, sizeof(buf), "%d", width);
2406 geometry->add_property("x-size", string(buf));
2407 snprintf(buf, sizeof(buf), "%d", height);
2408 geometry->add_property("y-size", string(buf));
2409 snprintf(buf, sizeof(buf), "%d", x);
2410 geometry->add_property("x-pos", string(buf));
2411 snprintf(buf, sizeof(buf), "%d", y);
2412 geometry->add_property("y-pos", string(buf));
2413 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2414 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2415 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2416 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2417 geometry->add_property("edit-vertical-pane-pos", string(buf));
2419 node->add_child_nocopy (*geometry);
2422 maybe_add_mixer_strip_width (*node);
2424 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2426 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2427 node->add_property ("zoom", buf);
2428 node->add_property ("snap-to", enum_2_string (_snap_type));
2429 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2430 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2431 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2432 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2433 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2434 node->add_property ("edit-point", enum_2_string (_edit_point));
2435 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2436 node->add_property ("visible-track-count", buf);
2438 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2439 node->add_property ("playhead", buf);
2440 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2441 node->add_property ("left-frame", buf);
2442 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2443 node->add_property ("y-origin", buf);
2445 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2446 node->add_property ("maximised", _maximised ? "yes" : "no");
2447 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2448 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2449 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2450 node->add_property ("mouse-mode", enum2str(mouse_mode));
2451 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2452 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2454 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2456 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2457 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2460 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2462 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2463 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2466 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2467 node->add_property (X_("editor-list-page"), buf);
2469 if (button_bindings) {
2470 XMLNode* bb = new XMLNode (X_("Buttons"));
2471 button_bindings->save (*bb);
2472 node->add_child_nocopy (*bb);
2475 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2477 node->add_child_nocopy (selection->get_state ());
2478 node->add_child_nocopy (_regions->get_state ());
2480 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2481 node->add_property ("nudge-clock-value", buf);
2486 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2487 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2489 * @return pair: TimeAxisView that y is over, layer index.
2491 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2492 * in stacked or expanded region display mode, otherwise 0.
2494 std::pair<TimeAxisView *, double>
2495 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2497 if (!trackview_relative_offset) {
2498 y -= _trackview_group->canvas_origin().y;
2502 return std::make_pair ( (TimeAxisView *) 0, 0);
2505 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2507 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2514 return std::make_pair ( (TimeAxisView *) 0, 0);
2517 /** Snap a position to the grid, if appropriate, taking into account current
2518 * grid settings and also the state of any snap modifier keys that may be pressed.
2519 * @param start Position to snap.
2520 * @param event Event to get current key modifier information from, or 0.
2523 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2525 if (!_session || !event) {
2529 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2530 if (_snap_mode == SnapOff) {
2531 snap_to_internal (start, direction, for_mark);
2534 if (_snap_mode != SnapOff) {
2535 snap_to_internal (start, direction, for_mark);
2541 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2543 if (!_session || _snap_mode == SnapOff) {
2547 snap_to_internal (start, direction, for_mark);
2551 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2553 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2554 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2556 switch (_snap_type) {
2557 case SnapToTimecodeFrame:
2558 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2559 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2561 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2565 case SnapToTimecodeSeconds:
2566 if (_session->config.get_timecode_offset_negative()) {
2567 start += _session->config.get_timecode_offset ();
2569 start -= _session->config.get_timecode_offset ();
2571 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2572 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2574 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2577 if (_session->config.get_timecode_offset_negative()) {
2578 start -= _session->config.get_timecode_offset ();
2580 start += _session->config.get_timecode_offset ();
2584 case SnapToTimecodeMinutes:
2585 if (_session->config.get_timecode_offset_negative()) {
2586 start += _session->config.get_timecode_offset ();
2588 start -= _session->config.get_timecode_offset ();
2590 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2591 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2593 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2595 if (_session->config.get_timecode_offset_negative()) {
2596 start -= _session->config.get_timecode_offset ();
2598 start += _session->config.get_timecode_offset ();
2602 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2608 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2610 const framepos_t one_second = _session->frame_rate();
2611 const framepos_t one_minute = _session->frame_rate() * 60;
2612 framepos_t presnap = start;
2616 switch (_snap_type) {
2617 case SnapToTimecodeFrame:
2618 case SnapToTimecodeSeconds:
2619 case SnapToTimecodeMinutes:
2620 return timecode_snap_to_internal (start, direction, for_mark);
2623 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2624 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2626 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2631 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2632 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2634 start = (framepos_t) floor ((double) start / one_second) * one_second;
2639 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2640 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2642 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2647 start = _session->tempo_map().round_to_bar (start, direction);
2651 start = _session->tempo_map().round_to_beat (start, direction);
2654 case SnapToBeatDiv128:
2655 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2657 case SnapToBeatDiv64:
2658 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2660 case SnapToBeatDiv32:
2661 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2663 case SnapToBeatDiv28:
2664 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2666 case SnapToBeatDiv24:
2667 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2669 case SnapToBeatDiv20:
2670 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2672 case SnapToBeatDiv16:
2673 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2675 case SnapToBeatDiv14:
2676 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2678 case SnapToBeatDiv12:
2679 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2681 case SnapToBeatDiv10:
2682 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2684 case SnapToBeatDiv8:
2685 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2687 case SnapToBeatDiv7:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2690 case SnapToBeatDiv6:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2693 case SnapToBeatDiv5:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2696 case SnapToBeatDiv4:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2699 case SnapToBeatDiv3:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2702 case SnapToBeatDiv2:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2711 _session->locations()->marks_either_side (start, before, after);
2713 if (before == max_framepos && after == max_framepos) {
2714 /* No marks to snap to, so just don't snap */
2716 } else if (before == max_framepos) {
2718 } else if (after == max_framepos) {
2720 } else if (before != max_framepos && after != max_framepos) {
2721 /* have before and after */
2722 if ((start - before) < (after - start)) {
2731 case SnapToRegionStart:
2732 case SnapToRegionEnd:
2733 case SnapToRegionSync:
2734 case SnapToRegionBoundary:
2735 if (!region_boundary_cache.empty()) {
2737 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2738 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2740 if (direction > 0) {
2741 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2743 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2746 if (next != region_boundary_cache.begin ()) {
2751 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2752 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2754 if (start > (p + n) / 2) {
2763 switch (_snap_mode) {
2769 if (presnap > start) {
2770 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2774 } else if (presnap < start) {
2775 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2781 /* handled at entry */
2789 Editor::setup_toolbar ()
2791 HBox* mode_box = manage(new HBox);
2792 mode_box->set_border_width (2);
2793 mode_box->set_spacing(2);
2795 HBox* mouse_mode_box = manage (new HBox);
2796 HBox* mouse_mode_hbox = manage (new HBox);
2797 VBox* mouse_mode_vbox = manage (new VBox);
2798 Alignment* mouse_mode_align = manage (new Alignment);
2800 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2801 //mouse_mode_size_group->add_widget (smart_mode_button);
2802 mouse_mode_size_group->add_widget (mouse_move_button);
2803 mouse_mode_size_group->add_widget (mouse_cut_button);
2804 mouse_mode_size_group->add_widget (mouse_select_button);
2805 mouse_mode_size_group->add_widget (mouse_zoom_button);
2806 mouse_mode_size_group->add_widget (mouse_gain_button);
2807 mouse_mode_size_group->add_widget (mouse_timefx_button);
2808 mouse_mode_size_group->add_widget (mouse_audition_button);
2809 mouse_mode_size_group->add_widget (mouse_draw_button);
2810 mouse_mode_size_group->add_widget (internal_edit_button);
2812 if (!ARDOUR::Profile->get_small_screen()) {
2813 /* make them just a bit bigger */
2814 mouse_move_button.set_size_request (24, 30);
2816 /* make them just a bit taller */
2817 mouse_move_button.set_size_request (-1, 30);
2819 mouse_mode_hbox->set_spacing (2);
2821 if (!ARDOUR::Profile->get_trx()) {
2822 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2825 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2826 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2828 if (!ARDOUR::Profile->get_mixbus()) {
2829 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2830 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2833 if (!ARDOUR::Profile->get_trx()) {
2834 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2835 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2836 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2837 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2838 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 4);
2841 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2843 mouse_mode_align->add (*mouse_mode_vbox);
2844 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2846 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2848 edit_mode_selector.set_name ("mouse mode button");
2850 if (!ARDOUR::Profile->get_trx()) {
2851 mode_box->pack_start (edit_mode_selector, false, false);
2853 mode_box->pack_start (*mouse_mode_box, false, false);
2855 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2856 _mouse_mode_tearoff->set_name ("MouseModeBase");
2857 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2859 if (Profile->get_sae() || Profile->get_mixbus() ) {
2860 _mouse_mode_tearoff->set_can_be_torn_off (false);
2863 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2864 &_mouse_mode_tearoff->tearoff_window()));
2865 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2866 &_mouse_mode_tearoff->tearoff_window(), 1));
2867 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2868 &_mouse_mode_tearoff->tearoff_window()));
2869 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2870 &_mouse_mode_tearoff->tearoff_window(), 1));
2874 _zoom_box.set_spacing (2);
2875 _zoom_box.set_border_width (2);
2879 zoom_preset_selector.set_name ("zoom button");
2880 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2881 zoom_preset_selector.set_size_request (42, -1);
2883 zoom_in_button.set_name ("zoom button");
2884 // zoom_in_button.add_elements ( ArdourButton::Inset );
2885 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2886 zoom_in_button.set_image(::get_icon ("zoom_in"));
2887 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2888 zoom_in_button.set_related_action (act);
2890 zoom_out_button.set_name ("zoom button");
2891 // zoom_out_button.add_elements ( ArdourButton::Inset );
2892 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2893 zoom_out_button.set_image(::get_icon ("zoom_out"));
2894 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2895 zoom_out_button.set_related_action (act);
2897 zoom_out_full_button.set_name ("zoom button");
2898 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2899 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2900 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2901 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2902 zoom_out_full_button.set_related_action (act);
2904 zoom_focus_selector.set_name ("zoom button");
2905 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2907 if (ARDOUR::Profile->get_mixbus()) {
2908 _zoom_box.pack_start (zoom_preset_selector, false, false);
2909 } else if (ARDOUR::Profile->get_trx()) {
2910 mode_box->pack_start (zoom_out_button, false, false);
2911 mode_box->pack_start (zoom_in_button, false, false);
2913 _zoom_box.pack_start (zoom_out_button, false, false);
2914 _zoom_box.pack_start (zoom_in_button, false, false);
2915 _zoom_box.pack_start (zoom_out_full_button, false, false);
2916 _zoom_box.pack_start (zoom_focus_selector, false, false);
2919 /* Track zoom buttons */
2920 visible_tracks_selector.set_name ("zoom button");
2921 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2922 if (Profile->get_mixbus()) {
2923 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2924 visible_tracks_selector.set_size_request (42, -1);
2926 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2929 tav_expand_button.set_name ("zoom button");
2930 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2931 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2932 tav_expand_button.set_size_request (-1, 20);
2933 tav_expand_button.set_image(::get_icon ("tav_exp"));
2934 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2935 tav_expand_button.set_related_action (act);
2937 tav_shrink_button.set_name ("zoom button");
2938 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2939 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2940 tav_shrink_button.set_size_request (-1, 20);
2941 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2942 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2943 tav_shrink_button.set_related_action (act);
2945 if (ARDOUR::Profile->get_mixbus()) {
2946 _zoom_box.pack_start (visible_tracks_selector);
2947 } else if (ARDOUR::Profile->get_trx()) {
2948 _zoom_box.pack_start (tav_shrink_button);
2949 _zoom_box.pack_start (tav_expand_button);
2951 _zoom_box.pack_start (visible_tracks_selector);
2952 _zoom_box.pack_start (tav_shrink_button);
2953 _zoom_box.pack_start (tav_expand_button);
2956 if (!ARDOUR::Profile->get_trx()) {
2957 _zoom_tearoff = manage (new TearOff (_zoom_box));
2959 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2960 &_zoom_tearoff->tearoff_window()));
2961 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2962 &_zoom_tearoff->tearoff_window(), 0));
2963 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2964 &_zoom_tearoff->tearoff_window()));
2965 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2966 &_zoom_tearoff->tearoff_window(), 0));
2969 if (Profile->get_sae() || Profile->get_mixbus() ) {
2970 _zoom_tearoff->set_can_be_torn_off (false);
2973 snap_box.set_spacing (2);
2974 snap_box.set_border_width (2);
2976 snap_type_selector.set_name ("mouse mode button");
2978 snap_mode_selector.set_name ("mouse mode button");
2980 edit_point_selector.set_name ("mouse mode button");
2982 snap_box.pack_start (snap_mode_selector, false, false);
2983 snap_box.pack_start (snap_type_selector, false, false);
2984 snap_box.pack_start (edit_point_selector, false, false);
2988 HBox *nudge_box = manage (new HBox);
2989 nudge_box->set_spacing (2);
2990 nudge_box->set_border_width (2);
2992 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2993 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2995 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2996 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2998 nudge_box->pack_start (nudge_backward_button, false, false);
2999 nudge_box->pack_start (nudge_forward_button, false, false);
3000 nudge_box->pack_start (*nudge_clock, false, false);
3003 /* Pack everything in... */
3005 HBox* hbox = manage (new HBox);
3006 hbox->set_spacing(2);
3008 _tools_tearoff = manage (new TearOff (*hbox));
3009 _tools_tearoff->set_name ("MouseModeBase");
3010 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3012 if (Profile->get_sae() || Profile->get_mixbus()) {
3013 _tools_tearoff->set_can_be_torn_off (false);
3016 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3017 &_tools_tearoff->tearoff_window()));
3018 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3019 &_tools_tearoff->tearoff_window(), 0));
3020 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3021 &_tools_tearoff->tearoff_window()));
3022 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3023 &_tools_tearoff->tearoff_window(), 0));
3025 toolbar_hbox.set_spacing (2);
3026 toolbar_hbox.set_border_width (1);
3028 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3029 if (!ARDOUR::Profile->get_trx()) {
3030 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3031 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3034 if (!ARDOUR::Profile->get_trx()) {
3035 hbox->pack_start (snap_box, false, false);
3036 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3037 hbox->pack_start (*nudge_box, false, false);
3039 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3042 hbox->pack_start (panic_box, false, false);
3046 toolbar_base.set_name ("ToolBarBase");
3047 toolbar_base.add (toolbar_hbox);
3049 _toolbar_viewport.add (toolbar_base);
3050 /* stick to the required height but allow width to vary if there's not enough room */
3051 _toolbar_viewport.set_size_request (1, -1);
3053 toolbar_frame.set_shadow_type (SHADOW_OUT);
3054 toolbar_frame.set_name ("BaseFrame");
3055 toolbar_frame.add (_toolbar_viewport);
3059 Editor::build_edit_point_menu ()
3061 using namespace Menu_Helpers;
3063 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3064 if(!Profile->get_mixbus())
3065 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3066 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3068 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, _combo_pad_string, 2);
3072 Editor::build_edit_mode_menu ()
3074 using namespace Menu_Helpers;
3076 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3077 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3078 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3079 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3081 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, _combo_pad_string, 2);
3085 Editor::build_snap_mode_menu ()
3087 using namespace Menu_Helpers;
3089 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3090 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3091 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3093 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, _combo_pad_string, 2);
3097 Editor::build_snap_type_menu ()
3099 using namespace Menu_Helpers;
3101 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3102 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3103 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3104 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3105 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3106 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3107 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3108 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3109 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3110 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3111 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3112 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3113 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3114 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3115 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3116 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3117 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3118 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3119 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3120 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3121 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3122 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3123 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3124 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3125 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3126 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3132 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, _combo_pad_string, 2);
3137 Editor::setup_tooltips ()
3139 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3140 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3141 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3142 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3143 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3144 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3145 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3146 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3147 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3148 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3149 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3150 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3151 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3152 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3153 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3154 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3155 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3156 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3157 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3158 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3159 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3160 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3161 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3162 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3163 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3164 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3168 Editor::convert_drop_to_paths (
3169 vector<string>& paths,
3170 const RefPtr<Gdk::DragContext>& /*context*/,
3173 const SelectionData& data,
3177 if (_session == 0) {
3181 vector<string> uris = data.get_uris();
3185 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3186 are actually URI lists. So do it by hand.
3189 if (data.get_target() != "text/plain") {
3193 /* Parse the "uri-list" format that Nautilus provides,
3194 where each pathname is delimited by \r\n.
3196 THERE MAY BE NO NULL TERMINATING CHAR!!!
3199 string txt = data.get_text();
3203 p = (char *) malloc (txt.length() + 1);
3204 txt.copy (p, txt.length(), 0);
3205 p[txt.length()] = '\0';
3211 while (g_ascii_isspace (*p))
3215 while (*q && (*q != '\n') && (*q != '\r')) {
3222 while (q > p && g_ascii_isspace (*q))
3227 uris.push_back (string (p, q - p + 1));
3231 p = strchr (p, '\n');
3243 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3244 if ((*i).substr (0,7) == "file://") {
3245 paths.push_back (Glib::filename_from_uri (*i));
3253 Editor::new_tempo_section ()
3258 Editor::map_transport_state ()
3260 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3262 if (_session && _session->transport_stopped()) {
3263 have_pending_keyboard_selection = false;
3266 update_loop_range_view ();
3272 Editor::begin_reversible_command (string name)
3275 _session->begin_reversible_command (name);
3280 Editor::begin_reversible_command (GQuark q)
3283 _session->begin_reversible_command (q);
3288 Editor::commit_reversible_command ()
3291 _session->commit_reversible_command ();
3296 Editor::history_changed ()
3300 if (undo_action && _session) {
3301 if (_session->undo_depth() == 0) {
3302 label = S_("Command|Undo");
3304 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3306 undo_action->property_label() = label;
3309 if (redo_action && _session) {
3310 if (_session->redo_depth() == 0) {
3313 label = string_compose(_("Redo (%1)"), _session->next_redo());
3315 redo_action->property_label() = label;
3320 Editor::duplicate_range (bool with_dialog)
3324 RegionSelection rs = get_regions_from_selection_and_entered ();
3326 if ( selection->time.length() == 0 && rs.empty()) {
3332 ArdourDialog win (_("Duplicate"));
3333 Label label (_("Number of duplications:"));
3334 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3335 SpinButton spinner (adjustment, 0.0, 1);
3338 win.get_vbox()->set_spacing (12);
3339 win.get_vbox()->pack_start (hbox);
3340 hbox.set_border_width (6);
3341 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3343 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3344 place, visually. so do this by hand.
3347 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3348 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3349 spinner.grab_focus();
3355 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3356 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3357 win.set_default_response (RESPONSE_ACCEPT);
3359 spinner.grab_focus ();
3361 switch (win.run ()) {
3362 case RESPONSE_ACCEPT:
3368 times = adjustment.get_value();
3371 if ((current_mouse_mode() == Editing::MouseRange)) {
3372 if (selection->time.length()) {
3373 duplicate_selection (times);
3375 } else if (get_smart_mode()) {
3376 if (selection->time.length()) {
3377 duplicate_selection (times);
3379 duplicate_some_regions (rs, times);
3381 duplicate_some_regions (rs, times);
3386 Editor::set_edit_mode (EditMode m)
3388 Config->set_edit_mode (m);
3392 Editor::cycle_edit_mode ()
3394 switch (Config->get_edit_mode()) {
3396 if (Profile->get_sae()) {
3397 Config->set_edit_mode (Lock);
3399 Config->set_edit_mode (Ripple);
3404 Config->set_edit_mode (Lock);
3407 Config->set_edit_mode (Slide);
3413 Editor::edit_mode_selection_done ( EditMode m )
3415 Config->set_edit_mode ( m );
3419 Editor::snap_type_selection_done (SnapType snaptype)
3421 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3423 ract->set_active ();
3428 Editor::snap_mode_selection_done (SnapMode mode)
3430 RefPtr<RadioAction> ract = snap_mode_action (mode);
3433 ract->set_active (true);
3438 Editor::cycle_edit_point (bool with_marker)
3440 if(Profile->get_mixbus())
3441 with_marker = false;
3443 switch (_edit_point) {
3445 set_edit_point_preference (EditAtPlayhead);
3447 case EditAtPlayhead:
3449 set_edit_point_preference (EditAtSelectedMarker);
3451 set_edit_point_preference (EditAtMouse);
3454 case EditAtSelectedMarker:
3455 set_edit_point_preference (EditAtMouse);
3461 Editor::edit_point_selection_done (EditPoint ep)
3463 set_edit_point_preference ( ep );
3467 Editor::build_zoom_focus_menu ()
3469 using namespace Menu_Helpers;
3471 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3472 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3473 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3474 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3475 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3476 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3478 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, _combo_pad_string, 2);
3482 Editor::zoom_focus_selection_done ( ZoomFocus f )
3484 RefPtr<RadioAction> ract = zoom_focus_action (f);
3486 ract->set_active ();
3491 Editor::build_track_count_menu ()
3493 using namespace Menu_Helpers;
3495 if (!Profile->get_mixbus()) {
3496 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3497 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3498 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3499 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3500 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3501 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3502 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3503 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3504 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3505 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3506 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3507 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3508 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3510 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3511 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3512 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3513 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3514 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3515 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3516 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3517 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3518 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3519 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3521 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3522 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3523 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3524 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3525 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3526 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3527 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3528 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3529 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3530 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3531 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3536 Editor::set_zoom_preset (int64_t ms)
3539 temporal_zoom_session();
3543 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3544 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3548 Editor::set_visible_track_count (int32_t n)
3550 _visible_track_count = n;
3552 /* if the canvas hasn't really been allocated any size yet, just
3553 record the desired number of visible tracks and return. when canvas
3554 allocation happens, we will get called again and then we can do the
3558 if (_visible_canvas_height <= 1) {
3565 if (_visible_track_count > 0) {
3566 h = trackviews_height() / _visible_track_count;
3567 std::ostringstream s;
3568 s << _visible_track_count;
3570 } else if (_visible_track_count == 0) {
3572 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3573 if ((*i)->marked_for_display()) {
3577 h = trackviews_height() / n;
3580 /* negative value means that the visible track count has
3581 been overridden by explicit track height changes.
3583 visible_tracks_selector.set_text (X_("*"));
3587 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3588 (*i)->set_height (h);
3591 if (str != visible_tracks_selector.get_text()) {
3592 visible_tracks_selector.set_text (str);
3597 Editor::override_visible_track_count ()
3599 _visible_track_count = -_visible_track_count;
3600 visible_tracks_selector.set_text ( _("*") );
3604 Editor::edit_controls_button_release (GdkEventButton* ev)
3606 if (Keyboard::is_context_menu_event (ev)) {
3607 ARDOUR_UI::instance()->add_route (this);
3608 } else if (ev->button == 1) {
3609 selection->clear_tracks ();
3616 Editor::mouse_select_button_release (GdkEventButton* ev)
3618 /* this handles just right-clicks */
3620 if (ev->button != 3) {
3628 Editor::set_zoom_focus (ZoomFocus f)
3630 string str = zoom_focus_strings[(int)f];
3632 if (str != zoom_focus_selector.get_text()) {
3633 zoom_focus_selector.set_text (str);
3636 if (zoom_focus != f) {
3643 Editor::cycle_zoom_focus ()
3645 switch (zoom_focus) {
3647 set_zoom_focus (ZoomFocusRight);
3649 case ZoomFocusRight:
3650 set_zoom_focus (ZoomFocusCenter);
3652 case ZoomFocusCenter:
3653 set_zoom_focus (ZoomFocusPlayhead);
3655 case ZoomFocusPlayhead:
3656 set_zoom_focus (ZoomFocusMouse);
3658 case ZoomFocusMouse:
3659 set_zoom_focus (ZoomFocusEdit);
3662 set_zoom_focus (ZoomFocusLeft);
3668 Editor::ensure_float (Window& win)
3670 win.set_transient_for (*this);
3674 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3676 /* recover or initialize pane positions. do this here rather than earlier because
3677 we don't want the positions to change the child allocations, which they seem to do.
3683 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3692 XMLNode* geometry = find_named_node (*node, "geometry");
3694 if (which == static_cast<Paned*> (&edit_pane)) {
3696 if (done & Horizontal) {
3700 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3701 _notebook_shrunk = string_is_affirmative (prop->value ());
3704 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3705 /* initial allocation is 90% to canvas, 10% to notebook */
3706 pos = (int) floor (alloc.get_width() * 0.90f);
3707 snprintf (buf, sizeof(buf), "%d", pos);
3709 pos = atoi (prop->value());
3712 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3713 edit_pane.set_position (pos);
3716 done = (Pane) (done | Horizontal);
3718 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3720 if (done & Vertical) {
3724 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3725 /* initial allocation is 90% to canvas, 10% to summary */
3726 pos = (int) floor (alloc.get_height() * 0.90f);
3727 snprintf (buf, sizeof(buf), "%d", pos);
3730 pos = atoi (prop->value());
3733 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3734 editor_summary_pane.set_position (pos);
3737 done = (Pane) (done | Vertical);
3742 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3744 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3745 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3746 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3747 top_hbox.remove (toolbar_frame);
3752 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3754 if (toolbar_frame.get_parent() == 0) {
3755 top_hbox.pack_end (toolbar_frame);
3760 Editor::set_show_measures (bool yn)
3762 if (_show_measures != yn) {
3765 if ((_show_measures = yn) == true) {
3767 tempo_lines->show();
3770 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3771 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3773 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3774 draw_measures (begin, end);
3782 Editor::toggle_follow_playhead ()
3784 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3786 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3787 set_follow_playhead (tact->get_active());
3791 /** @param yn true to follow playhead, otherwise false.
3792 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3795 Editor::set_follow_playhead (bool yn, bool catch_up)
3797 if (_follow_playhead != yn) {
3798 if ((_follow_playhead = yn) == true && catch_up) {
3800 reset_x_origin_to_follow_playhead ();
3807 Editor::toggle_stationary_playhead ()
3809 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3811 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3812 set_stationary_playhead (tact->get_active());
3817 Editor::set_stationary_playhead (bool yn)
3819 if (_stationary_playhead != yn) {
3820 if ((_stationary_playhead = yn) == true) {
3822 // FIXME need a 3.0 equivalent of this 2.X call
3823 // update_current_screen ();
3830 Editor::playlist_selector () const
3832 return *_playlist_selector;
3836 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3840 switch (_snap_type) {
3845 case SnapToBeatDiv128:
3848 case SnapToBeatDiv64:
3851 case SnapToBeatDiv32:
3854 case SnapToBeatDiv28:
3857 case SnapToBeatDiv24:
3860 case SnapToBeatDiv20:
3863 case SnapToBeatDiv16:
3866 case SnapToBeatDiv14:
3869 case SnapToBeatDiv12:
3872 case SnapToBeatDiv10:
3875 case SnapToBeatDiv8:
3878 case SnapToBeatDiv7:
3881 case SnapToBeatDiv6:
3884 case SnapToBeatDiv5:
3887 case SnapToBeatDiv4:
3890 case SnapToBeatDiv3:
3893 case SnapToBeatDiv2:
3899 return _session->tempo_map().meter_at (position).divisions_per_bar();
3904 case SnapToTimecodeFrame:
3905 case SnapToTimecodeSeconds:
3906 case SnapToTimecodeMinutes:
3909 case SnapToRegionStart:
3910 case SnapToRegionEnd:
3911 case SnapToRegionSync:
3912 case SnapToRegionBoundary:
3922 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3926 ret = nudge_clock->current_duration (pos);
3927 next = ret + 1; /* XXXX fix me */
3933 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3935 ArdourDialog dialog (_("Playlist Deletion"));
3936 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3937 "If it is kept, its audio files will not be cleaned.\n"
3938 "If it is deleted, audio files used by it alone will be cleaned."),
3941 dialog.set_position (WIN_POS_CENTER);
3942 dialog.get_vbox()->pack_start (label);
3946 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3947 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3948 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3950 switch (dialog.run ()) {
3951 case RESPONSE_ACCEPT:
3952 /* delete the playlist */
3956 case RESPONSE_REJECT:
3957 /* keep the playlist */
3969 Editor::audio_region_selection_covers (framepos_t where)
3971 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3972 if ((*a)->region()->covers (where)) {
3981 Editor::prepare_for_cleanup ()
3983 cut_buffer->clear_regions ();
3984 cut_buffer->clear_playlists ();
3986 selection->clear_regions ();
3987 selection->clear_playlists ();
3989 _regions->suspend_redisplay ();
3993 Editor::finish_cleanup ()
3995 _regions->resume_redisplay ();
3999 Editor::transport_loop_location()
4002 return _session->locations()->auto_loop_location();
4009 Editor::transport_punch_location()
4012 return _session->locations()->auto_punch_location();
4019 Editor::control_layout_scroll (GdkEventScroll* ev)
4021 /* Just forward to the normal canvas scroll method. The coordinate
4022 systems are different but since the canvas is always larger than the
4023 track headers, and aligned with the trackview area, this will work.
4025 In the not too distant future this layout is going away anyway and
4026 headers will be on the canvas.
4028 return canvas_scroll_event (ev, false);
4032 Editor::session_state_saved (string)
4035 _snapshots->redisplay ();
4039 Editor::update_tearoff_visibility()
4041 bool visible = Config->get_keep_tearoffs();
4042 _mouse_mode_tearoff->set_visible (visible);
4043 _tools_tearoff->set_visible (visible);
4044 if (_zoom_tearoff) {
4045 _zoom_tearoff->set_visible (visible);
4050 Editor::maximise_editing_space ()
4062 Editor::restore_editing_space ()
4074 * Make new playlists for a given track and also any others that belong
4075 * to the same active route group with the `select' property.
4080 Editor::new_playlists (TimeAxisView* v)
4082 begin_reversible_command (_("new playlists"));
4083 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4084 _session->playlists->get (playlists);
4085 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4086 commit_reversible_command ();
4090 * Use a copy of the current playlist for a given track and also any others that belong
4091 * to the same active route group with the `select' property.
4096 Editor::copy_playlists (TimeAxisView* v)
4098 begin_reversible_command (_("copy playlists"));
4099 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4100 _session->playlists->get (playlists);
4101 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4102 commit_reversible_command ();
4105 /** Clear the current playlist for a given track and also any others that belong
4106 * to the same active route group with the `select' property.
4111 Editor::clear_playlists (TimeAxisView* v)
4113 begin_reversible_command (_("clear playlists"));
4114 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4115 _session->playlists->get (playlists);
4116 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4117 commit_reversible_command ();
4121 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4123 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4127 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4129 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4133 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4135 atv.clear_playlist ();
4139 Editor::on_key_press_event (GdkEventKey* ev)
4141 return key_press_focus_accelerator_handler (*this, ev);
4145 Editor::on_key_release_event (GdkEventKey* ev)
4147 return Gtk::Window::on_key_release_event (ev);
4148 // return key_press_focus_accelerator_handler (*this, ev);
4151 /** Queue up a change to the viewport x origin.
4152 * @param frame New x origin.
4155 Editor::reset_x_origin (framepos_t frame)
4157 pending_visual_change.add (VisualChange::TimeOrigin);
4158 pending_visual_change.time_origin = frame;
4159 ensure_visual_change_idle_handler ();
4163 Editor::reset_y_origin (double y)
4165 pending_visual_change.add (VisualChange::YOrigin);
4166 pending_visual_change.y_origin = y;
4167 ensure_visual_change_idle_handler ();
4171 Editor::reset_zoom (framecnt_t spp)
4173 if (spp == samples_per_pixel) {
4177 pending_visual_change.add (VisualChange::ZoomLevel);
4178 pending_visual_change.samples_per_pixel = spp;
4179 ensure_visual_change_idle_handler ();
4183 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4185 reset_x_origin (frame);
4188 if (!no_save_visual) {
4189 undo_visual_stack.push_back (current_visual_state(false));
4193 Editor::VisualState::VisualState (bool with_tracks)
4194 : gui_state (with_tracks ? new GUIObjectState : 0)
4198 Editor::VisualState::~VisualState ()
4203 Editor::VisualState*
4204 Editor::current_visual_state (bool with_tracks)
4206 VisualState* vs = new VisualState (with_tracks);
4207 vs->y_position = vertical_adjustment.get_value();
4208 vs->samples_per_pixel = samples_per_pixel;
4209 vs->leftmost_frame = leftmost_frame;
4210 vs->zoom_focus = zoom_focus;
4213 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4220 Editor::undo_visual_state ()
4222 if (undo_visual_stack.empty()) {
4226 VisualState* vs = undo_visual_stack.back();
4227 undo_visual_stack.pop_back();
4230 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4232 use_visual_state (*vs);
4236 Editor::redo_visual_state ()
4238 if (redo_visual_stack.empty()) {
4242 VisualState* vs = redo_visual_stack.back();
4243 redo_visual_stack.pop_back();
4245 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4247 use_visual_state (*vs);
4251 Editor::swap_visual_state ()
4253 if (undo_visual_stack.empty()) {
4254 redo_visual_state ();
4256 undo_visual_state ();
4261 Editor::use_visual_state (VisualState& vs)
4263 PBD::Unwinder<bool> nsv (no_save_visual, true);
4264 DisplaySuspender ds;
4266 vertical_adjustment.set_value (vs.y_position);
4268 set_zoom_focus (vs.zoom_focus);
4269 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4272 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4274 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4275 (*i)->reset_visual_state ();
4279 _routes->update_visibility ();
4282 /** This is the core function that controls the zoom level of the canvas. It is called
4283 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4284 * @param spp new number of samples per pixel
4287 Editor::set_samples_per_pixel (framecnt_t spp)
4293 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4294 const framecnt_t lots_of_pixels = 4000;
4296 /* if the zoom level is greater than what you'd get trying to display 3
4297 * days of audio on a really big screen, then it's too big.
4300 if (spp * lots_of_pixels > three_days) {
4304 samples_per_pixel = spp;
4307 tempo_lines->tempo_map_changed();
4310 bool const showing_time_selection = selection->time.length() > 0;
4312 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4313 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4314 (*i)->reshow_selection (selection->time);
4318 ZoomChanged (); /* EMIT_SIGNAL */
4320 ArdourCanvas::GtkCanvasViewport* c;
4322 c = get_track_canvas();
4324 c->canvas()->zoomed ();
4327 if (playhead_cursor) {
4328 playhead_cursor->set_position (playhead_cursor->current_frame ());
4331 refresh_location_display();
4332 _summary->set_overlays_dirty ();
4334 update_marker_labels ();
4340 Editor::queue_visual_videotimeline_update ()
4343 * pending_visual_change.add (VisualChange::VideoTimeline);
4344 * or maybe even more specific: which videotimeline-image
4345 * currently it calls update_video_timeline() to update
4346 * _all outdated_ images on the video-timeline.
4347 * see 'exposeimg()' in video_image_frame.cc
4349 ensure_visual_change_idle_handler ();
4353 Editor::ensure_visual_change_idle_handler ()
4355 if (pending_visual_change.idle_handler_id < 0) {
4356 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4357 pending_visual_change.being_handled = false;
4362 Editor::_idle_visual_changer (void* arg)
4364 return static_cast<Editor*>(arg)->idle_visual_changer ();
4368 Editor::idle_visual_changer ()
4370 /* set_horizontal_position() below (and maybe other calls) call
4371 gtk_main_iteration(), so it's possible that a signal will be handled
4372 half-way through this method. If this signal wants an
4373 idle_visual_changer we must schedule another one after this one, so
4374 mark the idle_handler_id as -1 here to allow that. Also make a note
4375 that we are doing the visual change, so that changes in response to
4376 super-rapid-screen-update can be dropped if we are still processing
4380 pending_visual_change.idle_handler_id = -1;
4381 pending_visual_change.being_handled = true;
4383 VisualChange vc = pending_visual_change;
4385 pending_visual_change.pending = (VisualChange::Type) 0;
4387 visual_changer (vc);
4389 pending_visual_change.being_handled = false;
4391 return 0; /* this is always a one-shot call */
4395 Editor::visual_changer (const VisualChange& vc)
4397 double const last_time_origin = horizontal_position ();
4399 if (vc.pending & VisualChange::ZoomLevel) {
4400 set_samples_per_pixel (vc.samples_per_pixel);
4402 compute_fixed_ruler_scale ();
4404 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4405 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4407 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4408 current_bbt_points_begin, current_bbt_points_end);
4409 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4410 current_bbt_points_begin, current_bbt_points_end);
4411 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4413 update_video_timeline();
4416 if (vc.pending & VisualChange::TimeOrigin) {
4417 set_horizontal_position (vc.time_origin / samples_per_pixel);
4420 if (vc.pending & VisualChange::YOrigin) {
4421 vertical_adjustment.set_value (vc.y_origin);
4424 if (last_time_origin == horizontal_position ()) {
4425 /* changed signal not emitted */
4426 update_fixed_rulers ();
4427 redisplay_tempo (true);
4430 if (!(vc.pending & VisualChange::ZoomLevel)) {
4431 update_video_timeline();
4434 _summary->set_overlays_dirty ();
4437 struct EditorOrderTimeAxisSorter {
4438 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4439 return a->order () < b->order ();
4444 Editor::sort_track_selection (TrackViewList& sel)
4446 EditorOrderTimeAxisSorter cmp;
4451 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4454 framepos_t where = 0;
4455 EditPoint ep = _edit_point;
4457 if(Profile->get_mixbus())
4458 if (ep == EditAtSelectedMarker)
4461 if (from_context_menu && (ep == EditAtMouse)) {
4462 return canvas_event_sample (&context_click_event, 0, 0);
4465 if (entered_marker) {
4466 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4467 return entered_marker->position();
4470 if (ignore_playhead && ep == EditAtPlayhead) {
4471 ep = EditAtSelectedMarker;
4475 case EditAtPlayhead:
4476 where = _session->audible_frame();
4477 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4480 case EditAtSelectedMarker:
4481 if (!selection->markers.empty()) {
4483 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4486 where = loc->start();
4490 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4498 if (!mouse_frame (where, ignored)) {
4499 /* XXX not right but what can we do ? */
4503 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4511 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4513 if (!_session) return;
4515 begin_reversible_command (cmd);
4519 if ((tll = transport_loop_location()) == 0) {
4520 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4521 XMLNode &before = _session->locations()->get_state();
4522 _session->locations()->add (loc, true);
4523 _session->set_auto_loop_location (loc);
4524 XMLNode &after = _session->locations()->get_state();
4525 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4527 XMLNode &before = tll->get_state();
4528 tll->set_hidden (false, this);
4529 tll->set (start, end);
4530 XMLNode &after = tll->get_state();
4531 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4534 commit_reversible_command ();
4538 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4540 if (!_session) return;
4542 begin_reversible_command (cmd);
4546 if ((tpl = transport_punch_location()) == 0) {
4547 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4548 XMLNode &before = _session->locations()->get_state();
4549 _session->locations()->add (loc, true);
4550 _session->set_auto_punch_location (loc);
4551 XMLNode &after = _session->locations()->get_state();
4552 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4555 XMLNode &before = tpl->get_state();
4556 tpl->set_hidden (false, this);
4557 tpl->set (start, end);
4558 XMLNode &after = tpl->get_state();
4559 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4562 commit_reversible_command ();
4565 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4566 * @param rs List to which found regions are added.
4567 * @param where Time to look at.
4568 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4571 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4573 const TrackViewList* tracks;
4576 tracks = &track_views;
4581 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4583 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4586 boost::shared_ptr<Track> tr;
4587 boost::shared_ptr<Playlist> pl;
4589 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4591 boost::shared_ptr<RegionList> regions = pl->regions_at (
4592 (framepos_t) floor ( (double) where * tr->speed()));
4594 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4595 RegionView* rv = rtv->view()->find_view (*i);
4606 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4608 const TrackViewList* tracks;
4611 tracks = &track_views;
4616 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4617 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4619 boost::shared_ptr<Track> tr;
4620 boost::shared_ptr<Playlist> pl;
4622 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4624 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4625 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4627 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4629 RegionView* rv = rtv->view()->find_view (*i);
4640 /** Get regions using the following method:
4642 * Make a region list using:
4643 * (a) any selected regions
4644 * (b) the intersection of any selected tracks and the edit point(*)
4645 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4647 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4649 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4653 Editor::get_regions_from_selection_and_edit_point ()
4655 RegionSelection regions;
4657 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4658 regions.add (entered_regionview);
4660 regions = selection->regions;
4663 if ( regions.empty() ) {
4664 TrackViewList tracks = selection->tracks;
4666 if (!tracks.empty()) {
4667 /* no region selected or entered, but some selected tracks:
4668 * act on all regions on the selected tracks at the edit point
4670 framepos_t const where = get_preferred_edit_position ();
4671 get_regions_at(regions, where, tracks);
4678 /** Get regions using the following method:
4680 * Make a region list using:
4681 * (a) any selected regions
4682 * (b) the intersection of any selected tracks and the edit point(*)
4683 * (c) if neither exists, then whatever region is under the mouse
4685 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4687 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4690 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4692 RegionSelection regions;
4694 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4695 regions.add (entered_regionview);
4697 regions = selection->regions;
4700 if ( regions.empty() ) {
4701 TrackViewList tracks = selection->tracks;
4703 if (!tracks.empty()) {
4704 /* no region selected or entered, but some selected tracks:
4705 * act on all regions on the selected tracks at the edit point
4707 get_regions_at(regions, pos, tracks);
4714 /** Start with regions that are selected, or the entered regionview if none are selected.
4715 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4716 * of the regions that we started with.
4720 Editor::get_regions_from_selection_and_entered ()
4722 RegionSelection regions = selection->regions;
4724 if (regions.empty() && entered_regionview) {
4725 regions.add (entered_regionview);
4732 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4734 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4736 RouteTimeAxisView* tatv;
4738 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4740 boost::shared_ptr<Playlist> pl;
4741 vector<boost::shared_ptr<Region> > results;
4743 boost::shared_ptr<Track> tr;
4745 if ((tr = tatv->track()) == 0) {
4750 if ((pl = (tr->playlist())) != 0) {
4751 if (src_comparison) {
4752 pl->get_source_equivalent_regions (region, results);
4754 pl->get_region_list_equivalent_regions (region, results);
4758 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4759 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4760 regions.push_back (marv);
4769 Editor::show_rhythm_ferret ()
4771 if (rhythm_ferret == 0) {
4772 rhythm_ferret = new RhythmFerret(*this);
4775 rhythm_ferret->set_session (_session);
4776 rhythm_ferret->show ();
4777 rhythm_ferret->present ();
4781 Editor::first_idle ()
4783 MessageDialog* dialog = 0;
4785 if (track_views.size() > 1) {
4786 dialog = new MessageDialog (
4788 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4792 ARDOUR_UI::instance()->flush_pending ();
4795 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4799 // first idle adds route children (automation tracks), so we need to redisplay here
4800 _routes->redisplay ();
4807 Editor::_idle_resize (gpointer arg)
4809 return ((Editor*)arg)->idle_resize ();
4813 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4815 if (resize_idle_id < 0) {
4816 resize_idle_id = g_idle_add (_idle_resize, this);
4817 _pending_resize_amount = 0;
4820 /* make a note of the smallest resulting height, so that we can clamp the
4821 lower limit at TimeAxisView::hSmall */
4823 int32_t min_resulting = INT32_MAX;
4825 _pending_resize_amount += h;
4826 _pending_resize_view = view;
4828 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4830 if (selection->tracks.contains (_pending_resize_view)) {
4831 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4832 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4836 if (min_resulting < 0) {
4841 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4842 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4846 /** Handle pending resizing of tracks */
4848 Editor::idle_resize ()
4850 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4852 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4853 selection->tracks.contains (_pending_resize_view)) {
4855 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4856 if (*i != _pending_resize_view) {
4857 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4862 _pending_resize_amount = 0;
4863 _group_tabs->set_dirty ();
4864 resize_idle_id = -1;
4872 ENSURE_GUI_THREAD (*this, &Editor::located);
4875 playhead_cursor->set_position (_session->audible_frame ());
4876 if (_follow_playhead && !_pending_initial_locate) {
4877 reset_x_origin_to_follow_playhead ();
4881 _pending_locate_request = false;
4882 _pending_initial_locate = false;
4886 Editor::region_view_added (RegionView *)
4888 _summary->set_background_dirty ();
4892 Editor::region_view_removed ()
4894 _summary->set_background_dirty ();
4898 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4900 TrackViewList::const_iterator j = track_views.begin ();
4901 while (j != track_views.end()) {
4902 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4903 if (rtv && rtv->route() == r) {
4914 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4918 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4919 TimeAxisView* tv = axis_view_from_route (*i);
4929 Editor::suspend_route_redisplay ()
4932 _routes->suspend_redisplay();
4937 Editor::resume_route_redisplay ()
4940 _routes->resume_redisplay();
4945 Editor::add_routes (RouteList& routes)
4947 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4949 RouteTimeAxisView *rtv;
4950 list<RouteTimeAxisView*> new_views;
4952 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4953 boost::shared_ptr<Route> route = (*x);
4955 if (route->is_auditioner() || route->is_monitor()) {
4959 DataType dt = route->input()->default_type();
4961 if (dt == ARDOUR::DataType::AUDIO) {
4962 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4963 rtv->set_route (route);
4964 } else if (dt == ARDOUR::DataType::MIDI) {
4965 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4966 rtv->set_route (route);
4968 throw unknown_type();
4971 new_views.push_back (rtv);
4972 track_views.push_back (rtv);
4974 rtv->effective_gain_display ();
4976 if (internal_editing()) {
4977 rtv->enter_internal_edit_mode ();
4979 rtv->leave_internal_edit_mode ();
4982 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4983 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4986 if (new_views.size() > 0) {
4987 _routes->routes_added (new_views);
4988 _summary->routes_added (new_views);
4991 if (show_editor_mixer_when_tracks_arrive) {
4992 show_editor_mixer (true);
4995 editor_list_button.set_sensitive (true);
4999 Editor::timeaxisview_deleted (TimeAxisView *tv)
5001 if (tv == entered_track) {
5005 if (_session && _session->deletion_in_progress()) {
5006 /* the situation is under control */
5010 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5012 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5014 _routes->route_removed (tv);
5016 TimeAxisView::Children c = tv->get_child_list ();
5017 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5018 if (entered_track == i->get()) {
5023 /* remove it from the list of track views */
5025 TrackViewList::iterator i;
5027 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5028 i = track_views.erase (i);
5031 /* update whatever the current mixer strip is displaying, if revelant */
5033 boost::shared_ptr<Route> route;
5036 route = rtav->route ();
5039 if (current_mixer_strip && current_mixer_strip->route() == route) {
5041 TimeAxisView* next_tv;
5043 if (track_views.empty()) {
5045 } else if (i == track_views.end()) {
5046 next_tv = track_views.front();
5053 set_selected_mixer_strip (*next_tv);
5055 /* make the editor mixer strip go away setting the
5056 * button to inactive (which also unticks the menu option)
5059 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5065 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5067 if (apply_to_selection) {
5068 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5070 TrackSelection::iterator j = i;
5073 hide_track_in_display (*i, false);
5078 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5080 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5081 // this will hide the mixer strip
5082 set_selected_mixer_strip (*tv);
5085 _routes->hide_track_in_display (*tv);
5090 Editor::sync_track_view_list_and_routes ()
5092 track_views = TrackViewList (_routes->views ());
5094 _summary->set_dirty ();
5095 _group_tabs->set_dirty ();
5097 return false; // do not call again (until needed)
5101 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5103 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5108 /** Find a RouteTimeAxisView by the ID of its route */
5110 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5112 RouteTimeAxisView* v;
5114 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5115 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5116 if(v->route()->id() == id) {
5126 Editor::fit_route_group (RouteGroup *g)
5128 TrackViewList ts = axis_views_from_routes (g->route_list ());
5133 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5135 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5138 _session->cancel_audition ();
5142 if (_session->is_auditioning()) {
5143 _session->cancel_audition ();
5144 if (r == last_audition_region) {
5149 _session->audition_region (r);
5150 last_audition_region = r;
5155 Editor::hide_a_region (boost::shared_ptr<Region> r)
5157 r->set_hidden (true);
5161 Editor::show_a_region (boost::shared_ptr<Region> r)
5163 r->set_hidden (false);
5167 Editor::audition_region_from_region_list ()
5169 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5173 Editor::hide_region_from_region_list ()
5175 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5179 Editor::show_region_in_region_list ()
5181 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5185 Editor::step_edit_status_change (bool yn)
5188 start_step_editing ();
5190 stop_step_editing ();
5195 Editor::start_step_editing ()
5197 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5201 Editor::stop_step_editing ()
5203 step_edit_connection.disconnect ();
5207 Editor::check_step_edit ()
5209 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5210 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5212 mtv->check_step_edit ();
5216 return true; // do it again, till we stop
5220 Editor::scroll_press (Direction dir)
5222 ++_scroll_callbacks;
5224 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5225 /* delay the first auto-repeat */
5231 scroll_backward (1);
5239 scroll_up_one_track ();
5243 scroll_down_one_track ();
5247 /* do hacky auto-repeat */
5248 if (!_scroll_connection.connected ()) {
5250 _scroll_connection = Glib::signal_timeout().connect (
5251 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5254 _scroll_callbacks = 0;
5261 Editor::scroll_release ()
5263 _scroll_connection.disconnect ();
5266 /** Queue a change for the Editor viewport x origin to follow the playhead */
5268 Editor::reset_x_origin_to_follow_playhead ()
5270 framepos_t const frame = playhead_cursor->current_frame ();
5272 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5274 if (_session->transport_speed() < 0) {
5276 if (frame > (current_page_samples() / 2)) {
5277 center_screen (frame-(current_page_samples()/2));
5279 center_screen (current_page_samples()/2);
5286 if (frame < leftmost_frame) {
5288 if (_session->transport_rolling()) {
5289 /* rolling; end up with the playhead at the right of the page */
5290 l = frame - current_page_samples ();
5292 /* not rolling: end up with the playhead 1/4 of the way along the page */
5293 l = frame - current_page_samples() / 4;
5297 if (_session->transport_rolling()) {
5298 /* rolling: end up with the playhead on the left of the page */
5301 /* not rolling: end up with the playhead 3/4 of the way along the page */
5302 l = frame - 3 * current_page_samples() / 4;
5310 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5316 Editor::super_rapid_screen_update ()
5318 if (!_session || !_session->engine().running()) {
5322 /* METERING / MIXER STRIPS */
5324 /* update track meters, if required */
5325 if (is_mapped() && meters_running) {
5326 RouteTimeAxisView* rtv;
5327 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5328 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5329 rtv->fast_update ();
5334 /* and any current mixer strip */
5335 if (current_mixer_strip) {
5336 current_mixer_strip->fast_update ();
5339 /* PLAYHEAD AND VIEWPORT */
5341 framepos_t const frame = _session->audible_frame();
5343 /* There are a few reasons why we might not update the playhead / viewport stuff:
5345 * 1. we don't update things when there's a pending locate request, otherwise
5346 * when the editor requests a locate there is a chance that this method
5347 * will move the playhead before the locate request is processed, causing
5349 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5350 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5353 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5355 last_update_frame = frame;
5357 if (!_dragging_playhead) {
5358 playhead_cursor->set_position (frame);
5361 if (!_stationary_playhead) {
5363 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5364 /* We only do this if we aren't already
5365 handling a visual change (ie if
5366 pending_visual_change.being_handled is
5367 false) so that these requests don't stack
5368 up there are too many of them to handle in
5371 reset_x_origin_to_follow_playhead ();
5376 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5380 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5381 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5382 if (target <= 0.0) {
5385 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5386 target = (target * 0.15) + (current * 0.85);
5392 set_horizontal_position (current);
5401 Editor::session_going_away ()
5403 _have_idled = false;
5405 _session_connections.drop_connections ();
5407 super_rapid_screen_update_connection.disconnect ();
5409 selection->clear ();
5410 cut_buffer->clear ();
5412 clicked_regionview = 0;
5413 clicked_axisview = 0;
5414 clicked_routeview = 0;
5415 entered_regionview = 0;
5417 last_update_frame = 0;
5420 playhead_cursor->hide ();
5422 /* rip everything out of the list displays */
5426 _route_groups->clear ();
5428 /* do this first so that deleting a track doesn't reset cms to null
5429 and thus cause a leak.
5432 if (current_mixer_strip) {
5433 if (current_mixer_strip->get_parent() != 0) {
5434 global_hpacker.remove (*current_mixer_strip);
5436 delete current_mixer_strip;
5437 current_mixer_strip = 0;
5440 /* delete all trackviews */
5442 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5445 track_views.clear ();
5447 nudge_clock->set_session (0);
5449 editor_list_button.set_active(false);
5450 editor_list_button.set_sensitive(false);
5452 /* clear tempo/meter rulers */
5453 remove_metric_marks ();
5455 clear_marker_display ();
5457 stop_step_editing ();
5459 /* get rid of any existing editor mixer strip */
5461 WindowTitle title(Glib::get_application_name());
5462 title += _("Editor");
5464 set_title (title.get_string());
5466 SessionHandlePtr::session_going_away ();
5471 Editor::show_editor_list (bool yn)
5474 _the_notebook.show ();
5476 _the_notebook.hide ();
5481 Editor::change_region_layering_order (bool from_context_menu)
5483 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5485 if (!clicked_routeview) {
5486 if (layering_order_editor) {
5487 layering_order_editor->hide ();
5492 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5498 boost::shared_ptr<Playlist> pl = track->playlist();
5504 if (layering_order_editor == 0) {
5505 layering_order_editor = new RegionLayeringOrderEditor (*this);
5508 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5509 layering_order_editor->maybe_present ();
5513 Editor::update_region_layering_order_editor ()
5515 if (layering_order_editor && layering_order_editor->is_visible ()) {
5516 change_region_layering_order (true);
5521 Editor::setup_fade_images ()
5523 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5524 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5525 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5526 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5527 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5529 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5530 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5531 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5532 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5533 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5535 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5536 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5537 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5538 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5539 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5541 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5542 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5543 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5544 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5545 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5549 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5551 Editor::action_menu_item (std::string const & name)
5553 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5556 return *manage (a->create_menu_item ());
5560 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5562 EventBox* b = manage (new EventBox);
5563 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5564 Label* l = manage (new Label (name));
5568 _the_notebook.append_page (widget, *b);
5572 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5574 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5575 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5578 if (ev->type == GDK_2BUTTON_PRESS) {
5580 /* double-click on a notebook tab shrinks or expands the notebook */
5582 if (_notebook_shrunk) {
5583 if (pre_notebook_shrink_pane_width) {
5584 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5586 _notebook_shrunk = false;
5588 pre_notebook_shrink_pane_width = edit_pane.get_position();
5590 /* this expands the LHS of the edit pane to cover the notebook
5591 PAGE but leaves the tabs visible.
5593 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5594 _notebook_shrunk = true;
5602 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5604 using namespace Menu_Helpers;
5606 MenuList& items = _control_point_context_menu.items ();
5609 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5610 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5611 if (!can_remove_control_point (item)) {
5612 items.back().set_sensitive (false);
5615 _control_point_context_menu.popup (event->button.button, event->button.time);
5619 Editor::zoom_vertical_modifier_released()
5621 _stepping_axis_view = 0;
5625 Editor::ui_parameter_changed (string parameter)
5627 if (parameter == "icon-set") {
5628 while (!_cursor_stack.empty()) {
5629 _cursor_stack.pop();
5631 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5632 } else if (parameter == "draggable-playhead") {
5633 if (_verbose_cursor) {
5634 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());