2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
124 #include "verbose_cursor.h"
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_edit_mode_strings[] = {
199 static const gchar *_zoom_focus_strings[] = {
209 #ifdef USE_RUBBERBAND
210 static const gchar *_rb_opt_strings[] = {
213 N_("Balanced multitimbral mixture"),
214 N_("Unpitched percussion with stable notes"),
215 N_("Crisp monophonic instrumental"),
216 N_("Unpitched solo percussion"),
217 N_("Resample without preserving pitch"),
222 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
225 pane_size_watcher (Paned* pane)
227 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
231 Quartz: impossible to access
233 so stop that by preventing it from ever getting too narrow. 35
234 pixels is basically a rough guess at the tab width.
239 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
241 gint pos = pane->get_position ();
243 if (pos > max_width_of_lhs) {
244 pane->set_position (max_width_of_lhs);
249 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
251 /* time display buttons */
252 , minsec_label (_("Mins:Secs"))
253 , bbt_label (_("Bars:Beats"))
254 , timecode_label (_("Timecode"))
255 , samples_label (_("Samples"))
256 , tempo_label (_("Tempo"))
257 , meter_label (_("Meter"))
258 , mark_label (_("Location Markers"))
259 , range_mark_label (_("Range Markers"))
260 , transport_mark_label (_("Loop/Punch Ranges"))
261 , cd_mark_label (_("CD Markers"))
262 , videotl_label (_("Video Timeline"))
263 , edit_packer (4, 4, true)
265 /* the values here don't matter: layout widgets
266 reset them as needed.
269 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
270 , horizontal_adjustment (0.0, 0.0, 1e16)
271 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
273 , controls_layout (unused_adjustment, vertical_adjustment)
275 /* tool bar related */
277 , toolbar_selection_clock_table (2,3)
278 , _mouse_mode_tearoff (0)
279 , automation_mode_button (_("mode"))
283 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
288 , meters_running(false)
289 , _pending_locate_request (false)
290 , _pending_initial_locate (false)
291 , _last_cut_copy_source_track (0)
293 , _region_selection_change_updates_region_list (true)
294 , _following_mixer_selection (false)
295 , _control_point_toggled_on_press (false)
296 , _stepping_axis_view (0)
300 /* we are a singleton */
302 PublicEditor::_instance = this;
306 selection = new Selection (this);
307 cut_buffer = new Selection (this);
309 clicked_regionview = 0;
310 clicked_axisview = 0;
311 clicked_routeview = 0;
312 clicked_control_point = 0;
313 last_update_frame = 0;
314 pre_press_cursor = 0;
315 _drags = new DragManager (this);
318 current_mixer_strip = 0;
321 snap_type_strings = I18N (_snap_type_strings);
322 snap_mode_strings = I18N (_snap_mode_strings);
323 zoom_focus_strings = I18N (_zoom_focus_strings);
324 edit_mode_strings = I18N (_edit_mode_strings);
325 edit_point_strings = I18N (_edit_point_strings);
326 #ifdef USE_RUBBERBAND
327 rb_opt_strings = I18N (_rb_opt_strings);
331 build_edit_mode_menu();
332 build_zoom_focus_menu();
333 build_track_count_menu();
334 build_snap_mode_menu();
335 build_snap_type_menu();
336 build_edit_point_menu();
338 snap_threshold = 5.0;
339 bbt_beat_subdivision = 4;
340 _visible_canvas_width = 0;
341 _visible_canvas_height = 0;
342 autoscroll_horizontal_allowed = false;
343 autoscroll_vertical_allowed = false;
348 current_interthread_info = 0;
349 _show_measures = true;
351 show_gain_after_trim = false;
353 have_pending_keyboard_selection = false;
354 _follow_playhead = true;
355 _stationary_playhead = false;
356 editor_ruler_menu = 0;
357 no_ruler_shown_update = false;
359 range_marker_menu = 0;
360 marker_menu_item = 0;
361 tempo_or_meter_marker_menu = 0;
362 transport_marker_menu = 0;
363 new_transport_marker_menu = 0;
364 editor_mixer_strip_width = Wide;
365 show_editor_mixer_when_tracks_arrive = false;
366 region_edit_menu_split_multichannel_item = 0;
367 region_edit_menu_split_item = 0;
370 current_stepping_trackview = 0;
372 entered_regionview = 0;
374 clear_entered_track = false;
377 button_release_can_deselect = true;
378 _dragging_playhead = false;
379 _dragging_edit_point = false;
380 select_new_marker = false;
382 layering_order_editor = 0;
383 no_save_visual = false;
385 within_track_canvas = false;
387 scrubbing_direction = 0;
391 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
392 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
393 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
394 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
395 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
397 zoom_focus = ZoomFocusLeft;
398 _edit_point = EditAtMouse;
399 _internal_editing = false;
400 current_canvas_cursor = 0;
401 _visible_track_count = 16;
403 samples_per_pixel = 2048; /* too early to use reset_zoom () */
405 _scroll_callbacks = 0;
407 bbt_label.set_name ("EditorRulerLabel");
408 bbt_label.set_size_request (-1, (int)timebar_height);
409 bbt_label.set_alignment (1.0, 0.5);
410 bbt_label.set_padding (5,0);
412 bbt_label.set_no_show_all();
413 minsec_label.set_name ("EditorRulerLabel");
414 minsec_label.set_size_request (-1, (int)timebar_height);
415 minsec_label.set_alignment (1.0, 0.5);
416 minsec_label.set_padding (5,0);
417 minsec_label.hide ();
418 minsec_label.set_no_show_all();
419 timecode_label.set_name ("EditorRulerLabel");
420 timecode_label.set_size_request (-1, (int)timebar_height);
421 timecode_label.set_alignment (1.0, 0.5);
422 timecode_label.set_padding (5,0);
423 timecode_label.hide ();
424 timecode_label.set_no_show_all();
425 samples_label.set_name ("EditorRulerLabel");
426 samples_label.set_size_request (-1, (int)timebar_height);
427 samples_label.set_alignment (1.0, 0.5);
428 samples_label.set_padding (5,0);
429 samples_label.hide ();
430 samples_label.set_no_show_all();
432 tempo_label.set_name ("EditorRulerLabel");
433 tempo_label.set_size_request (-1, (int)timebar_height);
434 tempo_label.set_alignment (1.0, 0.5);
435 tempo_label.set_padding (5,0);
437 tempo_label.set_no_show_all();
439 meter_label.set_name ("EditorRulerLabel");
440 meter_label.set_size_request (-1, (int)timebar_height);
441 meter_label.set_alignment (1.0, 0.5);
442 meter_label.set_padding (5,0);
444 meter_label.set_no_show_all();
446 if (Profile->get_trx()) {
447 mark_label.set_text (_("Markers"));
449 mark_label.set_name ("EditorRulerLabel");
450 mark_label.set_size_request (-1, (int)timebar_height);
451 mark_label.set_alignment (1.0, 0.5);
452 mark_label.set_padding (5,0);
454 mark_label.set_no_show_all();
456 cd_mark_label.set_name ("EditorRulerLabel");
457 cd_mark_label.set_size_request (-1, (int)timebar_height);
458 cd_mark_label.set_alignment (1.0, 0.5);
459 cd_mark_label.set_padding (5,0);
460 cd_mark_label.hide();
461 cd_mark_label.set_no_show_all();
463 videotl_bar_height = 4;
464 videotl_label.set_name ("EditorRulerLabel");
465 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
466 videotl_label.set_alignment (1.0, 0.5);
467 videotl_label.set_padding (5,0);
468 videotl_label.hide();
469 videotl_label.set_no_show_all();
471 range_mark_label.set_name ("EditorRulerLabel");
472 range_mark_label.set_size_request (-1, (int)timebar_height);
473 range_mark_label.set_alignment (1.0, 0.5);
474 range_mark_label.set_padding (5,0);
475 range_mark_label.hide();
476 range_mark_label.set_no_show_all();
478 transport_mark_label.set_name ("EditorRulerLabel");
479 transport_mark_label.set_size_request (-1, (int)timebar_height);
480 transport_mark_label.set_alignment (1.0, 0.5);
481 transport_mark_label.set_padding (5,0);
482 transport_mark_label.hide();
483 transport_mark_label.set_no_show_all();
485 initialize_canvas ();
487 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
489 _summary = new EditorSummary (this);
491 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
492 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
494 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
496 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
497 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
499 edit_controls_vbox.set_spacing (0);
500 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
501 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
503 HBox* h = manage (new HBox);
504 _group_tabs = new EditorGroupTabs (this);
505 if (!ARDOUR::Profile->get_trx()) {
506 h->pack_start (*_group_tabs, PACK_SHRINK);
508 h->pack_start (edit_controls_vbox);
509 controls_layout.add (*h);
511 controls_layout.set_name ("EditControlsBase");
512 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
513 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
514 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
516 _cursors = new MouseCursors;
517 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
518 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
520 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
522 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
523 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
524 pad_line_1->set_outline_color (0xFF0000FF);
530 edit_packer.set_col_spacings (0);
531 edit_packer.set_row_spacings (0);
532 edit_packer.set_homogeneous (false);
533 edit_packer.set_border_width (0);
534 edit_packer.set_name ("EditorWindow");
536 time_bars_event_box.add (time_bars_vbox);
537 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
538 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
540 /* labels for the time bars */
541 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
543 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
545 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
547 bottom_hbox.set_border_width (2);
548 bottom_hbox.set_spacing (3);
550 _route_groups = new EditorRouteGroups (this);
551 _routes = new EditorRoutes (this);
552 _regions = new EditorRegions (this);
553 _snapshots = new EditorSnapshots (this);
554 _locations = new EditorLocations (this);
556 add_notebook_page (_("Regions"), _regions->widget ());
557 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
558 add_notebook_page (_("Snapshots"), _snapshots->widget ());
559 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
560 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
562 _the_notebook.set_show_tabs (true);
563 _the_notebook.set_scrollable (true);
564 _the_notebook.popup_disable ();
565 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
566 _the_notebook.show_all ();
568 _notebook_shrunk = false;
570 editor_summary_pane.pack1(edit_packer);
572 Button* summary_arrows_left_left = manage (new Button);
573 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
574 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
575 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 Button* summary_arrows_left_right = manage (new Button);
578 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
579 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
580 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 VBox* summary_arrows_left = manage (new VBox);
583 summary_arrows_left->pack_start (*summary_arrows_left_left);
584 summary_arrows_left->pack_start (*summary_arrows_left_right);
586 Button* summary_arrows_right_up = manage (new Button);
587 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
588 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
589 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591 Button* summary_arrows_right_down = manage (new Button);
592 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
593 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
594 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
596 VBox* summary_arrows_right = manage (new VBox);
597 summary_arrows_right->pack_start (*summary_arrows_right_up);
598 summary_arrows_right->pack_start (*summary_arrows_right_down);
600 Frame* summary_frame = manage (new Frame);
601 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
603 summary_frame->add (*_summary);
604 summary_frame->show ();
606 _summary_hbox.pack_start (*summary_arrows_left, false, false);
607 _summary_hbox.pack_start (*summary_frame, true, true);
608 _summary_hbox.pack_start (*summary_arrows_right, false, false);
610 if (!ARDOUR::Profile->get_trx()) {
611 editor_summary_pane.pack2 (_summary_hbox);
614 edit_pane.pack1 (editor_summary_pane, true, true);
615 if (!ARDOUR::Profile->get_trx()) {
616 edit_pane.pack2 (_the_notebook, false, true);
619 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
621 /* XXX: editor_summary_pane might need similar to the edit_pane */
623 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
625 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
626 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
628 top_hbox.pack_start (toolbar_frame);
630 HBox *hbox = manage (new HBox);
631 hbox->pack_start (edit_pane, true, true);
633 global_vpacker.pack_start (top_hbox, false, false);
634 global_vpacker.pack_start (*hbox, true, true);
636 global_hpacker.pack_start (global_vpacker, true, true);
638 set_name ("EditorWindow");
639 add_accel_group (ActionManager::ui_manager->get_accel_group());
641 status_bar_hpacker.show ();
643 vpacker.pack_end (status_bar_hpacker, false, false);
644 vpacker.pack_end (global_hpacker, true, true);
646 /* register actions now so that set_state() can find them and set toggles/checks etc */
649 /* when we start using our own keybinding system for the editor, this
650 * will be uncommented
656 set_zoom_focus (zoom_focus);
657 set_visible_track_count (_visible_track_count);
658 _snap_type = SnapToBeat;
659 set_snap_to (_snap_type);
660 _snap_mode = SnapOff;
661 set_snap_mode (_snap_mode);
662 set_mouse_mode (MouseObject, true);
663 pre_internal_mouse_mode = MouseObject;
664 pre_internal_snap_type = _snap_type;
665 pre_internal_snap_mode = _snap_mode;
666 internal_snap_type = _snap_type;
667 internal_snap_mode = _snap_mode;
668 set_edit_point_preference (EditAtMouse, true);
670 _playlist_selector = new PlaylistSelector();
671 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
673 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
677 nudge_forward_button.set_name ("nudge button");
678 nudge_forward_button.set_image(::get_icon("nudge_right"));
680 nudge_backward_button.set_name ("nudge button");
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;
795 Editor::button_settings () const
797 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
798 XMLNode* node = find_named_node (*settings, X_("Buttons"));
801 node = new XMLNode (X_("Buttons"));
808 Editor::add_toplevel_menu (Container& cont)
810 vpacker.pack_start (cont, false, false);
815 Editor::add_transport_frame (Container& cont)
817 if(ARDOUR::Profile->get_mixbus()) {
818 global_vpacker.pack_start (cont, false, false);
819 global_vpacker.reorder_child (cont, 0);
822 vpacker.pack_start (cont, false, false);
827 Editor::get_smart_mode () const
829 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
833 Editor::catch_vanishing_regionview (RegionView *rv)
835 /* note: the selection will take care of the vanishing
836 audioregionview by itself.
839 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
843 if (clicked_regionview == rv) {
844 clicked_regionview = 0;
847 if (entered_regionview == rv) {
848 set_entered_regionview (0);
851 if (!_all_region_actions_sensitized) {
852 sensitize_all_region_actions (true);
857 Editor::set_entered_regionview (RegionView* rv)
859 if (rv == entered_regionview) {
863 if (entered_regionview) {
864 entered_regionview->exited ();
867 entered_regionview = rv;
869 if (entered_regionview != 0) {
870 entered_regionview->entered (internal_editing ());
873 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
874 /* This RegionView entry might have changed what region actions
875 are allowed, so sensitize them all in case a key is pressed.
877 sensitize_all_region_actions (true);
882 Editor::set_entered_track (TimeAxisView* tav)
885 entered_track->exited ();
891 entered_track->entered ();
896 Editor::show_window ()
898 if (!is_visible ()) {
902 /* XXX: this is a bit unfortunate; it would probably
903 be nicer if we could just call show () above rather
904 than needing the show_all ()
907 /* re-hide stuff if necessary */
908 editor_list_button_toggled ();
909 parameter_changed ("show-summary");
910 parameter_changed ("show-group-tabs");
911 parameter_changed ("show-zoom-tools");
913 /* now reset all audio_time_axis heights, because widgets might need
919 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
920 tv = (static_cast<TimeAxisView*>(*i));
924 if (current_mixer_strip) {
925 current_mixer_strip->hide_things ();
926 current_mixer_strip->parameter_changed ("mixer-element-visibility");
934 Editor::instant_save ()
936 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
941 _session->add_instant_xml(get_state());
943 Config->add_instant_xml(get_state());
948 Editor::control_vertical_zoom_in_all ()
950 tav_zoom_smooth (false, true);
954 Editor::control_vertical_zoom_out_all ()
956 tav_zoom_smooth (true, true);
960 Editor::control_vertical_zoom_in_selected ()
962 tav_zoom_smooth (false, false);
966 Editor::control_vertical_zoom_out_selected ()
968 tav_zoom_smooth (true, false);
972 Editor::control_view (uint32_t view)
974 goto_visual_state (view);
978 Editor::control_unselect ()
980 selection->clear_tracks ();
984 Editor::control_select (uint32_t rid, Selection::Operation op)
986 /* handles the (static) signal from the ControlProtocol class that
987 * requests setting the selected track to a given RID
994 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1000 TimeAxisView* tav = axis_view_from_route (r);
1004 case Selection::Add:
1005 selection->add (tav);
1007 case Selection::Toggle:
1008 selection->toggle (tav);
1010 case Selection::Extend:
1012 case Selection::Set:
1013 selection->set (tav);
1017 selection->clear_tracks ();
1022 Editor::control_step_tracks_up ()
1024 scroll_tracks_up_line ();
1028 Editor::control_step_tracks_down ()
1030 scroll_tracks_down_line ();
1034 Editor::control_scroll (float fraction)
1036 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1042 double step = fraction * current_page_samples();
1045 _control_scroll_target is an optional<T>
1047 it acts like a pointer to an framepos_t, with
1048 a operator conversion to boolean to check
1049 that it has a value could possibly use
1050 playhead_cursor->current_frame to store the
1051 value and a boolean in the class to know
1052 when it's out of date
1055 if (!_control_scroll_target) {
1056 _control_scroll_target = _session->transport_frame();
1057 _dragging_playhead = true;
1060 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1061 *_control_scroll_target = 0;
1062 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1063 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1065 *_control_scroll_target += (framepos_t) floor (step);
1068 /* move visuals, we'll catch up with it later */
1070 playhead_cursor->set_position (*_control_scroll_target);
1071 UpdateAllTransportClocks (*_control_scroll_target);
1073 if (*_control_scroll_target > (current_page_samples() / 2)) {
1074 /* try to center PH in window */
1075 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1081 Now we do a timeout to actually bring the session to the right place
1082 according to the playhead. This is to avoid reading disk buffers on every
1083 call to control_scroll, which is driven by ScrollTimeline and therefore
1084 probably by a control surface wheel which can generate lots of events.
1086 /* cancel the existing timeout */
1088 control_scroll_connection.disconnect ();
1090 /* add the next timeout */
1092 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1096 Editor::deferred_control_scroll (framepos_t /*target*/)
1098 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1099 // reset for next stream
1100 _control_scroll_target = boost::none;
1101 _dragging_playhead = false;
1106 Editor::access_action (std::string action_group, std::string action_item)
1112 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1115 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1123 Editor::on_realize ()
1125 Window::on_realize ();
1128 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1129 start_lock_event_timing ();
1132 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1136 Editor::start_lock_event_timing ()
1138 /* check if we should lock the GUI every 30 seconds */
1140 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1144 Editor::generic_event_handler (GdkEvent* ev)
1147 case GDK_BUTTON_PRESS:
1148 case GDK_BUTTON_RELEASE:
1149 case GDK_MOTION_NOTIFY:
1151 case GDK_KEY_RELEASE:
1152 gettimeofday (&last_event_time, 0);
1155 case GDK_LEAVE_NOTIFY:
1156 switch (ev->crossing.detail) {
1157 case GDK_NOTIFY_UNKNOWN:
1158 case GDK_NOTIFY_INFERIOR:
1159 case GDK_NOTIFY_ANCESTOR:
1161 case GDK_NOTIFY_VIRTUAL:
1162 case GDK_NOTIFY_NONLINEAR:
1163 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1164 /* leaving window, so reset focus, thus ending any and
1165 all text entry operations.
1180 Editor::lock_timeout_callback ()
1182 struct timeval now, delta;
1184 gettimeofday (&now, 0);
1186 timersub (&now, &last_event_time, &delta);
1188 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1190 /* don't call again. Returning false will effectively
1191 disconnect us from the timer callback.
1193 unlock() will call start_lock_event_timing() to get things
1203 Editor::map_position_change (framepos_t frame)
1205 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1207 if (_session == 0) {
1211 if (_follow_playhead) {
1212 center_screen (frame);
1215 playhead_cursor->set_position (frame);
1219 Editor::center_screen (framepos_t frame)
1221 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1223 /* if we're off the page, then scroll.
1226 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1227 center_screen_internal (frame, page);
1232 Editor::center_screen_internal (framepos_t frame, float page)
1237 frame -= (framepos_t) page;
1242 reset_x_origin (frame);
1247 Editor::update_title ()
1249 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1252 bool dirty = _session->dirty();
1254 string session_name;
1256 if (_session->snap_name() != _session->name()) {
1257 session_name = _session->snap_name();
1259 session_name = _session->name();
1263 session_name = "*" + session_name;
1266 WindowTitle title(session_name);
1267 title += Glib::get_application_name();
1268 set_title (title.get_string());
1270 /* ::session_going_away() will have taken care of it */
1275 Editor::set_session (Session *t)
1277 SessionHandlePtr::set_session (t);
1283 _playlist_selector->set_session (_session);
1284 nudge_clock->set_session (_session);
1285 _summary->set_session (_session);
1286 _group_tabs->set_session (_session);
1287 _route_groups->set_session (_session);
1288 _regions->set_session (_session);
1289 _snapshots->set_session (_session);
1290 _routes->set_session (_session);
1291 _locations->set_session (_session);
1293 if (rhythm_ferret) {
1294 rhythm_ferret->set_session (_session);
1297 if (analysis_window) {
1298 analysis_window->set_session (_session);
1302 sfbrowser->set_session (_session);
1305 compute_fixed_ruler_scale ();
1307 /* Make sure we have auto loop and auto punch ranges */
1309 Location* loc = _session->locations()->auto_loop_location();
1311 loc->set_name (_("Loop"));
1314 loc = _session->locations()->auto_punch_location();
1317 loc->set_name (_("Punch"));
1320 refresh_location_display ();
1322 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1323 the selected Marker; this needs the LocationMarker list to be available.
1325 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1326 set_state (*node, Stateful::loading_state_version);
1328 /* catch up with the playhead */
1330 _session->request_locate (playhead_cursor->current_frame ());
1331 _pending_initial_locate = true;
1335 /* These signals can all be emitted by a non-GUI thread. Therefore the
1336 handlers for them must not attempt to directly interact with the GUI,
1337 but use PBD::Signal<T>::connect() which accepts an event loop
1338 ("context") where the handler will be asked to run.
1341 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1342 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1343 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1344 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1345 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1346 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1347 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1348 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1349 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1350 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1351 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1352 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1353 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1354 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1356 playhead_cursor->show ();
1358 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1359 Config->map_parameters (pc);
1360 _session->config.map_parameters (pc);
1362 restore_ruler_visibility ();
1363 //tempo_map_changed (PropertyChange (0));
1364 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1366 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1367 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1370 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1371 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1374 switch (_snap_type) {
1375 case SnapToRegionStart:
1376 case SnapToRegionEnd:
1377 case SnapToRegionSync:
1378 case SnapToRegionBoundary:
1379 build_region_boundary_cache ();
1386 /* register for undo history */
1387 _session->register_with_memento_command_factory(id(), this);
1389 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1391 start_updating_meters ();
1395 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1397 if (a->get_name() == "RegionMenu") {
1398 /* When the main menu's region menu is opened, we setup the actions so that they look right
1399 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1400 so we resensitize all region actions when the entered regionview or the region selection
1401 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1402 happens after the region context menu is opened. So we set a flag here, too.
1406 sensitize_the_right_region_actions ();
1407 _last_region_menu_was_main = true;
1412 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1414 using namespace Menu_Helpers;
1416 void (Editor::*emf)(FadeShape);
1417 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1420 images = &_xfade_in_images;
1421 emf = &Editor::set_fade_in_shape;
1423 images = &_xfade_out_images;
1424 emf = &Editor::set_fade_out_shape;
1429 _("Linear (for highly correlated material)"),
1430 *(*images)[FadeLinear],
1431 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1435 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1439 _("Constant power"),
1440 *(*images)[FadeConstantPower],
1441 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1444 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1449 *(*images)[FadeSymmetric],
1450 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1454 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 *(*images)[FadeSlow],
1460 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1463 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1468 *(*images)[FadeFast],
1469 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 /** Pop up a context menu for when the user clicks on a start crossfade */
1477 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1479 using namespace Menu_Helpers;
1480 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1483 MenuList& items (xfade_in_context_menu.items());
1486 if (arv->audio_region()->fade_in_active()) {
1487 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1489 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1492 items.push_back (SeparatorElem());
1493 fill_xfade_menu (items, true);
1495 xfade_in_context_menu.popup (button, time);
1498 /** Pop up a context menu for when the user clicks on an end crossfade */
1500 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1502 using namespace Menu_Helpers;
1503 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1506 MenuList& items (xfade_out_context_menu.items());
1509 if (arv->audio_region()->fade_out_active()) {
1510 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1512 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1515 items.push_back (SeparatorElem());
1516 fill_xfade_menu (items, false);
1518 xfade_out_context_menu.popup (button, time);
1522 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1524 using namespace Menu_Helpers;
1525 Menu* (Editor::*build_menu_function)();
1528 switch (item_type) {
1530 case RegionViewName:
1531 case RegionViewNameHighlight:
1532 case LeftFrameHandle:
1533 case RightFrameHandle:
1534 if (with_selection) {
1535 build_menu_function = &Editor::build_track_selection_context_menu;
1537 build_menu_function = &Editor::build_track_region_context_menu;
1542 if (with_selection) {
1543 build_menu_function = &Editor::build_track_selection_context_menu;
1545 build_menu_function = &Editor::build_track_context_menu;
1550 if (clicked_routeview->track()) {
1551 build_menu_function = &Editor::build_track_context_menu;
1553 build_menu_function = &Editor::build_track_bus_context_menu;
1558 /* probably shouldn't happen but if it does, we don't care */
1562 menu = (this->*build_menu_function)();
1563 menu->set_name ("ArdourContextMenu");
1565 /* now handle specific situations */
1567 switch (item_type) {
1569 case RegionViewName:
1570 case RegionViewNameHighlight:
1571 case LeftFrameHandle:
1572 case RightFrameHandle:
1573 if (!with_selection) {
1574 if (region_edit_menu_split_item) {
1575 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1576 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1578 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1581 if (region_edit_menu_split_multichannel_item) {
1582 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1583 region_edit_menu_split_multichannel_item->set_sensitive (true);
1585 region_edit_menu_split_multichannel_item->set_sensitive (false);
1598 /* probably shouldn't happen but if it does, we don't care */
1602 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1604 /* Bounce to disk */
1606 using namespace Menu_Helpers;
1607 MenuList& edit_items = menu->items();
1609 edit_items.push_back (SeparatorElem());
1611 switch (clicked_routeview->audio_track()->freeze_state()) {
1612 case AudioTrack::NoFreeze:
1613 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1616 case AudioTrack::Frozen:
1617 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1620 case AudioTrack::UnFrozen:
1621 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1627 if (item_type == StreamItem && clicked_routeview) {
1628 clicked_routeview->build_underlay_menu(menu);
1631 /* When the region menu is opened, we setup the actions so that they look right
1634 sensitize_the_right_region_actions ();
1635 _last_region_menu_was_main = false;
1637 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1638 menu->popup (button, time);
1642 Editor::build_track_context_menu ()
1644 using namespace Menu_Helpers;
1646 MenuList& edit_items = track_context_menu.items();
1649 add_dstream_context_items (edit_items);
1650 return &track_context_menu;
1654 Editor::build_track_bus_context_menu ()
1656 using namespace Menu_Helpers;
1658 MenuList& edit_items = track_context_menu.items();
1661 add_bus_context_items (edit_items);
1662 return &track_context_menu;
1666 Editor::build_track_region_context_menu ()
1668 using namespace Menu_Helpers;
1669 MenuList& edit_items = track_region_context_menu.items();
1672 /* we've just cleared the track region context menu, so the menu that these
1673 two items were on will have disappeared; stop them dangling.
1675 region_edit_menu_split_item = 0;
1676 region_edit_menu_split_multichannel_item = 0;
1678 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1681 boost::shared_ptr<Track> tr;
1682 boost::shared_ptr<Playlist> pl;
1684 if ((tr = rtv->track())) {
1685 add_region_context_items (edit_items, tr);
1689 add_dstream_context_items (edit_items);
1691 return &track_region_context_menu;
1695 Editor::analyze_region_selection ()
1697 if (analysis_window == 0) {
1698 analysis_window = new AnalysisWindow();
1701 analysis_window->set_session(_session);
1703 analysis_window->show_all();
1706 analysis_window->set_regionmode();
1707 analysis_window->analyze();
1709 analysis_window->present();
1713 Editor::analyze_range_selection()
1715 if (analysis_window == 0) {
1716 analysis_window = new AnalysisWindow();
1719 analysis_window->set_session(_session);
1721 analysis_window->show_all();
1724 analysis_window->set_rangemode();
1725 analysis_window->analyze();
1727 analysis_window->present();
1731 Editor::build_track_selection_context_menu ()
1733 using namespace Menu_Helpers;
1734 MenuList& edit_items = track_selection_context_menu.items();
1735 edit_items.clear ();
1737 add_selection_context_items (edit_items);
1738 // edit_items.push_back (SeparatorElem());
1739 // add_dstream_context_items (edit_items);
1741 return &track_selection_context_menu;
1745 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1747 using namespace Menu_Helpers;
1749 /* OK, stick the region submenu at the top of the list, and then add
1753 RegionSelection rs = get_regions_from_selection_and_entered ();
1755 string::size_type pos = 0;
1756 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1758 /* we have to hack up the region name because "_" has a special
1759 meaning for menu titles.
1762 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1763 menu_item_name.replace (pos, 1, "__");
1767 if (_popup_region_menu_item == 0) {
1768 _popup_region_menu_item = new MenuItem (menu_item_name);
1769 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1770 _popup_region_menu_item->show ();
1772 _popup_region_menu_item->set_label (menu_item_name);
1775 const framepos_t position = get_preferred_edit_position (false, true);
1777 edit_items.push_back (*_popup_region_menu_item);
1778 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1779 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1781 edit_items.push_back (SeparatorElem());
1784 /** Add context menu items relevant to selection ranges.
1785 * @param edit_items List to add the items to.
1788 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1790 using namespace Menu_Helpers;
1792 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1793 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1795 edit_items.push_back (SeparatorElem());
1796 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1798 edit_items.push_back (SeparatorElem());
1799 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1801 edit_items.push_back (SeparatorElem());
1803 edit_items.push_back (
1805 _("Move Range Start to Previous Region Boundary"),
1806 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1810 edit_items.push_back (
1812 _("Move Range Start to Next Region Boundary"),
1813 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1817 edit_items.push_back (
1819 _("Move Range End to Previous Region Boundary"),
1820 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1824 edit_items.push_back (
1826 _("Move Range End to Next Region Boundary"),
1827 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1831 edit_items.push_back (SeparatorElem());
1832 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1833 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1835 edit_items.push_back (SeparatorElem());
1836 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1838 edit_items.push_back (SeparatorElem());
1839 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1840 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1842 edit_items.push_back (SeparatorElem());
1843 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1845 edit_items.push_back (SeparatorElem());
1846 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1847 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1848 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1850 edit_items.push_back (SeparatorElem());
1851 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1852 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1853 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1854 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1855 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1856 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1857 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1863 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1865 using namespace Menu_Helpers;
1869 Menu *play_menu = manage (new Menu);
1870 MenuList& play_items = play_menu->items();
1871 play_menu->set_name ("ArdourContextMenu");
1873 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1874 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1875 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1876 play_items.push_back (SeparatorElem());
1877 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1879 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1883 Menu *select_menu = manage (new Menu);
1884 MenuList& select_items = select_menu->items();
1885 select_menu->set_name ("ArdourContextMenu");
1887 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1888 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1889 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1890 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1891 select_items.push_back (SeparatorElem());
1892 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1893 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1894 select_items.push_back (SeparatorElem());
1895 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1896 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1897 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1898 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1899 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1900 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1901 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1903 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1907 Menu *cutnpaste_menu = manage (new Menu);
1908 MenuList& cutnpaste_items = cutnpaste_menu->items();
1909 cutnpaste_menu->set_name ("ArdourContextMenu");
1911 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1912 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1913 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1915 cutnpaste_items.push_back (SeparatorElem());
1917 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1918 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1920 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1922 /* Adding new material */
1924 edit_items.push_back (SeparatorElem());
1925 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1926 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1930 Menu *nudge_menu = manage (new Menu());
1931 MenuList& nudge_items = nudge_menu->items();
1932 nudge_menu->set_name ("ArdourContextMenu");
1934 edit_items.push_back (SeparatorElem());
1935 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1936 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1937 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1938 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1940 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1944 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1946 using namespace Menu_Helpers;
1950 Menu *play_menu = manage (new Menu);
1951 MenuList& play_items = play_menu->items();
1952 play_menu->set_name ("ArdourContextMenu");
1954 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1955 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1956 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1960 Menu *select_menu = manage (new Menu);
1961 MenuList& select_items = select_menu->items();
1962 select_menu->set_name ("ArdourContextMenu");
1964 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1965 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1966 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1967 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1968 select_items.push_back (SeparatorElem());
1969 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1970 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1971 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1972 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1974 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1978 Menu *cutnpaste_menu = manage (new Menu);
1979 MenuList& cutnpaste_items = cutnpaste_menu->items();
1980 cutnpaste_menu->set_name ("ArdourContextMenu");
1982 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1983 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1984 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1986 Menu *nudge_menu = manage (new Menu());
1987 MenuList& nudge_items = nudge_menu->items();
1988 nudge_menu->set_name ("ArdourContextMenu");
1990 edit_items.push_back (SeparatorElem());
1991 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1992 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1993 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1994 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1996 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2000 Editor::snap_type() const
2006 Editor::snap_mode() const
2012 Editor::set_snap_to (SnapType st)
2014 unsigned int snap_ind = (unsigned int)st;
2018 if (snap_ind > snap_type_strings.size() - 1) {
2020 _snap_type = (SnapType)snap_ind;
2023 string str = snap_type_strings[snap_ind];
2025 if (str != snap_type_selector.get_text()) {
2026 snap_type_selector.set_text (str);
2031 switch (_snap_type) {
2032 case SnapToBeatDiv128:
2033 case SnapToBeatDiv64:
2034 case SnapToBeatDiv32:
2035 case SnapToBeatDiv28:
2036 case SnapToBeatDiv24:
2037 case SnapToBeatDiv20:
2038 case SnapToBeatDiv16:
2039 case SnapToBeatDiv14:
2040 case SnapToBeatDiv12:
2041 case SnapToBeatDiv10:
2042 case SnapToBeatDiv8:
2043 case SnapToBeatDiv7:
2044 case SnapToBeatDiv6:
2045 case SnapToBeatDiv5:
2046 case SnapToBeatDiv4:
2047 case SnapToBeatDiv3:
2048 case SnapToBeatDiv2: {
2049 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2050 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2052 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2053 current_bbt_points_begin, current_bbt_points_end);
2054 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2055 current_bbt_points_begin, current_bbt_points_end);
2056 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2060 case SnapToRegionStart:
2061 case SnapToRegionEnd:
2062 case SnapToRegionSync:
2063 case SnapToRegionBoundary:
2064 build_region_boundary_cache ();
2072 SnapChanged (); /* EMIT SIGNAL */
2076 Editor::set_snap_mode (SnapMode mode)
2078 string str = snap_mode_strings[(int)mode];
2080 if (_internal_editing) {
2081 internal_snap_mode = mode;
2083 pre_internal_snap_mode = mode;
2088 if (str != snap_mode_selector.get_text ()) {
2089 snap_mode_selector.set_text (str);
2095 Editor::set_edit_point_preference (EditPoint ep, bool force)
2097 bool changed = (_edit_point != ep);
2100 string str = edit_point_strings[(int)ep];
2102 if (Profile->get_mixbus())
2103 if (ep == EditAtSelectedMarker)
2104 ep = EditAtPlayhead;
2106 if (str != edit_point_selector.get_text ()) {
2107 edit_point_selector.set_text (str);
2110 reset_canvas_cursor ();
2112 if (!force && !changed) {
2116 const char* action=NULL;
2118 switch (_edit_point) {
2119 case EditAtPlayhead:
2120 action = "edit-at-playhead";
2122 case EditAtSelectedMarker:
2123 action = "edit-at-marker";
2126 action = "edit-at-mouse";
2130 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2132 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2136 bool in_track_canvas;
2138 if (!mouse_frame (foo, in_track_canvas)) {
2139 in_track_canvas = false;
2142 reset_canvas_action_sensitivity (in_track_canvas);
2148 Editor::set_state (const XMLNode& node, int /*version*/)
2150 const XMLProperty* prop;
2157 g.base_width = default_width;
2158 g.base_height = default_height;
2162 if ((geometry = find_named_node (node, "geometry")) != 0) {
2166 if ((prop = geometry->property("x_size")) == 0) {
2167 prop = geometry->property ("x-size");
2170 g.base_width = atoi(prop->value());
2172 if ((prop = geometry->property("y_size")) == 0) {
2173 prop = geometry->property ("y-size");
2176 g.base_height = atoi(prop->value());
2179 if ((prop = geometry->property ("x_pos")) == 0) {
2180 prop = geometry->property ("x-pos");
2183 x = atoi (prop->value());
2186 if ((prop = geometry->property ("y_pos")) == 0) {
2187 prop = geometry->property ("y-pos");
2190 y = atoi (prop->value());
2194 set_default_size (g.base_width, g.base_height);
2197 if (_session && (prop = node.property ("playhead"))) {
2199 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2200 playhead_cursor->set_position (pos);
2202 playhead_cursor->set_position (0);
2205 if ((prop = node.property ("mixer-width"))) {
2206 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2209 if ((prop = node.property ("zoom-focus"))) {
2210 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2213 if ((prop = node.property ("zoom"))) {
2214 /* older versions of ardour used floating point samples_per_pixel */
2215 double f = PBD::atof (prop->value());
2216 reset_zoom (llrintf (f));
2218 reset_zoom (samples_per_pixel);
2221 if ((prop = node.property ("visible-track-count"))) {
2222 set_visible_track_count (PBD::atoi (prop->value()));
2225 if ((prop = node.property ("snap-to"))) {
2226 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2229 if ((prop = node.property ("snap-mode"))) {
2230 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2233 if ((prop = node.property ("internal-snap-to"))) {
2234 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2237 if ((prop = node.property ("internal-snap-mode"))) {
2238 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2241 if ((prop = node.property ("pre-internal-snap-to"))) {
2242 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2246 if ((prop = node.property ("pre-internal-snap-mode"))) {
2247 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2250 if ((prop = node.property ("mouse-mode"))) {
2251 MouseMode m = str2mousemode(prop->value());
2252 set_mouse_mode (m, true);
2254 set_mouse_mode (MouseObject, true);
2257 if ((prop = node.property ("left-frame")) != 0) {
2259 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2263 reset_x_origin (pos);
2267 if ((prop = node.property ("y-origin")) != 0) {
2268 reset_y_origin (atof (prop->value ()));
2271 if ((prop = node.property ("internal-edit"))) {
2272 bool yn = string_is_affirmative (prop->value());
2273 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2275 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2276 tact->set_active (!yn);
2277 tact->set_active (yn);
2281 if ((prop = node.property ("join-object-range"))) {
2282 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2283 bool yn = string_is_affirmative (prop->value());
2285 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2286 tact->set_active (!yn);
2287 tact->set_active (yn);
2289 set_mouse_mode(mouse_mode, true);
2292 if ((prop = node.property ("edit-point"))) {
2293 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2296 if ((prop = node.property ("show-measures"))) {
2297 bool yn = string_is_affirmative (prop->value());
2298 _show_measures = yn;
2299 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2301 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2302 /* do it twice to force the change */
2303 tact->set_active (!yn);
2304 tact->set_active (yn);
2308 if ((prop = node.property ("follow-playhead"))) {
2309 bool yn = string_is_affirmative (prop->value());
2310 set_follow_playhead (yn);
2311 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2313 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2314 if (tact->get_active() != yn) {
2315 tact->set_active (yn);
2320 if ((prop = node.property ("stationary-playhead"))) {
2321 bool yn = string_is_affirmative (prop->value());
2322 set_stationary_playhead (yn);
2323 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2325 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2326 if (tact->get_active() != yn) {
2327 tact->set_active (yn);
2332 if ((prop = node.property ("region-list-sort-type"))) {
2333 RegionListSortType st;
2334 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2337 if ((prop = node.property ("show-editor-mixer"))) {
2339 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2342 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2343 bool yn = string_is_affirmative (prop->value());
2345 /* do it twice to force the change */
2347 tact->set_active (!yn);
2348 tact->set_active (yn);
2351 if ((prop = node.property ("show-editor-list"))) {
2353 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2356 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2357 bool yn = string_is_affirmative (prop->value());
2359 /* do it twice to force the change */
2361 tact->set_active (!yn);
2362 tact->set_active (yn);
2365 if ((prop = node.property (X_("editor-list-page")))) {
2366 _the_notebook.set_current_page (atoi (prop->value ()));
2369 if ((prop = node.property (X_("show-marker-lines")))) {
2370 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2372 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2373 bool yn = string_is_affirmative (prop->value ());
2375 tact->set_active (!yn);
2376 tact->set_active (yn);
2379 XMLNodeList children = node.children ();
2380 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2381 selection->set_state (**i, Stateful::current_state_version);
2382 _regions->set_state (**i);
2385 if ((prop = node.property ("maximised"))) {
2386 bool yn = string_is_affirmative (prop->value());
2387 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2389 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2390 bool fs = tact && tact->get_active();
2392 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2396 if ((prop = node.property ("nudge-clock-value"))) {
2398 sscanf (prop->value().c_str(), "%" PRId64, &f);
2399 nudge_clock->set (f);
2401 nudge_clock->set_mode (AudioClock::Timecode);
2402 nudge_clock->set (_session->frame_rate() * 5, true);
2409 Editor::get_state ()
2411 XMLNode* node = new XMLNode ("Editor");
2414 id().print (buf, sizeof (buf));
2415 node->add_property ("id", buf);
2417 if (is_realized()) {
2418 Glib::RefPtr<Gdk::Window> win = get_window();
2420 int x, y, width, height;
2421 win->get_root_origin(x, y);
2422 win->get_size(width, height);
2424 XMLNode* geometry = new XMLNode ("geometry");
2426 snprintf(buf, sizeof(buf), "%d", width);
2427 geometry->add_property("x-size", string(buf));
2428 snprintf(buf, sizeof(buf), "%d", height);
2429 geometry->add_property("y-size", string(buf));
2430 snprintf(buf, sizeof(buf), "%d", x);
2431 geometry->add_property("x-pos", string(buf));
2432 snprintf(buf, sizeof(buf), "%d", y);
2433 geometry->add_property("y-pos", string(buf));
2434 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2435 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2436 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2437 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2438 geometry->add_property("edit-vertical-pane-pos", string(buf));
2440 node->add_child_nocopy (*geometry);
2443 maybe_add_mixer_strip_width (*node);
2445 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2447 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2448 node->add_property ("zoom", buf);
2449 node->add_property ("snap-to", enum_2_string (_snap_type));
2450 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2451 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2452 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2453 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2454 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2455 node->add_property ("edit-point", enum_2_string (_edit_point));
2456 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2457 node->add_property ("visible-track-count", buf);
2459 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2460 node->add_property ("playhead", buf);
2461 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2462 node->add_property ("left-frame", buf);
2463 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2464 node->add_property ("y-origin", buf);
2466 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2467 node->add_property ("maximised", _maximised ? "yes" : "no");
2468 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2469 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2470 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2471 node->add_property ("mouse-mode", enum2str(mouse_mode));
2472 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2473 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2475 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2477 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2478 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2481 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2483 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2484 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2487 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2488 node->add_property (X_("editor-list-page"), buf);
2490 if (button_bindings) {
2491 XMLNode* bb = new XMLNode (X_("Buttons"));
2492 button_bindings->save (*bb);
2493 node->add_child_nocopy (*bb);
2496 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2498 node->add_child_nocopy (selection->get_state ());
2499 node->add_child_nocopy (_regions->get_state ());
2501 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2502 node->add_property ("nudge-clock-value", buf);
2507 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2508 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2510 * @return pair: TimeAxisView that y is over, layer index.
2512 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2513 * in stacked or expanded region display mode, otherwise 0.
2515 std::pair<TimeAxisView *, double>
2516 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2518 if (!trackview_relative_offset) {
2519 y -= _trackview_group->canvas_origin().y;
2523 return std::make_pair ( (TimeAxisView *) 0, 0);
2526 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2528 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2535 return std::make_pair ( (TimeAxisView *) 0, 0);
2538 /** Snap a position to the grid, if appropriate, taking into account current
2539 * grid settings and also the state of any snap modifier keys that may be pressed.
2540 * @param start Position to snap.
2541 * @param event Event to get current key modifier information from, or 0.
2544 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2546 if (!_session || !event) {
2550 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2551 if (_snap_mode == SnapOff) {
2552 snap_to_internal (start, direction, for_mark);
2555 if (_snap_mode != SnapOff) {
2556 snap_to_internal (start, direction, for_mark);
2562 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2564 if (!_session || _snap_mode == SnapOff) {
2568 snap_to_internal (start, direction, for_mark);
2572 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2574 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2575 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2577 switch (_snap_type) {
2578 case SnapToTimecodeFrame:
2579 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2580 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2582 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2586 case SnapToTimecodeSeconds:
2587 if (_session->config.get_timecode_offset_negative()) {
2588 start += _session->config.get_timecode_offset ();
2590 start -= _session->config.get_timecode_offset ();
2592 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2593 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2595 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2598 if (_session->config.get_timecode_offset_negative()) {
2599 start -= _session->config.get_timecode_offset ();
2601 start += _session->config.get_timecode_offset ();
2605 case SnapToTimecodeMinutes:
2606 if (_session->config.get_timecode_offset_negative()) {
2607 start += _session->config.get_timecode_offset ();
2609 start -= _session->config.get_timecode_offset ();
2611 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2612 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2614 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2616 if (_session->config.get_timecode_offset_negative()) {
2617 start -= _session->config.get_timecode_offset ();
2619 start += _session->config.get_timecode_offset ();
2623 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2629 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2631 const framepos_t one_second = _session->frame_rate();
2632 const framepos_t one_minute = _session->frame_rate() * 60;
2633 framepos_t presnap = start;
2637 switch (_snap_type) {
2638 case SnapToTimecodeFrame:
2639 case SnapToTimecodeSeconds:
2640 case SnapToTimecodeMinutes:
2641 return timecode_snap_to_internal (start, direction, for_mark);
2644 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2645 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2647 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2652 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2653 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2655 start = (framepos_t) floor ((double) start / one_second) * one_second;
2660 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2661 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2663 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2668 start = _session->tempo_map().round_to_bar (start, direction);
2672 start = _session->tempo_map().round_to_beat (start, direction);
2675 case SnapToBeatDiv128:
2676 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2678 case SnapToBeatDiv64:
2679 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2681 case SnapToBeatDiv32:
2682 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2684 case SnapToBeatDiv28:
2685 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2687 case SnapToBeatDiv24:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2690 case SnapToBeatDiv20:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2693 case SnapToBeatDiv16:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2696 case SnapToBeatDiv14:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2699 case SnapToBeatDiv12:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2702 case SnapToBeatDiv10:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2705 case SnapToBeatDiv8:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2708 case SnapToBeatDiv7:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2711 case SnapToBeatDiv6:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2714 case SnapToBeatDiv5:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2717 case SnapToBeatDiv4:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2720 case SnapToBeatDiv3:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2723 case SnapToBeatDiv2:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2732 _session->locations()->marks_either_side (start, before, after);
2734 if (before == max_framepos && after == max_framepos) {
2735 /* No marks to snap to, so just don't snap */
2737 } else if (before == max_framepos) {
2739 } else if (after == max_framepos) {
2741 } else if (before != max_framepos && after != max_framepos) {
2742 /* have before and after */
2743 if ((start - before) < (after - start)) {
2752 case SnapToRegionStart:
2753 case SnapToRegionEnd:
2754 case SnapToRegionSync:
2755 case SnapToRegionBoundary:
2756 if (!region_boundary_cache.empty()) {
2758 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2759 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2761 if (direction > 0) {
2762 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2764 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2767 if (next != region_boundary_cache.begin ()) {
2772 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2773 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2775 if (start > (p + n) / 2) {
2784 switch (_snap_mode) {
2790 if (presnap > start) {
2791 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2795 } else if (presnap < start) {
2796 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2802 /* handled at entry */
2810 Editor::setup_toolbar ()
2812 HBox* mode_box = manage(new HBox);
2813 mode_box->set_border_width (2);
2814 mode_box->set_spacing(2);
2816 HBox* mouse_mode_box = manage (new HBox);
2817 HBox* mouse_mode_hbox = manage (new HBox);
2818 VBox* mouse_mode_vbox = manage (new VBox);
2819 Alignment* mouse_mode_align = manage (new Alignment);
2821 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2822 mouse_mode_size_group->add_widget (smart_mode_button);
2823 mouse_mode_size_group->add_widget (mouse_move_button);
2824 mouse_mode_size_group->add_widget (mouse_cut_button);
2825 mouse_mode_size_group->add_widget (mouse_select_button);
2826 mouse_mode_size_group->add_widget (mouse_zoom_button);
2827 mouse_mode_size_group->add_widget (mouse_gain_button);
2828 mouse_mode_size_group->add_widget (mouse_timefx_button);
2829 mouse_mode_size_group->add_widget (mouse_audition_button);
2830 mouse_mode_size_group->add_widget (mouse_draw_button);
2831 mouse_mode_size_group->add_widget (internal_edit_button);
2833 mouse_mode_size_group->add_widget (zoom_in_button);
2834 mouse_mode_size_group->add_widget (zoom_out_button);
2835 mouse_mode_size_group->add_widget (zoom_preset_selector);
2836 mouse_mode_size_group->add_widget (zoom_out_full_button);
2837 mouse_mode_size_group->add_widget (zoom_focus_selector);
2839 mouse_mode_size_group->add_widget (tav_shrink_button);
2840 mouse_mode_size_group->add_widget (tav_expand_button);
2841 mouse_mode_size_group->add_widget (visible_tracks_selector);
2843 mouse_mode_size_group->add_widget (snap_type_selector);
2844 mouse_mode_size_group->add_widget (snap_mode_selector);
2846 mouse_mode_size_group->add_widget (edit_point_selector);
2847 mouse_mode_size_group->add_widget (edit_mode_selector);
2849 mouse_mode_size_group->add_widget (*nudge_clock);
2850 mouse_mode_size_group->add_widget (nudge_forward_button);
2851 mouse_mode_size_group->add_widget (nudge_backward_button);
2853 mouse_mode_hbox->set_spacing (2);
2855 if (!ARDOUR::Profile->get_trx()) {
2856 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2859 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2860 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2862 if (!ARDOUR::Profile->get_mixbus()) {
2863 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2864 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2867 if (!ARDOUR::Profile->get_trx()) {
2868 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2872 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2875 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2877 mouse_mode_align->add (*mouse_mode_vbox);
2878 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2880 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2882 edit_mode_selector.set_name ("mouse mode button");
2884 if (!ARDOUR::Profile->get_trx()) {
2885 mode_box->pack_start (edit_mode_selector, false, false);
2887 mode_box->pack_start (*mouse_mode_box, false, false);
2889 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2890 _mouse_mode_tearoff->set_name ("MouseModeBase");
2891 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2893 if (Profile->get_sae() || Profile->get_mixbus() ) {
2894 _mouse_mode_tearoff->set_can_be_torn_off (false);
2897 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2898 &_mouse_mode_tearoff->tearoff_window()));
2899 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2900 &_mouse_mode_tearoff->tearoff_window(), 1));
2901 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2902 &_mouse_mode_tearoff->tearoff_window()));
2903 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2904 &_mouse_mode_tearoff->tearoff_window(), 1));
2908 _zoom_box.set_spacing (2);
2909 _zoom_box.set_border_width (2);
2913 zoom_preset_selector.set_name ("zoom button");
2914 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2915 zoom_preset_selector.set_size_request (42, -1);
2917 zoom_in_button.set_name ("zoom button");
2918 zoom_in_button.set_image(::get_icon ("zoom_in"));
2919 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2920 zoom_in_button.set_related_action (act);
2922 zoom_out_button.set_name ("zoom button");
2923 zoom_out_button.set_image(::get_icon ("zoom_out"));
2924 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2925 zoom_out_button.set_related_action (act);
2927 zoom_out_full_button.set_name ("zoom button");
2928 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2929 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2930 zoom_out_full_button.set_related_action (act);
2932 zoom_focus_selector.set_name ("zoom button");
2934 if (ARDOUR::Profile->get_mixbus()) {
2935 _zoom_box.pack_start (zoom_preset_selector, false, false);
2936 } else if (ARDOUR::Profile->get_trx()) {
2937 mode_box->pack_start (zoom_out_button, false, false);
2938 mode_box->pack_start (zoom_in_button, false, false);
2940 _zoom_box.pack_start (zoom_out_button, false, false);
2941 _zoom_box.pack_start (zoom_in_button, false, false);
2942 _zoom_box.pack_start (zoom_out_full_button, false, false);
2943 _zoom_box.pack_start (zoom_focus_selector, false, false);
2946 /* Track zoom buttons */
2947 visible_tracks_selector.set_name ("zoom button");
2948 if (Profile->get_mixbus()) {
2949 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2950 visible_tracks_selector.set_size_request (42, -1);
2952 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2955 tav_expand_button.set_name ("zoom button");
2956 tav_expand_button.set_image(::get_icon ("tav_exp"));
2957 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2958 tav_expand_button.set_related_action (act);
2960 tav_shrink_button.set_name ("zoom button");
2961 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2962 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2963 tav_shrink_button.set_related_action (act);
2965 if (ARDOUR::Profile->get_mixbus()) {
2966 _zoom_box.pack_start (visible_tracks_selector);
2967 } else if (ARDOUR::Profile->get_trx()) {
2968 _zoom_box.pack_start (tav_shrink_button);
2969 _zoom_box.pack_start (tav_expand_button);
2971 _zoom_box.pack_start (visible_tracks_selector);
2972 _zoom_box.pack_start (tav_shrink_button);
2973 _zoom_box.pack_start (tav_expand_button);
2976 if (!ARDOUR::Profile->get_trx()) {
2977 _zoom_tearoff = manage (new TearOff (_zoom_box));
2979 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2980 &_zoom_tearoff->tearoff_window()));
2981 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2982 &_zoom_tearoff->tearoff_window(), 0));
2983 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2984 &_zoom_tearoff->tearoff_window()));
2985 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2986 &_zoom_tearoff->tearoff_window(), 0));
2989 if (Profile->get_sae() || Profile->get_mixbus() ) {
2990 _zoom_tearoff->set_can_be_torn_off (false);
2993 snap_box.set_spacing (2);
2994 snap_box.set_border_width (2);
2996 snap_type_selector.set_name ("mouse mode button");
2998 snap_mode_selector.set_name ("mouse mode button");
3000 edit_point_selector.set_name ("mouse mode button");
3002 snap_box.pack_start (snap_mode_selector, false, false);
3003 snap_box.pack_start (snap_type_selector, false, false);
3004 snap_box.pack_start (edit_point_selector, false, false);
3008 HBox *nudge_box = manage (new HBox);
3009 nudge_box->set_spacing (2);
3010 nudge_box->set_border_width (2);
3012 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3013 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3015 nudge_box->pack_start (nudge_backward_button, false, false);
3016 nudge_box->pack_start (nudge_forward_button, false, false);
3017 nudge_box->pack_start (*nudge_clock, false, false);
3020 /* Pack everything in... */
3022 HBox* hbox = manage (new HBox);
3023 hbox->set_spacing(2);
3025 _tools_tearoff = manage (new TearOff (*hbox));
3026 _tools_tearoff->set_name ("MouseModeBase");
3027 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3029 if (Profile->get_sae() || Profile->get_mixbus()) {
3030 _tools_tearoff->set_can_be_torn_off (false);
3033 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3034 &_tools_tearoff->tearoff_window()));
3035 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3036 &_tools_tearoff->tearoff_window(), 0));
3037 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3038 &_tools_tearoff->tearoff_window()));
3039 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3040 &_tools_tearoff->tearoff_window(), 0));
3042 toolbar_hbox.set_spacing (2);
3043 toolbar_hbox.set_border_width (1);
3045 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3046 if (!ARDOUR::Profile->get_trx()) {
3047 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3048 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3051 if (!ARDOUR::Profile->get_trx()) {
3052 hbox->pack_start (snap_box, false, false);
3053 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3054 hbox->pack_start (*nudge_box, false, false);
3056 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3059 hbox->pack_start (panic_box, false, false);
3063 toolbar_base.set_name ("ToolBarBase");
3064 toolbar_base.add (toolbar_hbox);
3066 _toolbar_viewport.add (toolbar_base);
3067 /* stick to the required height but allow width to vary if there's not enough room */
3068 _toolbar_viewport.set_size_request (1, -1);
3070 toolbar_frame.set_shadow_type (SHADOW_OUT);
3071 toolbar_frame.set_name ("BaseFrame");
3072 toolbar_frame.add (_toolbar_viewport);
3076 Editor::build_edit_point_menu ()
3078 using namespace Menu_Helpers;
3080 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3081 if(!Profile->get_mixbus())
3082 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3083 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3085 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3089 Editor::build_edit_mode_menu ()
3091 using namespace Menu_Helpers;
3093 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3094 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3095 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3096 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3098 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3102 Editor::build_snap_mode_menu ()
3104 using namespace Menu_Helpers;
3106 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3107 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3108 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3110 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3114 Editor::build_snap_type_menu ()
3116 using namespace Menu_Helpers;
3118 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3119 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3120 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3121 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3122 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3123 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3124 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3125 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3126 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3133 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3134 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3135 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3136 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3137 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3138 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3139 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3140 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3141 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3142 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3149 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3154 Editor::setup_tooltips ()
3156 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3157 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3158 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3159 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3160 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3161 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3162 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3163 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3164 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3165 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3166 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3167 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3168 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3169 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3170 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3171 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3172 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3173 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3174 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3175 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3176 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3177 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3178 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3179 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3180 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3181 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3185 Editor::convert_drop_to_paths (
3186 vector<string>& paths,
3187 const RefPtr<Gdk::DragContext>& /*context*/,
3190 const SelectionData& data,
3194 if (_session == 0) {
3198 vector<string> uris = data.get_uris();
3202 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3203 are actually URI lists. So do it by hand.
3206 if (data.get_target() != "text/plain") {
3210 /* Parse the "uri-list" format that Nautilus provides,
3211 where each pathname is delimited by \r\n.
3213 THERE MAY BE NO NULL TERMINATING CHAR!!!
3216 string txt = data.get_text();
3220 p = (char *) malloc (txt.length() + 1);
3221 txt.copy (p, txt.length(), 0);
3222 p[txt.length()] = '\0';
3228 while (g_ascii_isspace (*p))
3232 while (*q && (*q != '\n') && (*q != '\r')) {
3239 while (q > p && g_ascii_isspace (*q))
3244 uris.push_back (string (p, q - p + 1));
3248 p = strchr (p, '\n');
3260 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3261 if ((*i).substr (0,7) == "file://") {
3262 paths.push_back (Glib::filename_from_uri (*i));
3270 Editor::new_tempo_section ()
3275 Editor::map_transport_state ()
3277 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3279 if (_session && _session->transport_stopped()) {
3280 have_pending_keyboard_selection = false;
3283 update_loop_range_view ();
3289 Editor::begin_reversible_command (string name)
3292 _session->begin_reversible_command (name);
3297 Editor::begin_reversible_command (GQuark q)
3300 _session->begin_reversible_command (q);
3305 Editor::commit_reversible_command ()
3308 _session->commit_reversible_command ();
3313 Editor::history_changed ()
3317 if (undo_action && _session) {
3318 if (_session->undo_depth() == 0) {
3319 label = S_("Command|Undo");
3321 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3323 undo_action->property_label() = label;
3326 if (redo_action && _session) {
3327 if (_session->redo_depth() == 0) {
3330 label = string_compose(_("Redo (%1)"), _session->next_redo());
3332 redo_action->property_label() = label;
3337 Editor::duplicate_range (bool with_dialog)
3341 RegionSelection rs = get_regions_from_selection_and_entered ();
3343 if ( selection->time.length() == 0 && rs.empty()) {
3349 ArdourDialog win (_("Duplicate"));
3350 Label label (_("Number of duplications:"));
3351 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3352 SpinButton spinner (adjustment, 0.0, 1);
3355 win.get_vbox()->set_spacing (12);
3356 win.get_vbox()->pack_start (hbox);
3357 hbox.set_border_width (6);
3358 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3360 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3361 place, visually. so do this by hand.
3364 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3365 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3366 spinner.grab_focus();
3372 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3373 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3374 win.set_default_response (RESPONSE_ACCEPT);
3376 spinner.grab_focus ();
3378 switch (win.run ()) {
3379 case RESPONSE_ACCEPT:
3385 times = adjustment.get_value();
3388 if ((current_mouse_mode() == Editing::MouseRange)) {
3389 if (selection->time.length()) {
3390 duplicate_selection (times);
3392 } else if (get_smart_mode()) {
3393 if (selection->time.length()) {
3394 duplicate_selection (times);
3396 duplicate_some_regions (rs, times);
3398 duplicate_some_regions (rs, times);
3403 Editor::set_edit_mode (EditMode m)
3405 Config->set_edit_mode (m);
3409 Editor::cycle_edit_mode ()
3411 switch (Config->get_edit_mode()) {
3413 if (Profile->get_sae()) {
3414 Config->set_edit_mode (Lock);
3416 Config->set_edit_mode (Ripple);
3421 Config->set_edit_mode (Lock);
3424 Config->set_edit_mode (Slide);
3430 Editor::edit_mode_selection_done ( EditMode m )
3432 Config->set_edit_mode ( m );
3436 Editor::snap_type_selection_done (SnapType snaptype)
3438 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3440 ract->set_active ();
3445 Editor::snap_mode_selection_done (SnapMode mode)
3447 RefPtr<RadioAction> ract = snap_mode_action (mode);
3450 ract->set_active (true);
3455 Editor::cycle_edit_point (bool with_marker)
3457 if(Profile->get_mixbus())
3458 with_marker = false;
3460 switch (_edit_point) {
3462 set_edit_point_preference (EditAtPlayhead);
3464 case EditAtPlayhead:
3466 set_edit_point_preference (EditAtSelectedMarker);
3468 set_edit_point_preference (EditAtMouse);
3471 case EditAtSelectedMarker:
3472 set_edit_point_preference (EditAtMouse);
3478 Editor::edit_point_selection_done (EditPoint ep)
3480 set_edit_point_preference ( ep );
3484 Editor::build_zoom_focus_menu ()
3486 using namespace Menu_Helpers;
3488 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3489 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3490 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3491 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3492 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3493 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3495 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3499 Editor::zoom_focus_selection_done ( ZoomFocus f )
3501 RefPtr<RadioAction> ract = zoom_focus_action (f);
3503 ract->set_active ();
3508 Editor::build_track_count_menu ()
3510 using namespace Menu_Helpers;
3512 if (!Profile->get_mixbus()) {
3513 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3514 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3515 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3516 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3517 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3518 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3519 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3520 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3521 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3522 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3523 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3524 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3525 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3527 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3528 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3529 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3530 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3531 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3532 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3533 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3534 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3535 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3536 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3538 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3539 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3540 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3541 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3542 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3543 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3544 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3545 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3546 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3547 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3548 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3553 Editor::set_zoom_preset (int64_t ms)
3556 temporal_zoom_session();
3560 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3561 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3565 Editor::set_visible_track_count (int32_t n)
3567 _visible_track_count = n;
3569 /* if the canvas hasn't really been allocated any size yet, just
3570 record the desired number of visible tracks and return. when canvas
3571 allocation happens, we will get called again and then we can do the
3575 if (_visible_canvas_height <= 1) {
3582 if (_visible_track_count > 0) {
3583 h = trackviews_height() / _visible_track_count;
3584 std::ostringstream s;
3585 s << _visible_track_count;
3587 } else if (_visible_track_count == 0) {
3589 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3590 if ((*i)->marked_for_display()) {
3594 h = trackviews_height() / n;
3597 /* negative value means that the visible track count has
3598 been overridden by explicit track height changes.
3600 visible_tracks_selector.set_text (X_("*"));
3604 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3605 (*i)->set_height (h);
3608 if (str != visible_tracks_selector.get_text()) {
3609 visible_tracks_selector.set_text (str);
3614 Editor::override_visible_track_count ()
3616 _visible_track_count = -_visible_track_count;
3617 visible_tracks_selector.set_text ( _("*") );
3621 Editor::edit_controls_button_release (GdkEventButton* ev)
3623 if (Keyboard::is_context_menu_event (ev)) {
3624 ARDOUR_UI::instance()->add_route (this);
3625 } else if (ev->button == 1) {
3626 selection->clear_tracks ();
3633 Editor::mouse_select_button_release (GdkEventButton* ev)
3635 /* this handles just right-clicks */
3637 if (ev->button != 3) {
3645 Editor::set_zoom_focus (ZoomFocus f)
3647 string str = zoom_focus_strings[(int)f];
3649 if (str != zoom_focus_selector.get_text()) {
3650 zoom_focus_selector.set_text (str);
3653 if (zoom_focus != f) {
3660 Editor::cycle_zoom_focus ()
3662 switch (zoom_focus) {
3664 set_zoom_focus (ZoomFocusRight);
3666 case ZoomFocusRight:
3667 set_zoom_focus (ZoomFocusCenter);
3669 case ZoomFocusCenter:
3670 set_zoom_focus (ZoomFocusPlayhead);
3672 case ZoomFocusPlayhead:
3673 set_zoom_focus (ZoomFocusMouse);
3675 case ZoomFocusMouse:
3676 set_zoom_focus (ZoomFocusEdit);
3679 set_zoom_focus (ZoomFocusLeft);
3685 Editor::ensure_float (Window& win)
3687 win.set_transient_for (*this);
3691 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3693 /* recover or initialize pane positions. do this here rather than earlier because
3694 we don't want the positions to change the child allocations, which they seem to do.
3700 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3709 XMLNode* geometry = find_named_node (*node, "geometry");
3711 if (which == static_cast<Paned*> (&edit_pane)) {
3713 if (done & Horizontal) {
3717 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3718 _notebook_shrunk = string_is_affirmative (prop->value ());
3721 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3722 /* initial allocation is 90% to canvas, 10% to notebook */
3723 pos = (int) floor (alloc.get_width() * 0.90f);
3724 snprintf (buf, sizeof(buf), "%d", pos);
3726 pos = atoi (prop->value());
3729 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3730 edit_pane.set_position (pos);
3733 done = (Pane) (done | Horizontal);
3735 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3737 if (done & Vertical) {
3741 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3742 /* initial allocation is 90% to canvas, 10% to summary */
3743 pos = (int) floor (alloc.get_height() * 0.90f);
3744 snprintf (buf, sizeof(buf), "%d", pos);
3747 pos = atoi (prop->value());
3750 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3751 editor_summary_pane.set_position (pos);
3754 done = (Pane) (done | Vertical);
3759 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3761 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3762 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3763 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3764 top_hbox.remove (toolbar_frame);
3769 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3771 if (toolbar_frame.get_parent() == 0) {
3772 top_hbox.pack_end (toolbar_frame);
3777 Editor::set_show_measures (bool yn)
3779 if (_show_measures != yn) {
3782 if ((_show_measures = yn) == true) {
3784 tempo_lines->show();
3787 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3788 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3790 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3791 draw_measures (begin, end);
3799 Editor::toggle_follow_playhead ()
3801 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3803 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3804 set_follow_playhead (tact->get_active());
3808 /** @param yn true to follow playhead, otherwise false.
3809 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3812 Editor::set_follow_playhead (bool yn, bool catch_up)
3814 if (_follow_playhead != yn) {
3815 if ((_follow_playhead = yn) == true && catch_up) {
3817 reset_x_origin_to_follow_playhead ();
3824 Editor::toggle_stationary_playhead ()
3826 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3828 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3829 set_stationary_playhead (tact->get_active());
3834 Editor::set_stationary_playhead (bool yn)
3836 if (_stationary_playhead != yn) {
3837 if ((_stationary_playhead = yn) == true) {
3839 // FIXME need a 3.0 equivalent of this 2.X call
3840 // update_current_screen ();
3847 Editor::playlist_selector () const
3849 return *_playlist_selector;
3853 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3857 switch (_snap_type) {
3862 case SnapToBeatDiv128:
3865 case SnapToBeatDiv64:
3868 case SnapToBeatDiv32:
3871 case SnapToBeatDiv28:
3874 case SnapToBeatDiv24:
3877 case SnapToBeatDiv20:
3880 case SnapToBeatDiv16:
3883 case SnapToBeatDiv14:
3886 case SnapToBeatDiv12:
3889 case SnapToBeatDiv10:
3892 case SnapToBeatDiv8:
3895 case SnapToBeatDiv7:
3898 case SnapToBeatDiv6:
3901 case SnapToBeatDiv5:
3904 case SnapToBeatDiv4:
3907 case SnapToBeatDiv3:
3910 case SnapToBeatDiv2:
3916 return _session->tempo_map().meter_at (position).divisions_per_bar();
3921 case SnapToTimecodeFrame:
3922 case SnapToTimecodeSeconds:
3923 case SnapToTimecodeMinutes:
3926 case SnapToRegionStart:
3927 case SnapToRegionEnd:
3928 case SnapToRegionSync:
3929 case SnapToRegionBoundary:
3939 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3943 ret = nudge_clock->current_duration (pos);
3944 next = ret + 1; /* XXXX fix me */
3950 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3952 ArdourDialog dialog (_("Playlist Deletion"));
3953 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3954 "If it is kept, its audio files will not be cleaned.\n"
3955 "If it is deleted, audio files used by it alone will be cleaned."),
3958 dialog.set_position (WIN_POS_CENTER);
3959 dialog.get_vbox()->pack_start (label);
3963 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3964 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3965 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3967 switch (dialog.run ()) {
3968 case RESPONSE_ACCEPT:
3969 /* delete the playlist */
3973 case RESPONSE_REJECT:
3974 /* keep the playlist */
3986 Editor::audio_region_selection_covers (framepos_t where)
3988 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3989 if ((*a)->region()->covers (where)) {
3998 Editor::prepare_for_cleanup ()
4000 cut_buffer->clear_regions ();
4001 cut_buffer->clear_playlists ();
4003 selection->clear_regions ();
4004 selection->clear_playlists ();
4006 _regions->suspend_redisplay ();
4010 Editor::finish_cleanup ()
4012 _regions->resume_redisplay ();
4016 Editor::transport_loop_location()
4019 return _session->locations()->auto_loop_location();
4026 Editor::transport_punch_location()
4029 return _session->locations()->auto_punch_location();
4036 Editor::control_layout_scroll (GdkEventScroll* ev)
4038 /* Just forward to the normal canvas scroll method. The coordinate
4039 systems are different but since the canvas is always larger than the
4040 track headers, and aligned with the trackview area, this will work.
4042 In the not too distant future this layout is going away anyway and
4043 headers will be on the canvas.
4045 return canvas_scroll_event (ev, false);
4049 Editor::session_state_saved (string)
4052 _snapshots->redisplay ();
4056 Editor::update_tearoff_visibility()
4058 bool visible = Config->get_keep_tearoffs();
4059 _mouse_mode_tearoff->set_visible (visible);
4060 _tools_tearoff->set_visible (visible);
4061 if (_zoom_tearoff) {
4062 _zoom_tearoff->set_visible (visible);
4067 Editor::maximise_editing_space ()
4079 Editor::restore_editing_space ()
4091 * Make new playlists for a given track and also any others that belong
4092 * to the same active route group with the `select' property.
4097 Editor::new_playlists (TimeAxisView* v)
4099 begin_reversible_command (_("new playlists"));
4100 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4101 _session->playlists->get (playlists);
4102 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4103 commit_reversible_command ();
4107 * Use a copy of the current playlist for a given track and also any others that belong
4108 * to the same active route group with the `select' property.
4113 Editor::copy_playlists (TimeAxisView* v)
4115 begin_reversible_command (_("copy playlists"));
4116 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4117 _session->playlists->get (playlists);
4118 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4119 commit_reversible_command ();
4122 /** Clear the current playlist for a given track and also any others that belong
4123 * to the same active route group with the `select' property.
4128 Editor::clear_playlists (TimeAxisView* v)
4130 begin_reversible_command (_("clear playlists"));
4131 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4132 _session->playlists->get (playlists);
4133 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4134 commit_reversible_command ();
4138 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4140 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4144 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4146 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4150 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4152 atv.clear_playlist ();
4156 Editor::on_key_press_event (GdkEventKey* ev)
4158 return key_press_focus_accelerator_handler (*this, ev);
4162 Editor::on_key_release_event (GdkEventKey* ev)
4164 return Gtk::Window::on_key_release_event (ev);
4165 // return key_press_focus_accelerator_handler (*this, ev);
4168 /** Queue up a change to the viewport x origin.
4169 * @param frame New x origin.
4172 Editor::reset_x_origin (framepos_t frame)
4174 pending_visual_change.add (VisualChange::TimeOrigin);
4175 pending_visual_change.time_origin = frame;
4176 ensure_visual_change_idle_handler ();
4180 Editor::reset_y_origin (double y)
4182 pending_visual_change.add (VisualChange::YOrigin);
4183 pending_visual_change.y_origin = y;
4184 ensure_visual_change_idle_handler ();
4188 Editor::reset_zoom (framecnt_t spp)
4190 if (spp == samples_per_pixel) {
4194 pending_visual_change.add (VisualChange::ZoomLevel);
4195 pending_visual_change.samples_per_pixel = spp;
4196 ensure_visual_change_idle_handler ();
4200 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4202 reset_x_origin (frame);
4205 if (!no_save_visual) {
4206 undo_visual_stack.push_back (current_visual_state(false));
4210 Editor::VisualState::VisualState (bool with_tracks)
4211 : gui_state (with_tracks ? new GUIObjectState : 0)
4215 Editor::VisualState::~VisualState ()
4220 Editor::VisualState*
4221 Editor::current_visual_state (bool with_tracks)
4223 VisualState* vs = new VisualState (with_tracks);
4224 vs->y_position = vertical_adjustment.get_value();
4225 vs->samples_per_pixel = samples_per_pixel;
4226 vs->leftmost_frame = leftmost_frame;
4227 vs->zoom_focus = zoom_focus;
4230 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4237 Editor::undo_visual_state ()
4239 if (undo_visual_stack.empty()) {
4243 VisualState* vs = undo_visual_stack.back();
4244 undo_visual_stack.pop_back();
4247 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4249 use_visual_state (*vs);
4253 Editor::redo_visual_state ()
4255 if (redo_visual_stack.empty()) {
4259 VisualState* vs = redo_visual_stack.back();
4260 redo_visual_stack.pop_back();
4262 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4264 use_visual_state (*vs);
4268 Editor::swap_visual_state ()
4270 if (undo_visual_stack.empty()) {
4271 redo_visual_state ();
4273 undo_visual_state ();
4278 Editor::use_visual_state (VisualState& vs)
4280 PBD::Unwinder<bool> nsv (no_save_visual, true);
4281 DisplaySuspender ds;
4283 vertical_adjustment.set_value (vs.y_position);
4285 set_zoom_focus (vs.zoom_focus);
4286 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4289 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4291 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4292 (*i)->reset_visual_state ();
4296 _routes->update_visibility ();
4299 /** This is the core function that controls the zoom level of the canvas. It is called
4300 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4301 * @param spp new number of samples per pixel
4304 Editor::set_samples_per_pixel (framecnt_t spp)
4310 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4311 const framecnt_t lots_of_pixels = 4000;
4313 /* if the zoom level is greater than what you'd get trying to display 3
4314 * days of audio on a really big screen, then it's too big.
4317 if (spp * lots_of_pixels > three_days) {
4321 samples_per_pixel = spp;
4324 tempo_lines->tempo_map_changed();
4327 bool const showing_time_selection = selection->time.length() > 0;
4329 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4330 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4331 (*i)->reshow_selection (selection->time);
4335 ZoomChanged (); /* EMIT_SIGNAL */
4337 ArdourCanvas::GtkCanvasViewport* c;
4339 c = get_track_canvas();
4341 c->canvas()->zoomed ();
4344 if (playhead_cursor) {
4345 playhead_cursor->set_position (playhead_cursor->current_frame ());
4348 refresh_location_display();
4349 _summary->set_overlays_dirty ();
4351 update_marker_labels ();
4357 Editor::queue_visual_videotimeline_update ()
4360 * pending_visual_change.add (VisualChange::VideoTimeline);
4361 * or maybe even more specific: which videotimeline-image
4362 * currently it calls update_video_timeline() to update
4363 * _all outdated_ images on the video-timeline.
4364 * see 'exposeimg()' in video_image_frame.cc
4366 ensure_visual_change_idle_handler ();
4370 Editor::ensure_visual_change_idle_handler ()
4372 if (pending_visual_change.idle_handler_id < 0) {
4373 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4374 pending_visual_change.being_handled = false;
4379 Editor::_idle_visual_changer (void* arg)
4381 return static_cast<Editor*>(arg)->idle_visual_changer ();
4385 Editor::idle_visual_changer ()
4387 /* set_horizontal_position() below (and maybe other calls) call
4388 gtk_main_iteration(), so it's possible that a signal will be handled
4389 half-way through this method. If this signal wants an
4390 idle_visual_changer we must schedule another one after this one, so
4391 mark the idle_handler_id as -1 here to allow that. Also make a note
4392 that we are doing the visual change, so that changes in response to
4393 super-rapid-screen-update can be dropped if we are still processing
4397 pending_visual_change.idle_handler_id = -1;
4398 pending_visual_change.being_handled = true;
4400 VisualChange vc = pending_visual_change;
4402 pending_visual_change.pending = (VisualChange::Type) 0;
4404 visual_changer (vc);
4406 pending_visual_change.being_handled = false;
4408 return 0; /* this is always a one-shot call */
4412 Editor::visual_changer (const VisualChange& vc)
4414 double const last_time_origin = horizontal_position ();
4416 if (vc.pending & VisualChange::ZoomLevel) {
4417 set_samples_per_pixel (vc.samples_per_pixel);
4419 compute_fixed_ruler_scale ();
4421 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4422 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4424 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4425 current_bbt_points_begin, current_bbt_points_end);
4426 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4427 current_bbt_points_begin, current_bbt_points_end);
4428 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4430 update_video_timeline();
4433 if (vc.pending & VisualChange::TimeOrigin) {
4434 set_horizontal_position (vc.time_origin / samples_per_pixel);
4437 if (vc.pending & VisualChange::YOrigin) {
4438 vertical_adjustment.set_value (vc.y_origin);
4441 if (last_time_origin == horizontal_position ()) {
4442 /* changed signal not emitted */
4443 update_fixed_rulers ();
4444 redisplay_tempo (true);
4447 if (!(vc.pending & VisualChange::ZoomLevel)) {
4448 update_video_timeline();
4451 _summary->set_overlays_dirty ();
4454 struct EditorOrderTimeAxisSorter {
4455 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4456 return a->order () < b->order ();
4461 Editor::sort_track_selection (TrackViewList& sel)
4463 EditorOrderTimeAxisSorter cmp;
4468 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4471 framepos_t where = 0;
4472 EditPoint ep = _edit_point;
4474 if(Profile->get_mixbus())
4475 if (ep == EditAtSelectedMarker)
4478 if (from_context_menu && (ep == EditAtMouse)) {
4479 return canvas_event_sample (&context_click_event, 0, 0);
4482 if (entered_marker) {
4483 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4484 return entered_marker->position();
4487 if (ignore_playhead && ep == EditAtPlayhead) {
4488 ep = EditAtSelectedMarker;
4492 case EditAtPlayhead:
4493 where = _session->audible_frame();
4494 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4497 case EditAtSelectedMarker:
4498 if (!selection->markers.empty()) {
4500 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4503 where = loc->start();
4507 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4515 if (!mouse_frame (where, ignored)) {
4516 /* XXX not right but what can we do ? */
4520 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4528 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4530 if (!_session) return;
4532 begin_reversible_command (cmd);
4536 if ((tll = transport_loop_location()) == 0) {
4537 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4538 XMLNode &before = _session->locations()->get_state();
4539 _session->locations()->add (loc, true);
4540 _session->set_auto_loop_location (loc);
4541 XMLNode &after = _session->locations()->get_state();
4542 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4544 XMLNode &before = tll->get_state();
4545 tll->set_hidden (false, this);
4546 tll->set (start, end);
4547 XMLNode &after = tll->get_state();
4548 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4551 commit_reversible_command ();
4555 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4557 if (!_session) return;
4559 begin_reversible_command (cmd);
4563 if ((tpl = transport_punch_location()) == 0) {
4564 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4565 XMLNode &before = _session->locations()->get_state();
4566 _session->locations()->add (loc, true);
4567 _session->set_auto_punch_location (loc);
4568 XMLNode &after = _session->locations()->get_state();
4569 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4572 XMLNode &before = tpl->get_state();
4573 tpl->set_hidden (false, this);
4574 tpl->set (start, end);
4575 XMLNode &after = tpl->get_state();
4576 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4579 commit_reversible_command ();
4582 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4583 * @param rs List to which found regions are added.
4584 * @param where Time to look at.
4585 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4588 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4590 const TrackViewList* tracks;
4593 tracks = &track_views;
4598 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4600 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4603 boost::shared_ptr<Track> tr;
4604 boost::shared_ptr<Playlist> pl;
4606 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4608 boost::shared_ptr<RegionList> regions = pl->regions_at (
4609 (framepos_t) floor ( (double) where * tr->speed()));
4611 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4612 RegionView* rv = rtv->view()->find_view (*i);
4623 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4625 const TrackViewList* tracks;
4628 tracks = &track_views;
4633 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4634 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4636 boost::shared_ptr<Track> tr;
4637 boost::shared_ptr<Playlist> pl;
4639 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4641 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4642 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4644 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4646 RegionView* rv = rtv->view()->find_view (*i);
4657 /** Get regions using the following method:
4659 * Make a region list using:
4660 * (a) any selected regions
4661 * (b) the intersection of any selected tracks and the edit point(*)
4662 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4664 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4666 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4670 Editor::get_regions_from_selection_and_edit_point ()
4672 RegionSelection regions;
4674 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4675 regions.add (entered_regionview);
4677 regions = selection->regions;
4680 if ( regions.empty() ) {
4681 TrackViewList tracks = selection->tracks;
4683 if (!tracks.empty()) {
4684 /* no region selected or entered, but some selected tracks:
4685 * act on all regions on the selected tracks at the edit point
4687 framepos_t const where = get_preferred_edit_position ();
4688 get_regions_at(regions, where, tracks);
4695 /** Get regions using the following method:
4697 * Make a region list using:
4698 * (a) any selected regions
4699 * (b) the intersection of any selected tracks and the edit point(*)
4700 * (c) if neither exists, then whatever region is under the mouse
4702 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4704 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4707 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4709 RegionSelection regions;
4711 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4712 regions.add (entered_regionview);
4714 regions = selection->regions;
4717 if ( regions.empty() ) {
4718 TrackViewList tracks = selection->tracks;
4720 if (!tracks.empty()) {
4721 /* no region selected or entered, but some selected tracks:
4722 * act on all regions on the selected tracks at the edit point
4724 get_regions_at(regions, pos, tracks);
4731 /** Start with regions that are selected, or the entered regionview if none are selected.
4732 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4733 * of the regions that we started with.
4737 Editor::get_regions_from_selection_and_entered ()
4739 RegionSelection regions = selection->regions;
4741 if (regions.empty() && entered_regionview) {
4742 regions.add (entered_regionview);
4749 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4751 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4753 RouteTimeAxisView* tatv;
4755 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4757 boost::shared_ptr<Playlist> pl;
4758 vector<boost::shared_ptr<Region> > results;
4760 boost::shared_ptr<Track> tr;
4762 if ((tr = tatv->track()) == 0) {
4767 if ((pl = (tr->playlist())) != 0) {
4768 if (src_comparison) {
4769 pl->get_source_equivalent_regions (region, results);
4771 pl->get_region_list_equivalent_regions (region, results);
4775 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4776 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4777 regions.push_back (marv);
4786 Editor::show_rhythm_ferret ()
4788 if (rhythm_ferret == 0) {
4789 rhythm_ferret = new RhythmFerret(*this);
4792 rhythm_ferret->set_session (_session);
4793 rhythm_ferret->show ();
4794 rhythm_ferret->present ();
4798 Editor::first_idle ()
4800 MessageDialog* dialog = 0;
4802 if (track_views.size() > 1) {
4803 dialog = new MessageDialog (
4805 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4809 ARDOUR_UI::instance()->flush_pending ();
4812 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4816 // first idle adds route children (automation tracks), so we need to redisplay here
4817 _routes->redisplay ();
4824 Editor::_idle_resize (gpointer arg)
4826 return ((Editor*)arg)->idle_resize ();
4830 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4832 if (resize_idle_id < 0) {
4833 resize_idle_id = g_idle_add (_idle_resize, this);
4834 _pending_resize_amount = 0;
4837 /* make a note of the smallest resulting height, so that we can clamp the
4838 lower limit at TimeAxisView::hSmall */
4840 int32_t min_resulting = INT32_MAX;
4842 _pending_resize_amount += h;
4843 _pending_resize_view = view;
4845 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4847 if (selection->tracks.contains (_pending_resize_view)) {
4848 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4849 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4853 if (min_resulting < 0) {
4858 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4859 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4863 /** Handle pending resizing of tracks */
4865 Editor::idle_resize ()
4867 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4869 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4870 selection->tracks.contains (_pending_resize_view)) {
4872 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4873 if (*i != _pending_resize_view) {
4874 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4879 _pending_resize_amount = 0;
4880 _group_tabs->set_dirty ();
4881 resize_idle_id = -1;
4889 ENSURE_GUI_THREAD (*this, &Editor::located);
4892 playhead_cursor->set_position (_session->audible_frame ());
4893 if (_follow_playhead && !_pending_initial_locate) {
4894 reset_x_origin_to_follow_playhead ();
4898 _pending_locate_request = false;
4899 _pending_initial_locate = false;
4903 Editor::region_view_added (RegionView *)
4905 _summary->set_background_dirty ();
4909 Editor::region_view_removed ()
4911 _summary->set_background_dirty ();
4915 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4917 TrackViewList::const_iterator j = track_views.begin ();
4918 while (j != track_views.end()) {
4919 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4920 if (rtv && rtv->route() == r) {
4931 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4935 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4936 TimeAxisView* tv = axis_view_from_route (*i);
4946 Editor::suspend_route_redisplay ()
4949 _routes->suspend_redisplay();
4954 Editor::resume_route_redisplay ()
4957 _routes->resume_redisplay();
4962 Editor::add_routes (RouteList& routes)
4964 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4966 RouteTimeAxisView *rtv;
4967 list<RouteTimeAxisView*> new_views;
4969 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4970 boost::shared_ptr<Route> route = (*x);
4972 if (route->is_auditioner() || route->is_monitor()) {
4976 DataType dt = route->input()->default_type();
4978 if (dt == ARDOUR::DataType::AUDIO) {
4979 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4980 rtv->set_route (route);
4981 } else if (dt == ARDOUR::DataType::MIDI) {
4982 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4983 rtv->set_route (route);
4985 throw unknown_type();
4988 new_views.push_back (rtv);
4989 track_views.push_back (rtv);
4991 rtv->effective_gain_display ();
4993 if (internal_editing()) {
4994 rtv->enter_internal_edit_mode ();
4996 rtv->leave_internal_edit_mode ();
4999 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5000 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5003 if (new_views.size() > 0) {
5004 _routes->routes_added (new_views);
5005 _summary->routes_added (new_views);
5008 if (show_editor_mixer_when_tracks_arrive) {
5009 show_editor_mixer (true);
5012 editor_list_button.set_sensitive (true);
5016 Editor::timeaxisview_deleted (TimeAxisView *tv)
5018 if (tv == entered_track) {
5022 if (_session && _session->deletion_in_progress()) {
5023 /* the situation is under control */
5027 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5029 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5031 _routes->route_removed (tv);
5033 TimeAxisView::Children c = tv->get_child_list ();
5034 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5035 if (entered_track == i->get()) {
5040 /* remove it from the list of track views */
5042 TrackViewList::iterator i;
5044 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5045 i = track_views.erase (i);
5048 /* update whatever the current mixer strip is displaying, if revelant */
5050 boost::shared_ptr<Route> route;
5053 route = rtav->route ();
5056 if (current_mixer_strip && current_mixer_strip->route() == route) {
5058 TimeAxisView* next_tv;
5060 if (track_views.empty()) {
5062 } else if (i == track_views.end()) {
5063 next_tv = track_views.front();
5070 set_selected_mixer_strip (*next_tv);
5072 /* make the editor mixer strip go away setting the
5073 * button to inactive (which also unticks the menu option)
5076 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5082 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5084 if (apply_to_selection) {
5085 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5087 TrackSelection::iterator j = i;
5090 hide_track_in_display (*i, false);
5095 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5097 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5098 // this will hide the mixer strip
5099 set_selected_mixer_strip (*tv);
5102 _routes->hide_track_in_display (*tv);
5107 Editor::sync_track_view_list_and_routes ()
5109 track_views = TrackViewList (_routes->views ());
5111 _summary->set_dirty ();
5112 _group_tabs->set_dirty ();
5114 return false; // do not call again (until needed)
5118 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5120 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5125 /** Find a RouteTimeAxisView by the ID of its route */
5127 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5129 RouteTimeAxisView* v;
5131 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5132 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5133 if(v->route()->id() == id) {
5143 Editor::fit_route_group (RouteGroup *g)
5145 TrackViewList ts = axis_views_from_routes (g->route_list ());
5150 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5152 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5155 _session->cancel_audition ();
5159 if (_session->is_auditioning()) {
5160 _session->cancel_audition ();
5161 if (r == last_audition_region) {
5166 _session->audition_region (r);
5167 last_audition_region = r;
5172 Editor::hide_a_region (boost::shared_ptr<Region> r)
5174 r->set_hidden (true);
5178 Editor::show_a_region (boost::shared_ptr<Region> r)
5180 r->set_hidden (false);
5184 Editor::audition_region_from_region_list ()
5186 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5190 Editor::hide_region_from_region_list ()
5192 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5196 Editor::show_region_in_region_list ()
5198 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5202 Editor::step_edit_status_change (bool yn)
5205 start_step_editing ();
5207 stop_step_editing ();
5212 Editor::start_step_editing ()
5214 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5218 Editor::stop_step_editing ()
5220 step_edit_connection.disconnect ();
5224 Editor::check_step_edit ()
5226 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5227 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5229 mtv->check_step_edit ();
5233 return true; // do it again, till we stop
5237 Editor::scroll_press (Direction dir)
5239 ++_scroll_callbacks;
5241 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5242 /* delay the first auto-repeat */
5248 scroll_backward (1);
5256 scroll_up_one_track ();
5260 scroll_down_one_track ();
5264 /* do hacky auto-repeat */
5265 if (!_scroll_connection.connected ()) {
5267 _scroll_connection = Glib::signal_timeout().connect (
5268 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5271 _scroll_callbacks = 0;
5278 Editor::scroll_release ()
5280 _scroll_connection.disconnect ();
5283 /** Queue a change for the Editor viewport x origin to follow the playhead */
5285 Editor::reset_x_origin_to_follow_playhead ()
5287 framepos_t const frame = playhead_cursor->current_frame ();
5289 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5291 if (_session->transport_speed() < 0) {
5293 if (frame > (current_page_samples() / 2)) {
5294 center_screen (frame-(current_page_samples()/2));
5296 center_screen (current_page_samples()/2);
5303 if (frame < leftmost_frame) {
5305 if (_session->transport_rolling()) {
5306 /* rolling; end up with the playhead at the right of the page */
5307 l = frame - current_page_samples ();
5309 /* not rolling: end up with the playhead 1/4 of the way along the page */
5310 l = frame - current_page_samples() / 4;
5314 if (_session->transport_rolling()) {
5315 /* rolling: end up with the playhead on the left of the page */
5318 /* not rolling: end up with the playhead 3/4 of the way along the page */
5319 l = frame - 3 * current_page_samples() / 4;
5327 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5333 Editor::super_rapid_screen_update ()
5335 if (!_session || !_session->engine().running()) {
5339 /* METERING / MIXER STRIPS */
5341 /* update track meters, if required */
5342 if (is_mapped() && meters_running) {
5343 RouteTimeAxisView* rtv;
5344 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5345 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5346 rtv->fast_update ();
5351 /* and any current mixer strip */
5352 if (current_mixer_strip) {
5353 current_mixer_strip->fast_update ();
5356 /* PLAYHEAD AND VIEWPORT */
5358 framepos_t const frame = _session->audible_frame();
5360 /* There are a few reasons why we might not update the playhead / viewport stuff:
5362 * 1. we don't update things when there's a pending locate request, otherwise
5363 * when the editor requests a locate there is a chance that this method
5364 * will move the playhead before the locate request is processed, causing
5366 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5367 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5370 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5372 last_update_frame = frame;
5374 if (!_dragging_playhead) {
5375 playhead_cursor->set_position (frame);
5378 if (!_stationary_playhead) {
5380 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5381 /* We only do this if we aren't already
5382 handling a visual change (ie if
5383 pending_visual_change.being_handled is
5384 false) so that these requests don't stack
5385 up there are too many of them to handle in
5388 reset_x_origin_to_follow_playhead ();
5393 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5397 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5398 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5399 if (target <= 0.0) {
5402 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5403 target = (target * 0.15) + (current * 0.85);
5409 set_horizontal_position (current);
5418 Editor::session_going_away ()
5420 _have_idled = false;
5422 _session_connections.drop_connections ();
5424 super_rapid_screen_update_connection.disconnect ();
5426 selection->clear ();
5427 cut_buffer->clear ();
5429 clicked_regionview = 0;
5430 clicked_axisview = 0;
5431 clicked_routeview = 0;
5432 entered_regionview = 0;
5434 last_update_frame = 0;
5437 playhead_cursor->hide ();
5439 /* rip everything out of the list displays */
5443 _route_groups->clear ();
5445 /* do this first so that deleting a track doesn't reset cms to null
5446 and thus cause a leak.
5449 if (current_mixer_strip) {
5450 if (current_mixer_strip->get_parent() != 0) {
5451 global_hpacker.remove (*current_mixer_strip);
5453 delete current_mixer_strip;
5454 current_mixer_strip = 0;
5457 /* delete all trackviews */
5459 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5462 track_views.clear ();
5464 nudge_clock->set_session (0);
5466 editor_list_button.set_active(false);
5467 editor_list_button.set_sensitive(false);
5469 /* clear tempo/meter rulers */
5470 remove_metric_marks ();
5472 clear_marker_display ();
5474 stop_step_editing ();
5476 /* get rid of any existing editor mixer strip */
5478 WindowTitle title(Glib::get_application_name());
5479 title += _("Editor");
5481 set_title (title.get_string());
5483 SessionHandlePtr::session_going_away ();
5488 Editor::show_editor_list (bool yn)
5491 _the_notebook.show ();
5493 _the_notebook.hide ();
5498 Editor::change_region_layering_order (bool from_context_menu)
5500 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5502 if (!clicked_routeview) {
5503 if (layering_order_editor) {
5504 layering_order_editor->hide ();
5509 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5515 boost::shared_ptr<Playlist> pl = track->playlist();
5521 if (layering_order_editor == 0) {
5522 layering_order_editor = new RegionLayeringOrderEditor (*this);
5525 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5526 layering_order_editor->maybe_present ();
5530 Editor::update_region_layering_order_editor ()
5532 if (layering_order_editor && layering_order_editor->is_visible ()) {
5533 change_region_layering_order (true);
5538 Editor::setup_fade_images ()
5540 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5541 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5542 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5543 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5544 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5546 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5547 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5548 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5549 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5550 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5552 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5553 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5554 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5555 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5556 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5558 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5559 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5560 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5561 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5562 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5566 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5568 Editor::action_menu_item (std::string const & name)
5570 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5573 return *manage (a->create_menu_item ());
5577 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5579 EventBox* b = manage (new EventBox);
5580 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5581 Label* l = manage (new Label (name));
5585 _the_notebook.append_page (widget, *b);
5589 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5591 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5592 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5595 if (ev->type == GDK_2BUTTON_PRESS) {
5597 /* double-click on a notebook tab shrinks or expands the notebook */
5599 if (_notebook_shrunk) {
5600 if (pre_notebook_shrink_pane_width) {
5601 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5603 _notebook_shrunk = false;
5605 pre_notebook_shrink_pane_width = edit_pane.get_position();
5607 /* this expands the LHS of the edit pane to cover the notebook
5608 PAGE but leaves the tabs visible.
5610 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5611 _notebook_shrunk = true;
5619 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5621 using namespace Menu_Helpers;
5623 MenuList& items = _control_point_context_menu.items ();
5626 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5627 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5628 if (!can_remove_control_point (item)) {
5629 items.back().set_sensitive (false);
5632 _control_point_context_menu.popup (event->button.button, event->button.time);
5636 Editor::zoom_vertical_modifier_released()
5638 _stepping_axis_view = 0;
5642 Editor::ui_parameter_changed (string parameter)
5644 if (parameter == "icon-set") {
5645 while (!_cursor_stack.empty()) {
5646 _cursor_stack.pop();
5648 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5649 } else if (parameter == "draggable-playhead") {
5650 if (_verbose_cursor) {
5651 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());