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_LocationMarker();
392 location_range_color = ARDOUR_UI::config()->get_LocationRange();
393 location_cd_marker_color = ARDOUR_UI::config()->get_LocationCDMarker();
394 location_loop_color = ARDOUR_UI::config()->get_LocationLoop();
395 location_punch_color = ARDOUR_UI::config()->get_LocationPunch();
397 zoom_focus = ZoomFocusLeft;
398 _edit_point = EditAtMouse;
399 _internal_editing = false;
400 current_canvas_cursor = 0;
401 _visible_track_count = -1;
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 /* these are static location signals */
558 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
559 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
560 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
562 add_notebook_page (_("Regions"), _regions->widget ());
563 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
564 add_notebook_page (_("Snapshots"), _snapshots->widget ());
565 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
566 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
568 _the_notebook.set_show_tabs (true);
569 _the_notebook.set_scrollable (true);
570 _the_notebook.popup_disable ();
571 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
572 _the_notebook.show_all ();
574 _notebook_shrunk = false;
576 editor_summary_pane.pack1(edit_packer);
578 Button* summary_arrows_left_left = manage (new Button);
579 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
580 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
581 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 Button* summary_arrows_left_right = manage (new Button);
584 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
585 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
586 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
588 VBox* summary_arrows_left = manage (new VBox);
589 summary_arrows_left->pack_start (*summary_arrows_left_left);
590 summary_arrows_left->pack_start (*summary_arrows_left_right);
592 Button* summary_arrows_right_up = manage (new Button);
593 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
594 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
595 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
597 Button* summary_arrows_right_down = manage (new Button);
598 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
599 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
600 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
602 VBox* summary_arrows_right = manage (new VBox);
603 summary_arrows_right->pack_start (*summary_arrows_right_up);
604 summary_arrows_right->pack_start (*summary_arrows_right_down);
606 Frame* summary_frame = manage (new Frame);
607 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
609 summary_frame->add (*_summary);
610 summary_frame->show ();
612 _summary_hbox.pack_start (*summary_arrows_left, false, false);
613 _summary_hbox.pack_start (*summary_frame, true, true);
614 _summary_hbox.pack_start (*summary_arrows_right, false, false);
616 if (!ARDOUR::Profile->get_trx()) {
617 editor_summary_pane.pack2 (_summary_hbox);
620 edit_pane.pack1 (editor_summary_pane, true, true);
621 if (!ARDOUR::Profile->get_trx()) {
622 edit_pane.pack2 (_the_notebook, false, true);
625 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
627 /* XXX: editor_summary_pane might need similar to the edit_pane */
629 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
631 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
632 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
634 top_hbox.pack_start (toolbar_frame);
636 HBox *hbox = manage (new HBox);
637 hbox->pack_start (edit_pane, true, true);
639 global_vpacker.pack_start (top_hbox, false, false);
640 global_vpacker.pack_start (*hbox, true, true);
642 global_hpacker.pack_start (global_vpacker, true, true);
644 set_name ("EditorWindow");
645 add_accel_group (ActionManager::ui_manager->get_accel_group());
647 status_bar_hpacker.show ();
649 vpacker.pack_end (status_bar_hpacker, false, false);
650 vpacker.pack_end (global_hpacker, true, true);
652 /* register actions now so that set_state() can find them and set toggles/checks etc */
655 /* when we start using our own keybinding system for the editor, this
656 * will be uncommented
662 set_zoom_focus (zoom_focus);
663 set_visible_track_count (_visible_track_count);
664 _snap_type = SnapToBeat;
665 set_snap_to (_snap_type);
666 _snap_mode = SnapOff;
667 set_snap_mode (_snap_mode);
668 set_mouse_mode (MouseObject, true);
669 pre_internal_mouse_mode = MouseObject;
670 pre_internal_snap_type = _snap_type;
671 pre_internal_snap_mode = _snap_mode;
672 internal_snap_type = _snap_type;
673 internal_snap_mode = _snap_mode;
674 set_edit_point_preference (EditAtMouse, true);
676 _playlist_selector = new PlaylistSelector();
677 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
679 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
683 nudge_forward_button.set_name ("nudge button");
684 nudge_forward_button.set_image(::get_icon("nudge_right"));
686 nudge_backward_button.set_name ("nudge button");
687 nudge_backward_button.set_image(::get_icon("nudge_left"));
689 fade_context_menu.set_name ("ArdourContextMenu");
691 /* icons, titles, WM stuff */
693 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
694 Glib::RefPtr<Gdk::Pixbuf> icon;
696 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
697 window_icons.push_back (icon);
699 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
700 window_icons.push_back (icon);
702 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
703 window_icons.push_back (icon);
705 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
706 window_icons.push_back (icon);
708 if (!window_icons.empty()) {
709 // set_icon_list (window_icons);
710 set_default_icon_list (window_icons);
713 WindowTitle title(Glib::get_application_name());
714 title += _("Editor");
715 set_title (title.get_string());
716 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
719 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
721 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
722 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
724 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
726 /* allow external control surfaces/protocols to do various things */
728 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
729 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
730 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
731 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
732 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
733 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
734 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
735 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
736 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
737 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
738 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
739 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
740 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
741 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
743 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
744 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
745 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
746 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
747 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
749 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
751 /* problematic: has to return a value and thus cannot be x-thread */
753 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
755 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
756 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
758 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
760 _ignore_region_action = false;
761 _last_region_menu_was_main = false;
762 _popup_region_menu_item = 0;
764 _ignore_follow_edits = false;
766 _show_marker_lines = false;
768 /* Button bindings */
770 button_bindings = new Bindings;
772 XMLNode* node = button_settings();
774 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
775 button_bindings->load (**i);
781 /* grab current parameter state */
782 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
783 ARDOUR_UI::config()->map_parameters (pc);
785 setup_fade_images ();
792 delete button_bindings;
794 delete _route_groups;
795 delete _track_canvas_viewport;
801 Editor::button_settings () const
803 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
804 XMLNode* node = find_named_node (*settings, X_("Buttons"));
807 node = new XMLNode (X_("Buttons"));
814 Editor::add_toplevel_menu (Container& cont)
816 vpacker.pack_start (cont, false, false);
821 Editor::add_transport_frame (Container& cont)
823 if(ARDOUR::Profile->get_mixbus()) {
824 global_vpacker.pack_start (cont, false, false);
825 global_vpacker.reorder_child (cont, 0);
828 vpacker.pack_start (cont, false, false);
833 Editor::get_smart_mode () const
835 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
839 Editor::catch_vanishing_regionview (RegionView *rv)
841 /* note: the selection will take care of the vanishing
842 audioregionview by itself.
845 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
849 if (clicked_regionview == rv) {
850 clicked_regionview = 0;
853 if (entered_regionview == rv) {
854 set_entered_regionview (0);
857 if (!_all_region_actions_sensitized) {
858 sensitize_all_region_actions (true);
863 Editor::set_entered_regionview (RegionView* rv)
865 if (rv == entered_regionview) {
869 if (entered_regionview) {
870 entered_regionview->exited ();
873 entered_regionview = rv;
875 if (entered_regionview != 0) {
876 entered_regionview->entered (internal_editing ());
879 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
880 /* This RegionView entry might have changed what region actions
881 are allowed, so sensitize them all in case a key is pressed.
883 sensitize_all_region_actions (true);
888 Editor::set_entered_track (TimeAxisView* tav)
891 entered_track->exited ();
897 entered_track->entered ();
902 Editor::show_window ()
904 if (!is_visible ()) {
908 /* XXX: this is a bit unfortunate; it would probably
909 be nicer if we could just call show () above rather
910 than needing the show_all ()
913 /* re-hide stuff if necessary */
914 editor_list_button_toggled ();
915 parameter_changed ("show-summary");
916 parameter_changed ("show-group-tabs");
917 parameter_changed ("show-zoom-tools");
919 /* now reset all audio_time_axis heights, because widgets might need
925 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
926 tv = (static_cast<TimeAxisView*>(*i));
930 if (current_mixer_strip) {
931 current_mixer_strip->hide_things ();
932 current_mixer_strip->parameter_changed ("mixer-element-visibility");
940 Editor::instant_save ()
942 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
947 _session->add_instant_xml(get_state());
949 Config->add_instant_xml(get_state());
954 Editor::control_vertical_zoom_in_all ()
956 tav_zoom_smooth (false, true);
960 Editor::control_vertical_zoom_out_all ()
962 tav_zoom_smooth (true, true);
966 Editor::control_vertical_zoom_in_selected ()
968 tav_zoom_smooth (false, false);
972 Editor::control_vertical_zoom_out_selected ()
974 tav_zoom_smooth (true, false);
978 Editor::control_view (uint32_t view)
980 goto_visual_state (view);
984 Editor::control_unselect ()
986 selection->clear_tracks ();
990 Editor::control_select (uint32_t rid, Selection::Operation op)
992 /* handles the (static) signal from the ControlProtocol class that
993 * requests setting the selected track to a given RID
1000 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1006 TimeAxisView* tav = axis_view_from_route (r);
1010 case Selection::Add:
1011 selection->add (tav);
1013 case Selection::Toggle:
1014 selection->toggle (tav);
1016 case Selection::Extend:
1018 case Selection::Set:
1019 selection->set (tav);
1023 selection->clear_tracks ();
1028 Editor::control_step_tracks_up ()
1030 scroll_tracks_up_line ();
1034 Editor::control_step_tracks_down ()
1036 scroll_tracks_down_line ();
1040 Editor::control_scroll (float fraction)
1042 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1048 double step = fraction * current_page_samples();
1051 _control_scroll_target is an optional<T>
1053 it acts like a pointer to an framepos_t, with
1054 a operator conversion to boolean to check
1055 that it has a value could possibly use
1056 playhead_cursor->current_frame to store the
1057 value and a boolean in the class to know
1058 when it's out of date
1061 if (!_control_scroll_target) {
1062 _control_scroll_target = _session->transport_frame();
1063 _dragging_playhead = true;
1066 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1067 *_control_scroll_target = 0;
1068 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1069 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1071 *_control_scroll_target += (framepos_t) floor (step);
1074 /* move visuals, we'll catch up with it later */
1076 playhead_cursor->set_position (*_control_scroll_target);
1077 UpdateAllTransportClocks (*_control_scroll_target);
1079 if (*_control_scroll_target > (current_page_samples() / 2)) {
1080 /* try to center PH in window */
1081 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1087 Now we do a timeout to actually bring the session to the right place
1088 according to the playhead. This is to avoid reading disk buffers on every
1089 call to control_scroll, which is driven by ScrollTimeline and therefore
1090 probably by a control surface wheel which can generate lots of events.
1092 /* cancel the existing timeout */
1094 control_scroll_connection.disconnect ();
1096 /* add the next timeout */
1098 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1102 Editor::deferred_control_scroll (framepos_t /*target*/)
1104 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1105 // reset for next stream
1106 _control_scroll_target = boost::none;
1107 _dragging_playhead = false;
1112 Editor::access_action (std::string action_group, std::string action_item)
1118 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1121 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1129 Editor::on_realize ()
1131 Window::on_realize ();
1134 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1135 start_lock_event_timing ();
1138 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1142 Editor::start_lock_event_timing ()
1144 /* check if we should lock the GUI every 30 seconds */
1146 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1150 Editor::generic_event_handler (GdkEvent* ev)
1153 case GDK_BUTTON_PRESS:
1154 case GDK_BUTTON_RELEASE:
1155 case GDK_MOTION_NOTIFY:
1157 case GDK_KEY_RELEASE:
1158 gettimeofday (&last_event_time, 0);
1161 case GDK_LEAVE_NOTIFY:
1162 switch (ev->crossing.detail) {
1163 case GDK_NOTIFY_UNKNOWN:
1164 case GDK_NOTIFY_INFERIOR:
1165 case GDK_NOTIFY_ANCESTOR:
1167 case GDK_NOTIFY_VIRTUAL:
1168 case GDK_NOTIFY_NONLINEAR:
1169 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1170 /* leaving window, so reset focus, thus ending any and
1171 all text entry operations.
1186 Editor::lock_timeout_callback ()
1188 struct timeval now, delta;
1190 gettimeofday (&now, 0);
1192 timersub (&now, &last_event_time, &delta);
1194 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1196 /* don't call again. Returning false will effectively
1197 disconnect us from the timer callback.
1199 unlock() will call start_lock_event_timing() to get things
1209 Editor::map_position_change (framepos_t frame)
1211 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1213 if (_session == 0) {
1217 if (_follow_playhead) {
1218 center_screen (frame);
1221 playhead_cursor->set_position (frame);
1225 Editor::center_screen (framepos_t frame)
1227 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1229 /* if we're off the page, then scroll.
1232 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1233 center_screen_internal (frame, page);
1238 Editor::center_screen_internal (framepos_t frame, float page)
1243 frame -= (framepos_t) page;
1248 reset_x_origin (frame);
1253 Editor::update_title ()
1255 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1258 bool dirty = _session->dirty();
1260 string session_name;
1262 if (_session->snap_name() != _session->name()) {
1263 session_name = _session->snap_name();
1265 session_name = _session->name();
1269 session_name = "*" + session_name;
1272 WindowTitle title(session_name);
1273 title += Glib::get_application_name();
1274 set_title (title.get_string());
1276 /* ::session_going_away() will have taken care of it */
1281 Editor::set_session (Session *t)
1283 SessionHandlePtr::set_session (t);
1289 _playlist_selector->set_session (_session);
1290 nudge_clock->set_session (_session);
1291 _summary->set_session (_session);
1292 _group_tabs->set_session (_session);
1293 _route_groups->set_session (_session);
1294 _regions->set_session (_session);
1295 _snapshots->set_session (_session);
1296 _routes->set_session (_session);
1297 _locations->set_session (_session);
1299 if (rhythm_ferret) {
1300 rhythm_ferret->set_session (_session);
1303 if (analysis_window) {
1304 analysis_window->set_session (_session);
1308 sfbrowser->set_session (_session);
1311 compute_fixed_ruler_scale ();
1313 /* Make sure we have auto loop and auto punch ranges */
1315 Location* loc = _session->locations()->auto_loop_location();
1317 loc->set_name (_("Loop"));
1320 loc = _session->locations()->auto_punch_location();
1323 loc->set_name (_("Punch"));
1326 refresh_location_display ();
1328 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1329 the selected Marker; this needs the LocationMarker list to be available.
1331 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1332 set_state (*node, Stateful::loading_state_version);
1334 /* catch up with the playhead */
1336 _session->request_locate (playhead_cursor->current_frame ());
1337 _pending_initial_locate = true;
1341 /* These signals can all be emitted by a non-GUI thread. Therefore the
1342 handlers for them must not attempt to directly interact with the GUI,
1343 but use PBD::Signal<T>::connect() which accepts an event loop
1344 ("context") where the handler will be asked to run.
1347 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1348 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1349 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1350 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1351 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1352 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1353 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1354 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1355 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1356 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1357 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1358 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1359 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1360 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1362 playhead_cursor->show ();
1364 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1365 Config->map_parameters (pc);
1366 _session->config.map_parameters (pc);
1368 restore_ruler_visibility ();
1369 //tempo_map_changed (PropertyChange (0));
1370 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1372 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1373 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1376 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1377 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1380 switch (_snap_type) {
1381 case SnapToRegionStart:
1382 case SnapToRegionEnd:
1383 case SnapToRegionSync:
1384 case SnapToRegionBoundary:
1385 build_region_boundary_cache ();
1392 /* register for undo history */
1393 _session->register_with_memento_command_factory(id(), this);
1395 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1397 start_updating_meters ();
1401 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1403 if (a->get_name() == "RegionMenu") {
1404 /* When the main menu's region menu is opened, we setup the actions so that they look right
1405 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1406 so we resensitize all region actions when the entered regionview or the region selection
1407 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1408 happens after the region context menu is opened. So we set a flag here, too.
1412 sensitize_the_right_region_actions ();
1413 _last_region_menu_was_main = true;
1418 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1420 using namespace Menu_Helpers;
1422 void (Editor::*emf)(FadeShape);
1423 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1426 images = &_xfade_in_images;
1427 emf = &Editor::set_fade_in_shape;
1429 images = &_xfade_out_images;
1430 emf = &Editor::set_fade_out_shape;
1435 _("Linear (for highly correlated material)"),
1436 *(*images)[FadeLinear],
1437 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1441 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1445 _("Constant power"),
1446 *(*images)[FadeConstantPower],
1447 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1450 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1455 *(*images)[FadeSymmetric],
1456 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1460 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1465 *(*images)[FadeSlow],
1466 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1469 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1474 *(*images)[FadeFast],
1475 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1481 /** Pop up a context menu for when the user clicks on a start crossfade */
1483 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1485 using namespace Menu_Helpers;
1486 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1489 MenuList& items (xfade_in_context_menu.items());
1492 if (arv->audio_region()->fade_in_active()) {
1493 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1495 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1498 items.push_back (SeparatorElem());
1499 fill_xfade_menu (items, true);
1501 xfade_in_context_menu.popup (button, time);
1504 /** Pop up a context menu for when the user clicks on an end crossfade */
1506 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1508 using namespace Menu_Helpers;
1509 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1512 MenuList& items (xfade_out_context_menu.items());
1515 if (arv->audio_region()->fade_out_active()) {
1516 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1518 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1521 items.push_back (SeparatorElem());
1522 fill_xfade_menu (items, false);
1524 xfade_out_context_menu.popup (button, time);
1528 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1530 using namespace Menu_Helpers;
1531 Menu* (Editor::*build_menu_function)();
1534 switch (item_type) {
1536 case RegionViewName:
1537 case RegionViewNameHighlight:
1538 case LeftFrameHandle:
1539 case RightFrameHandle:
1540 if (with_selection) {
1541 build_menu_function = &Editor::build_track_selection_context_menu;
1543 build_menu_function = &Editor::build_track_region_context_menu;
1548 if (with_selection) {
1549 build_menu_function = &Editor::build_track_selection_context_menu;
1551 build_menu_function = &Editor::build_track_context_menu;
1556 if (clicked_routeview->track()) {
1557 build_menu_function = &Editor::build_track_context_menu;
1559 build_menu_function = &Editor::build_track_bus_context_menu;
1564 /* probably shouldn't happen but if it does, we don't care */
1568 menu = (this->*build_menu_function)();
1569 menu->set_name ("ArdourContextMenu");
1571 /* now handle specific situations */
1573 switch (item_type) {
1575 case RegionViewName:
1576 case RegionViewNameHighlight:
1577 case LeftFrameHandle:
1578 case RightFrameHandle:
1579 if (!with_selection) {
1580 if (region_edit_menu_split_item) {
1581 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1582 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1584 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1587 if (region_edit_menu_split_multichannel_item) {
1588 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1589 region_edit_menu_split_multichannel_item->set_sensitive (true);
1591 region_edit_menu_split_multichannel_item->set_sensitive (false);
1604 /* probably shouldn't happen but if it does, we don't care */
1608 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1610 /* Bounce to disk */
1612 using namespace Menu_Helpers;
1613 MenuList& edit_items = menu->items();
1615 edit_items.push_back (SeparatorElem());
1617 switch (clicked_routeview->audio_track()->freeze_state()) {
1618 case AudioTrack::NoFreeze:
1619 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1622 case AudioTrack::Frozen:
1623 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1626 case AudioTrack::UnFrozen:
1627 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1633 if (item_type == StreamItem && clicked_routeview) {
1634 clicked_routeview->build_underlay_menu(menu);
1637 /* When the region menu is opened, we setup the actions so that they look right
1640 sensitize_the_right_region_actions ();
1641 _last_region_menu_was_main = false;
1643 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1644 menu->popup (button, time);
1648 Editor::build_track_context_menu ()
1650 using namespace Menu_Helpers;
1652 MenuList& edit_items = track_context_menu.items();
1655 add_dstream_context_items (edit_items);
1656 return &track_context_menu;
1660 Editor::build_track_bus_context_menu ()
1662 using namespace Menu_Helpers;
1664 MenuList& edit_items = track_context_menu.items();
1667 add_bus_context_items (edit_items);
1668 return &track_context_menu;
1672 Editor::build_track_region_context_menu ()
1674 using namespace Menu_Helpers;
1675 MenuList& edit_items = track_region_context_menu.items();
1678 /* we've just cleared the track region context menu, so the menu that these
1679 two items were on will have disappeared; stop them dangling.
1681 region_edit_menu_split_item = 0;
1682 region_edit_menu_split_multichannel_item = 0;
1684 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1687 boost::shared_ptr<Track> tr;
1688 boost::shared_ptr<Playlist> pl;
1690 if ((tr = rtv->track())) {
1691 add_region_context_items (edit_items, tr);
1695 add_dstream_context_items (edit_items);
1697 return &track_region_context_menu;
1701 Editor::analyze_region_selection ()
1703 if (analysis_window == 0) {
1704 analysis_window = new AnalysisWindow();
1707 analysis_window->set_session(_session);
1709 analysis_window->show_all();
1712 analysis_window->set_regionmode();
1713 analysis_window->analyze();
1715 analysis_window->present();
1719 Editor::analyze_range_selection()
1721 if (analysis_window == 0) {
1722 analysis_window = new AnalysisWindow();
1725 analysis_window->set_session(_session);
1727 analysis_window->show_all();
1730 analysis_window->set_rangemode();
1731 analysis_window->analyze();
1733 analysis_window->present();
1737 Editor::build_track_selection_context_menu ()
1739 using namespace Menu_Helpers;
1740 MenuList& edit_items = track_selection_context_menu.items();
1741 edit_items.clear ();
1743 add_selection_context_items (edit_items);
1744 // edit_items.push_back (SeparatorElem());
1745 // add_dstream_context_items (edit_items);
1747 return &track_selection_context_menu;
1751 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1753 using namespace Menu_Helpers;
1755 /* OK, stick the region submenu at the top of the list, and then add
1759 RegionSelection rs = get_regions_from_selection_and_entered ();
1761 string::size_type pos = 0;
1762 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1764 /* we have to hack up the region name because "_" has a special
1765 meaning for menu titles.
1768 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1769 menu_item_name.replace (pos, 1, "__");
1773 if (_popup_region_menu_item == 0) {
1774 _popup_region_menu_item = new MenuItem (menu_item_name);
1775 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1776 _popup_region_menu_item->show ();
1778 _popup_region_menu_item->set_label (menu_item_name);
1781 const framepos_t position = get_preferred_edit_position (false, true);
1783 edit_items.push_back (*_popup_region_menu_item);
1784 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1785 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1787 edit_items.push_back (SeparatorElem());
1790 /** Add context menu items relevant to selection ranges.
1791 * @param edit_items List to add the items to.
1794 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1796 using namespace Menu_Helpers;
1798 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1799 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1801 edit_items.push_back (SeparatorElem());
1802 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1804 edit_items.push_back (SeparatorElem());
1805 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1807 edit_items.push_back (SeparatorElem());
1809 edit_items.push_back (
1811 _("Move Range Start to Previous Region Boundary"),
1812 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1816 edit_items.push_back (
1818 _("Move Range Start to Next Region Boundary"),
1819 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1823 edit_items.push_back (
1825 _("Move Range End to Previous Region Boundary"),
1826 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1830 edit_items.push_back (
1832 _("Move Range End to Next Region Boundary"),
1833 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1837 edit_items.push_back (SeparatorElem());
1838 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1839 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1841 edit_items.push_back (SeparatorElem());
1842 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1844 edit_items.push_back (SeparatorElem());
1845 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1846 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1848 edit_items.push_back (SeparatorElem());
1849 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1851 edit_items.push_back (SeparatorElem());
1852 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1853 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1854 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1856 edit_items.push_back (SeparatorElem());
1857 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1858 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1859 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1860 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1861 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1862 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1863 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1869 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1871 using namespace Menu_Helpers;
1875 Menu *play_menu = manage (new Menu);
1876 MenuList& play_items = play_menu->items();
1877 play_menu->set_name ("ArdourContextMenu");
1879 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1880 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1881 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1882 play_items.push_back (SeparatorElem());
1883 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1885 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1889 Menu *select_menu = manage (new Menu);
1890 MenuList& select_items = select_menu->items();
1891 select_menu->set_name ("ArdourContextMenu");
1893 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1894 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1895 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1896 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1897 select_items.push_back (SeparatorElem());
1898 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1899 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1900 select_items.push_back (SeparatorElem());
1901 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1902 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1903 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1904 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1905 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1906 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1907 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1909 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1913 Menu *cutnpaste_menu = manage (new Menu);
1914 MenuList& cutnpaste_items = cutnpaste_menu->items();
1915 cutnpaste_menu->set_name ("ArdourContextMenu");
1917 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1918 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1919 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1921 cutnpaste_items.push_back (SeparatorElem());
1923 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1924 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1926 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1928 /* Adding new material */
1930 edit_items.push_back (SeparatorElem());
1931 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1932 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1936 Menu *nudge_menu = manage (new Menu());
1937 MenuList& nudge_items = nudge_menu->items();
1938 nudge_menu->set_name ("ArdourContextMenu");
1940 edit_items.push_back (SeparatorElem());
1941 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1942 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1943 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1944 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1946 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1950 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1952 using namespace Menu_Helpers;
1956 Menu *play_menu = manage (new Menu);
1957 MenuList& play_items = play_menu->items();
1958 play_menu->set_name ("ArdourContextMenu");
1960 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1961 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1962 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1966 Menu *select_menu = manage (new Menu);
1967 MenuList& select_items = select_menu->items();
1968 select_menu->set_name ("ArdourContextMenu");
1970 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1971 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1972 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1973 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1974 select_items.push_back (SeparatorElem());
1975 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1976 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1977 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1978 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1980 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1984 Menu *cutnpaste_menu = manage (new Menu);
1985 MenuList& cutnpaste_items = cutnpaste_menu->items();
1986 cutnpaste_menu->set_name ("ArdourContextMenu");
1988 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1989 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1990 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1992 Menu *nudge_menu = manage (new Menu());
1993 MenuList& nudge_items = nudge_menu->items();
1994 nudge_menu->set_name ("ArdourContextMenu");
1996 edit_items.push_back (SeparatorElem());
1997 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1998 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1999 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2000 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2002 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2006 Editor::snap_type() const
2012 Editor::snap_mode() const
2018 Editor::set_snap_to (SnapType st)
2020 unsigned int snap_ind = (unsigned int)st;
2024 if (snap_ind > snap_type_strings.size() - 1) {
2026 _snap_type = (SnapType)snap_ind;
2029 string str = snap_type_strings[snap_ind];
2031 if (str != snap_type_selector.get_text()) {
2032 snap_type_selector.set_text (str);
2037 switch (_snap_type) {
2038 case SnapToBeatDiv128:
2039 case SnapToBeatDiv64:
2040 case SnapToBeatDiv32:
2041 case SnapToBeatDiv28:
2042 case SnapToBeatDiv24:
2043 case SnapToBeatDiv20:
2044 case SnapToBeatDiv16:
2045 case SnapToBeatDiv14:
2046 case SnapToBeatDiv12:
2047 case SnapToBeatDiv10:
2048 case SnapToBeatDiv8:
2049 case SnapToBeatDiv7:
2050 case SnapToBeatDiv6:
2051 case SnapToBeatDiv5:
2052 case SnapToBeatDiv4:
2053 case SnapToBeatDiv3:
2054 case SnapToBeatDiv2: {
2055 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2056 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2058 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2059 current_bbt_points_begin, current_bbt_points_end);
2060 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2061 current_bbt_points_begin, current_bbt_points_end);
2062 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2066 case SnapToRegionStart:
2067 case SnapToRegionEnd:
2068 case SnapToRegionSync:
2069 case SnapToRegionBoundary:
2070 build_region_boundary_cache ();
2078 SnapChanged (); /* EMIT SIGNAL */
2082 Editor::set_snap_mode (SnapMode mode)
2084 string str = snap_mode_strings[(int)mode];
2086 if (_internal_editing) {
2087 internal_snap_mode = mode;
2089 pre_internal_snap_mode = mode;
2094 if (str != snap_mode_selector.get_text ()) {
2095 snap_mode_selector.set_text (str);
2101 Editor::set_edit_point_preference (EditPoint ep, bool force)
2103 bool changed = (_edit_point != ep);
2106 string str = edit_point_strings[(int)ep];
2108 if (Profile->get_mixbus())
2109 if (ep == EditAtSelectedMarker)
2110 ep = EditAtPlayhead;
2112 if (str != edit_point_selector.get_text ()) {
2113 edit_point_selector.set_text (str);
2116 reset_canvas_cursor ();
2118 if (!force && !changed) {
2122 const char* action=NULL;
2124 switch (_edit_point) {
2125 case EditAtPlayhead:
2126 action = "edit-at-playhead";
2128 case EditAtSelectedMarker:
2129 action = "edit-at-marker";
2132 action = "edit-at-mouse";
2136 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2138 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2142 bool in_track_canvas;
2144 if (!mouse_frame (foo, in_track_canvas)) {
2145 in_track_canvas = false;
2148 reset_canvas_action_sensitivity (in_track_canvas);
2154 Editor::set_state (const XMLNode& node, int /*version*/)
2156 const XMLProperty* prop;
2163 g.base_width = default_width;
2164 g.base_height = default_height;
2168 if ((geometry = find_named_node (node, "geometry")) != 0) {
2172 if ((prop = geometry->property("x_size")) == 0) {
2173 prop = geometry->property ("x-size");
2176 g.base_width = atoi(prop->value());
2178 if ((prop = geometry->property("y_size")) == 0) {
2179 prop = geometry->property ("y-size");
2182 g.base_height = atoi(prop->value());
2185 if ((prop = geometry->property ("x_pos")) == 0) {
2186 prop = geometry->property ("x-pos");
2189 x = atoi (prop->value());
2192 if ((prop = geometry->property ("y_pos")) == 0) {
2193 prop = geometry->property ("y-pos");
2196 y = atoi (prop->value());
2200 set_default_size (g.base_width, g.base_height);
2203 if (_session && (prop = node.property ("playhead"))) {
2205 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2207 playhead_cursor->set_position (pos);
2209 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2210 playhead_cursor->set_position (0);
2213 playhead_cursor->set_position (0);
2216 if ((prop = node.property ("mixer-width"))) {
2217 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2220 if ((prop = node.property ("zoom-focus"))) {
2221 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2224 if ((prop = node.property ("zoom"))) {
2225 /* older versions of ardour used floating point samples_per_pixel */
2226 double f = PBD::atof (prop->value());
2227 reset_zoom (llrintf (f));
2229 reset_zoom (samples_per_pixel);
2232 if ((prop = node.property ("visible-track-count"))) {
2233 set_visible_track_count (PBD::atoi (prop->value()));
2236 if ((prop = node.property ("snap-to"))) {
2237 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2240 if ((prop = node.property ("snap-mode"))) {
2241 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2244 if ((prop = node.property ("internal-snap-to"))) {
2245 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2248 if ((prop = node.property ("internal-snap-mode"))) {
2249 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2252 if ((prop = node.property ("pre-internal-snap-to"))) {
2253 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2257 if ((prop = node.property ("pre-internal-snap-mode"))) {
2258 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2261 if ((prop = node.property ("mouse-mode"))) {
2262 MouseMode m = str2mousemode(prop->value());
2263 set_mouse_mode (m, true);
2265 set_mouse_mode (MouseObject, true);
2268 if ((prop = node.property ("left-frame")) != 0) {
2270 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2274 reset_x_origin (pos);
2278 if ((prop = node.property ("y-origin")) != 0) {
2279 reset_y_origin (atof (prop->value ()));
2282 if ((prop = node.property ("internal-edit"))) {
2283 bool yn = string_is_affirmative (prop->value());
2284 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2286 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2287 tact->set_active (!yn);
2288 tact->set_active (yn);
2292 if ((prop = node.property ("join-object-range"))) {
2293 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2294 bool yn = string_is_affirmative (prop->value());
2296 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2297 tact->set_active (!yn);
2298 tact->set_active (yn);
2300 set_mouse_mode(mouse_mode, true);
2303 if ((prop = node.property ("edit-point"))) {
2304 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2307 if ((prop = node.property ("show-measures"))) {
2308 bool yn = string_is_affirmative (prop->value());
2309 _show_measures = yn;
2310 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2312 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2313 /* do it twice to force the change */
2314 tact->set_active (!yn);
2315 tact->set_active (yn);
2319 if ((prop = node.property ("follow-playhead"))) {
2320 bool yn = string_is_affirmative (prop->value());
2321 set_follow_playhead (yn);
2322 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2324 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2325 if (tact->get_active() != yn) {
2326 tact->set_active (yn);
2331 if ((prop = node.property ("stationary-playhead"))) {
2332 bool yn = string_is_affirmative (prop->value());
2333 set_stationary_playhead (yn);
2334 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2336 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2337 if (tact->get_active() != yn) {
2338 tact->set_active (yn);
2343 if ((prop = node.property ("region-list-sort-type"))) {
2344 RegionListSortType st;
2345 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2348 if ((prop = node.property ("show-editor-mixer"))) {
2350 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2353 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2354 bool yn = string_is_affirmative (prop->value());
2356 /* do it twice to force the change */
2358 tact->set_active (!yn);
2359 tact->set_active (yn);
2362 if ((prop = node.property ("show-editor-list"))) {
2364 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2367 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2368 bool yn = string_is_affirmative (prop->value());
2370 /* do it twice to force the change */
2372 tact->set_active (!yn);
2373 tact->set_active (yn);
2376 if ((prop = node.property (X_("editor-list-page")))) {
2377 _the_notebook.set_current_page (atoi (prop->value ()));
2380 if ((prop = node.property (X_("show-marker-lines")))) {
2381 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2383 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2384 bool yn = string_is_affirmative (prop->value ());
2386 tact->set_active (!yn);
2387 tact->set_active (yn);
2390 XMLNodeList children = node.children ();
2391 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2392 selection->set_state (**i, Stateful::current_state_version);
2393 _regions->set_state (**i);
2396 if ((prop = node.property ("maximised"))) {
2397 bool yn = string_is_affirmative (prop->value());
2398 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2400 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2401 bool fs = tact && tact->get_active();
2403 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2407 if ((prop = node.property ("nudge-clock-value"))) {
2409 sscanf (prop->value().c_str(), "%" PRId64, &f);
2410 nudge_clock->set (f);
2412 nudge_clock->set_mode (AudioClock::Timecode);
2413 nudge_clock->set (_session->frame_rate() * 5, true);
2420 Editor::get_state ()
2422 XMLNode* node = new XMLNode ("Editor");
2425 id().print (buf, sizeof (buf));
2426 node->add_property ("id", buf);
2428 if (is_realized()) {
2429 Glib::RefPtr<Gdk::Window> win = get_window();
2431 int x, y, width, height;
2432 win->get_root_origin(x, y);
2433 win->get_size(width, height);
2435 XMLNode* geometry = new XMLNode ("geometry");
2437 snprintf(buf, sizeof(buf), "%d", width);
2438 geometry->add_property("x-size", string(buf));
2439 snprintf(buf, sizeof(buf), "%d", height);
2440 geometry->add_property("y-size", string(buf));
2441 snprintf(buf, sizeof(buf), "%d", x);
2442 geometry->add_property("x-pos", string(buf));
2443 snprintf(buf, sizeof(buf), "%d", y);
2444 geometry->add_property("y-pos", string(buf));
2445 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2446 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2447 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2448 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2449 geometry->add_property("edit-vertical-pane-pos", string(buf));
2451 node->add_child_nocopy (*geometry);
2454 maybe_add_mixer_strip_width (*node);
2456 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2458 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2459 node->add_property ("zoom", buf);
2460 node->add_property ("snap-to", enum_2_string (_snap_type));
2461 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2462 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2463 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2464 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2465 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2466 node->add_property ("edit-point", enum_2_string (_edit_point));
2467 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2468 node->add_property ("visible-track-count", buf);
2470 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2471 node->add_property ("playhead", buf);
2472 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2473 node->add_property ("left-frame", buf);
2474 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2475 node->add_property ("y-origin", buf);
2477 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2478 node->add_property ("maximised", _maximised ? "yes" : "no");
2479 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2480 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2481 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2482 node->add_property ("mouse-mode", enum2str(mouse_mode));
2483 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2484 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2486 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2488 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2489 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2492 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2494 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2498 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2499 node->add_property (X_("editor-list-page"), buf);
2501 if (button_bindings) {
2502 XMLNode* bb = new XMLNode (X_("Buttons"));
2503 button_bindings->save (*bb);
2504 node->add_child_nocopy (*bb);
2507 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2509 node->add_child_nocopy (selection->get_state ());
2510 node->add_child_nocopy (_regions->get_state ());
2512 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2513 node->add_property ("nudge-clock-value", buf);
2518 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2519 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2521 * @return pair: TimeAxisView that y is over, layer index.
2523 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2524 * in stacked or expanded region display mode, otherwise 0.
2526 std::pair<TimeAxisView *, double>
2527 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2529 if (!trackview_relative_offset) {
2530 y -= _trackview_group->canvas_origin().y;
2534 return std::make_pair ( (TimeAxisView *) 0, 0);
2537 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2539 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2546 return std::make_pair ( (TimeAxisView *) 0, 0);
2549 /** Snap a position to the grid, if appropriate, taking into account current
2550 * grid settings and also the state of any snap modifier keys that may be pressed.
2551 * @param start Position to snap.
2552 * @param event Event to get current key modifier information from, or 0.
2555 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2557 if (!_session || !event) {
2561 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2562 if (_snap_mode == SnapOff) {
2563 snap_to_internal (start, direction, for_mark);
2566 if (_snap_mode != SnapOff) {
2567 snap_to_internal (start, direction, for_mark);
2573 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2575 if (!_session || _snap_mode == SnapOff) {
2579 snap_to_internal (start, direction, for_mark);
2583 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2585 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2586 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2588 switch (_snap_type) {
2589 case SnapToTimecodeFrame:
2590 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2591 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2593 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2597 case SnapToTimecodeSeconds:
2598 if (_session->config.get_timecode_offset_negative()) {
2599 start += _session->config.get_timecode_offset ();
2601 start -= _session->config.get_timecode_offset ();
2603 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2604 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2606 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2609 if (_session->config.get_timecode_offset_negative()) {
2610 start -= _session->config.get_timecode_offset ();
2612 start += _session->config.get_timecode_offset ();
2616 case SnapToTimecodeMinutes:
2617 if (_session->config.get_timecode_offset_negative()) {
2618 start += _session->config.get_timecode_offset ();
2620 start -= _session->config.get_timecode_offset ();
2622 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2623 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2625 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2627 if (_session->config.get_timecode_offset_negative()) {
2628 start -= _session->config.get_timecode_offset ();
2630 start += _session->config.get_timecode_offset ();
2634 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2640 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2642 const framepos_t one_second = _session->frame_rate();
2643 const framepos_t one_minute = _session->frame_rate() * 60;
2644 framepos_t presnap = start;
2648 switch (_snap_type) {
2649 case SnapToTimecodeFrame:
2650 case SnapToTimecodeSeconds:
2651 case SnapToTimecodeMinutes:
2652 return timecode_snap_to_internal (start, direction, for_mark);
2655 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2656 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2658 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2663 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2664 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2666 start = (framepos_t) floor ((double) start / one_second) * one_second;
2671 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2672 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2674 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2679 start = _session->tempo_map().round_to_bar (start, direction);
2683 start = _session->tempo_map().round_to_beat (start, direction);
2686 case SnapToBeatDiv128:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2689 case SnapToBeatDiv64:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2692 case SnapToBeatDiv32:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2695 case SnapToBeatDiv28:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2698 case SnapToBeatDiv24:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2701 case SnapToBeatDiv20:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2704 case SnapToBeatDiv16:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2707 case SnapToBeatDiv14:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2710 case SnapToBeatDiv12:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2713 case SnapToBeatDiv10:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2716 case SnapToBeatDiv8:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2719 case SnapToBeatDiv7:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2722 case SnapToBeatDiv6:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2725 case SnapToBeatDiv5:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2728 case SnapToBeatDiv4:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2731 case SnapToBeatDiv3:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2734 case SnapToBeatDiv2:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2743 _session->locations()->marks_either_side (start, before, after);
2745 if (before == max_framepos && after == max_framepos) {
2746 /* No marks to snap to, so just don't snap */
2748 } else if (before == max_framepos) {
2750 } else if (after == max_framepos) {
2752 } else if (before != max_framepos && after != max_framepos) {
2753 /* have before and after */
2754 if ((start - before) < (after - start)) {
2763 case SnapToRegionStart:
2764 case SnapToRegionEnd:
2765 case SnapToRegionSync:
2766 case SnapToRegionBoundary:
2767 if (!region_boundary_cache.empty()) {
2769 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2770 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2772 if (direction > 0) {
2773 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2775 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2778 if (next != region_boundary_cache.begin ()) {
2783 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2784 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2786 if (start > (p + n) / 2) {
2795 switch (_snap_mode) {
2801 if (presnap > start) {
2802 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2806 } else if (presnap < start) {
2807 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2813 /* handled at entry */
2821 Editor::setup_toolbar ()
2823 HBox* mode_box = manage(new HBox);
2824 mode_box->set_border_width (2);
2825 mode_box->set_spacing(2);
2827 HBox* mouse_mode_box = manage (new HBox);
2828 HBox* mouse_mode_hbox = manage (new HBox);
2829 VBox* mouse_mode_vbox = manage (new VBox);
2830 Alignment* mouse_mode_align = manage (new Alignment);
2832 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2833 mouse_mode_size_group->add_widget (smart_mode_button);
2834 mouse_mode_size_group->add_widget (mouse_move_button);
2835 mouse_mode_size_group->add_widget (mouse_cut_button);
2836 mouse_mode_size_group->add_widget (mouse_select_button);
2837 mouse_mode_size_group->add_widget (mouse_gain_button);
2838 mouse_mode_size_group->add_widget (mouse_timefx_button);
2839 mouse_mode_size_group->add_widget (mouse_audition_button);
2840 mouse_mode_size_group->add_widget (mouse_draw_button);
2841 mouse_mode_size_group->add_widget (internal_edit_button);
2843 mouse_mode_size_group->add_widget (zoom_in_button);
2844 mouse_mode_size_group->add_widget (zoom_out_button);
2845 mouse_mode_size_group->add_widget (zoom_preset_selector);
2846 mouse_mode_size_group->add_widget (zoom_out_full_button);
2847 mouse_mode_size_group->add_widget (zoom_focus_selector);
2849 mouse_mode_size_group->add_widget (tav_shrink_button);
2850 mouse_mode_size_group->add_widget (tav_expand_button);
2851 mouse_mode_size_group->add_widget (visible_tracks_selector);
2853 mouse_mode_size_group->add_widget (snap_type_selector);
2854 mouse_mode_size_group->add_widget (snap_mode_selector);
2856 mouse_mode_size_group->add_widget (edit_point_selector);
2857 mouse_mode_size_group->add_widget (edit_mode_selector);
2859 mouse_mode_size_group->add_widget (*nudge_clock);
2860 mouse_mode_size_group->add_widget (nudge_forward_button);
2861 mouse_mode_size_group->add_widget (nudge_backward_button);
2863 mouse_mode_hbox->set_spacing (2);
2865 if (!ARDOUR::Profile->get_trx()) {
2866 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2872 if (!ARDOUR::Profile->get_mixbus()) {
2873 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2876 if (!ARDOUR::Profile->get_trx()) {
2877 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2878 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2879 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2880 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2881 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2884 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2886 mouse_mode_align->add (*mouse_mode_vbox);
2887 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2889 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2891 edit_mode_selector.set_name ("mouse mode button");
2893 if (!ARDOUR::Profile->get_trx()) {
2894 mode_box->pack_start (edit_mode_selector, false, false);
2896 mode_box->pack_start (*mouse_mode_box, false, false);
2898 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2899 _mouse_mode_tearoff->set_name ("MouseModeBase");
2900 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2902 if (Profile->get_sae() || Profile->get_mixbus() ) {
2903 _mouse_mode_tearoff->set_can_be_torn_off (false);
2906 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2907 &_mouse_mode_tearoff->tearoff_window()));
2908 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2909 &_mouse_mode_tearoff->tearoff_window(), 1));
2910 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2911 &_mouse_mode_tearoff->tearoff_window()));
2912 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2913 &_mouse_mode_tearoff->tearoff_window(), 1));
2917 _zoom_box.set_spacing (2);
2918 _zoom_box.set_border_width (2);
2922 zoom_preset_selector.set_name ("zoom button");
2923 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2924 zoom_preset_selector.set_size_request (42, -1);
2926 zoom_in_button.set_name ("zoom button");
2927 zoom_in_button.set_image(::get_icon ("zoom_in"));
2928 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2929 zoom_in_button.set_related_action (act);
2931 zoom_out_button.set_name ("zoom button");
2932 zoom_out_button.set_image(::get_icon ("zoom_out"));
2933 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2934 zoom_out_button.set_related_action (act);
2936 zoom_out_full_button.set_name ("zoom button");
2937 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2938 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2939 zoom_out_full_button.set_related_action (act);
2941 zoom_focus_selector.set_name ("zoom button");
2943 if (ARDOUR::Profile->get_mixbus()) {
2944 _zoom_box.pack_start (zoom_preset_selector, false, false);
2945 } else if (ARDOUR::Profile->get_trx()) {
2946 mode_box->pack_start (zoom_out_button, false, false);
2947 mode_box->pack_start (zoom_in_button, false, false);
2949 _zoom_box.pack_start (zoom_out_button, false, false);
2950 _zoom_box.pack_start (zoom_in_button, false, false);
2951 _zoom_box.pack_start (zoom_out_full_button, false, false);
2952 _zoom_box.pack_start (zoom_focus_selector, false, false);
2955 /* Track zoom buttons */
2956 visible_tracks_selector.set_name ("zoom button");
2957 if (Profile->get_mixbus()) {
2958 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2959 visible_tracks_selector.set_size_request (42, -1);
2961 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2964 tav_expand_button.set_name ("zoom button");
2965 tav_expand_button.set_image(::get_icon ("tav_exp"));
2966 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2967 tav_expand_button.set_related_action (act);
2969 tav_shrink_button.set_name ("zoom button");
2970 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2971 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2972 tav_shrink_button.set_related_action (act);
2974 if (ARDOUR::Profile->get_mixbus()) {
2975 _zoom_box.pack_start (visible_tracks_selector);
2976 } else if (ARDOUR::Profile->get_trx()) {
2977 _zoom_box.pack_start (tav_shrink_button);
2978 _zoom_box.pack_start (tav_expand_button);
2980 _zoom_box.pack_start (visible_tracks_selector);
2981 _zoom_box.pack_start (tav_shrink_button);
2982 _zoom_box.pack_start (tav_expand_button);
2985 if (!ARDOUR::Profile->get_trx()) {
2986 _zoom_tearoff = manage (new TearOff (_zoom_box));
2988 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2989 &_zoom_tearoff->tearoff_window()));
2990 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2991 &_zoom_tearoff->tearoff_window(), 0));
2992 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2993 &_zoom_tearoff->tearoff_window()));
2994 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2995 &_zoom_tearoff->tearoff_window(), 0));
2998 if (Profile->get_sae() || Profile->get_mixbus() ) {
2999 _zoom_tearoff->set_can_be_torn_off (false);
3002 snap_box.set_spacing (2);
3003 snap_box.set_border_width (2);
3005 snap_type_selector.set_name ("mouse mode button");
3007 snap_mode_selector.set_name ("mouse mode button");
3009 edit_point_selector.set_name ("mouse mode button");
3011 snap_box.pack_start (snap_mode_selector, false, false);
3012 snap_box.pack_start (snap_type_selector, false, false);
3013 snap_box.pack_start (edit_point_selector, false, false);
3017 HBox *nudge_box = manage (new HBox);
3018 nudge_box->set_spacing (2);
3019 nudge_box->set_border_width (2);
3021 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3022 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3024 nudge_box->pack_start (nudge_backward_button, false, false);
3025 nudge_box->pack_start (nudge_forward_button, false, false);
3026 nudge_box->pack_start (*nudge_clock, false, false);
3029 /* Pack everything in... */
3031 HBox* hbox = manage (new HBox);
3032 hbox->set_spacing(2);
3034 _tools_tearoff = manage (new TearOff (*hbox));
3035 _tools_tearoff->set_name ("MouseModeBase");
3036 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3038 if (Profile->get_sae() || Profile->get_mixbus()) {
3039 _tools_tearoff->set_can_be_torn_off (false);
3042 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3043 &_tools_tearoff->tearoff_window()));
3044 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3045 &_tools_tearoff->tearoff_window(), 0));
3046 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3047 &_tools_tearoff->tearoff_window()));
3048 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3049 &_tools_tearoff->tearoff_window(), 0));
3051 toolbar_hbox.set_spacing (2);
3052 toolbar_hbox.set_border_width (1);
3054 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3055 if (!ARDOUR::Profile->get_trx()) {
3056 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3057 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3060 if (!ARDOUR::Profile->get_trx()) {
3061 hbox->pack_start (snap_box, false, false);
3062 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3063 hbox->pack_start (*nudge_box, false, false);
3065 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3068 hbox->pack_start (panic_box, false, false);
3072 toolbar_base.set_name ("ToolBarBase");
3073 toolbar_base.add (toolbar_hbox);
3075 _toolbar_viewport.add (toolbar_base);
3076 /* stick to the required height but allow width to vary if there's not enough room */
3077 _toolbar_viewport.set_size_request (1, -1);
3079 toolbar_frame.set_shadow_type (SHADOW_OUT);
3080 toolbar_frame.set_name ("BaseFrame");
3081 toolbar_frame.add (_toolbar_viewport);
3085 Editor::build_edit_point_menu ()
3087 using namespace Menu_Helpers;
3089 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3090 if(!Profile->get_mixbus())
3091 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3092 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3094 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3098 Editor::build_edit_mode_menu ()
3100 using namespace Menu_Helpers;
3102 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3103 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3104 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3105 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3107 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3111 Editor::build_snap_mode_menu ()
3113 using namespace Menu_Helpers;
3115 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3116 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3117 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3119 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3123 Editor::build_snap_type_menu ()
3125 using namespace Menu_Helpers;
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3133 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3134 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3135 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3136 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3137 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3138 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3139 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3140 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3141 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3142 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3158 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3163 Editor::setup_tooltips ()
3165 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3166 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3167 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3168 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3169 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3170 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3171 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3172 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3173 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3174 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3175 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3176 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3177 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3178 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3179 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3180 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3181 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3182 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3183 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3184 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3185 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3186 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3187 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3188 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3189 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3193 Editor::convert_drop_to_paths (
3194 vector<string>& paths,
3195 const RefPtr<Gdk::DragContext>& /*context*/,
3198 const SelectionData& data,
3202 if (_session == 0) {
3206 vector<string> uris = data.get_uris();
3210 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3211 are actually URI lists. So do it by hand.
3214 if (data.get_target() != "text/plain") {
3218 /* Parse the "uri-list" format that Nautilus provides,
3219 where each pathname is delimited by \r\n.
3221 THERE MAY BE NO NULL TERMINATING CHAR!!!
3224 string txt = data.get_text();
3228 p = (char *) malloc (txt.length() + 1);
3229 txt.copy (p, txt.length(), 0);
3230 p[txt.length()] = '\0';
3236 while (g_ascii_isspace (*p))
3240 while (*q && (*q != '\n') && (*q != '\r')) {
3247 while (q > p && g_ascii_isspace (*q))
3252 uris.push_back (string (p, q - p + 1));
3256 p = strchr (p, '\n');
3268 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3269 if ((*i).substr (0,7) == "file://") {
3270 paths.push_back (Glib::filename_from_uri (*i));
3278 Editor::new_tempo_section ()
3283 Editor::map_transport_state ()
3285 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3287 if (_session && _session->transport_stopped()) {
3288 have_pending_keyboard_selection = false;
3291 update_loop_range_view ();
3297 Editor::begin_reversible_command (string name)
3300 _session->begin_reversible_command (name);
3305 Editor::begin_reversible_command (GQuark q)
3308 _session->begin_reversible_command (q);
3313 Editor::commit_reversible_command ()
3316 _session->commit_reversible_command ();
3321 Editor::history_changed ()
3325 if (undo_action && _session) {
3326 if (_session->undo_depth() == 0) {
3327 label = S_("Command|Undo");
3329 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3331 undo_action->property_label() = label;
3334 if (redo_action && _session) {
3335 if (_session->redo_depth() == 0) {
3338 label = string_compose(_("Redo (%1)"), _session->next_redo());
3340 redo_action->property_label() = label;
3345 Editor::duplicate_range (bool with_dialog)
3349 RegionSelection rs = get_regions_from_selection_and_entered ();
3351 if ( selection->time.length() == 0 && rs.empty()) {
3357 ArdourDialog win (_("Duplicate"));
3358 Label label (_("Number of duplications:"));
3359 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3360 SpinButton spinner (adjustment, 0.0, 1);
3363 win.get_vbox()->set_spacing (12);
3364 win.get_vbox()->pack_start (hbox);
3365 hbox.set_border_width (6);
3366 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3368 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3369 place, visually. so do this by hand.
3372 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3373 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3374 spinner.grab_focus();
3380 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3381 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3382 win.set_default_response (RESPONSE_ACCEPT);
3384 spinner.grab_focus ();
3386 switch (win.run ()) {
3387 case RESPONSE_ACCEPT:
3393 times = adjustment.get_value();
3396 if ((current_mouse_mode() == Editing::MouseRange)) {
3397 if (selection->time.length()) {
3398 duplicate_selection (times);
3400 } else if (get_smart_mode()) {
3401 if (selection->time.length()) {
3402 duplicate_selection (times);
3404 duplicate_some_regions (rs, times);
3406 duplicate_some_regions (rs, times);
3411 Editor::set_edit_mode (EditMode m)
3413 Config->set_edit_mode (m);
3417 Editor::cycle_edit_mode ()
3419 switch (Config->get_edit_mode()) {
3421 if (Profile->get_sae()) {
3422 Config->set_edit_mode (Lock);
3424 Config->set_edit_mode (Ripple);
3429 Config->set_edit_mode (Lock);
3432 Config->set_edit_mode (Slide);
3438 Editor::edit_mode_selection_done ( EditMode m )
3440 Config->set_edit_mode ( m );
3444 Editor::snap_type_selection_done (SnapType snaptype)
3446 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3448 ract->set_active ();
3453 Editor::snap_mode_selection_done (SnapMode mode)
3455 RefPtr<RadioAction> ract = snap_mode_action (mode);
3458 ract->set_active (true);
3463 Editor::cycle_edit_point (bool with_marker)
3465 if(Profile->get_mixbus())
3466 with_marker = false;
3468 switch (_edit_point) {
3470 set_edit_point_preference (EditAtPlayhead);
3472 case EditAtPlayhead:
3474 set_edit_point_preference (EditAtSelectedMarker);
3476 set_edit_point_preference (EditAtMouse);
3479 case EditAtSelectedMarker:
3480 set_edit_point_preference (EditAtMouse);
3486 Editor::edit_point_selection_done (EditPoint ep)
3488 set_edit_point_preference ( ep );
3492 Editor::build_zoom_focus_menu ()
3494 using namespace Menu_Helpers;
3496 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3497 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3498 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3499 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3500 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3501 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3503 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3507 Editor::zoom_focus_selection_done ( ZoomFocus f )
3509 RefPtr<RadioAction> ract = zoom_focus_action (f);
3511 ract->set_active ();
3516 Editor::build_track_count_menu ()
3518 using namespace Menu_Helpers;
3520 if (!Profile->get_mixbus()) {
3521 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3522 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3523 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3524 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3525 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3526 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3527 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3528 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3529 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3530 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3531 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3532 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3533 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3535 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3536 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3537 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3538 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3539 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3540 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3541 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3542 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3543 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3544 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3546 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3547 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3548 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3549 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3550 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3551 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3552 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3553 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3554 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3555 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3556 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3561 Editor::set_zoom_preset (int64_t ms)
3564 temporal_zoom_session();
3568 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3569 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3573 Editor::set_visible_track_count (int32_t n)
3575 _visible_track_count = n;
3577 /* if the canvas hasn't really been allocated any size yet, just
3578 record the desired number of visible tracks and return. when canvas
3579 allocation happens, we will get called again and then we can do the
3583 if (_visible_canvas_height <= 1) {
3590 if (_visible_track_count > 0) {
3591 h = trackviews_height() / _visible_track_count;
3592 std::ostringstream s;
3593 s << _visible_track_count;
3595 } else if (_visible_track_count == 0) {
3597 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3598 if ((*i)->marked_for_display()) {
3602 h = trackviews_height() / n;
3605 /* negative value means that the visible track count has
3606 been overridden by explicit track height changes.
3608 visible_tracks_selector.set_text (X_("*"));
3612 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3613 (*i)->set_height (h);
3616 if (str != visible_tracks_selector.get_text()) {
3617 visible_tracks_selector.set_text (str);
3622 Editor::override_visible_track_count ()
3624 _visible_track_count = -1;
3625 visible_tracks_selector.set_text ( _("*") );
3629 Editor::edit_controls_button_release (GdkEventButton* ev)
3631 if (Keyboard::is_context_menu_event (ev)) {
3632 ARDOUR_UI::instance()->add_route (this);
3633 } else if (ev->button == 1) {
3634 selection->clear_tracks ();
3641 Editor::mouse_select_button_release (GdkEventButton* ev)
3643 /* this handles just right-clicks */
3645 if (ev->button != 3) {
3653 Editor::set_zoom_focus (ZoomFocus f)
3655 string str = zoom_focus_strings[(int)f];
3657 if (str != zoom_focus_selector.get_text()) {
3658 zoom_focus_selector.set_text (str);
3661 if (zoom_focus != f) {
3668 Editor::cycle_zoom_focus ()
3670 switch (zoom_focus) {
3672 set_zoom_focus (ZoomFocusRight);
3674 case ZoomFocusRight:
3675 set_zoom_focus (ZoomFocusCenter);
3677 case ZoomFocusCenter:
3678 set_zoom_focus (ZoomFocusPlayhead);
3680 case ZoomFocusPlayhead:
3681 set_zoom_focus (ZoomFocusMouse);
3683 case ZoomFocusMouse:
3684 set_zoom_focus (ZoomFocusEdit);
3687 set_zoom_focus (ZoomFocusLeft);
3693 Editor::ensure_float (Window& win)
3695 win.set_transient_for (*this);
3699 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3701 /* recover or initialize pane positions. do this here rather than earlier because
3702 we don't want the positions to change the child allocations, which they seem to do.
3708 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3717 XMLNode* geometry = find_named_node (*node, "geometry");
3719 if (which == static_cast<Paned*> (&edit_pane)) {
3721 if (done & Horizontal) {
3725 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3726 _notebook_shrunk = string_is_affirmative (prop->value ());
3729 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3730 /* initial allocation is 90% to canvas, 10% to notebook */
3731 pos = (int) floor (alloc.get_width() * 0.90f);
3732 snprintf (buf, sizeof(buf), "%d", pos);
3734 pos = atoi (prop->value());
3737 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3738 edit_pane.set_position (pos);
3741 done = (Pane) (done | Horizontal);
3743 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3745 if (done & Vertical) {
3749 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3750 /* initial allocation is 90% to canvas, 10% to summary */
3751 pos = (int) floor (alloc.get_height() * 0.90f);
3752 snprintf (buf, sizeof(buf), "%d", pos);
3755 pos = atoi (prop->value());
3758 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3759 editor_summary_pane.set_position (pos);
3762 done = (Pane) (done | Vertical);
3767 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3769 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3770 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3771 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3772 top_hbox.remove (toolbar_frame);
3777 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3779 if (toolbar_frame.get_parent() == 0) {
3780 top_hbox.pack_end (toolbar_frame);
3785 Editor::set_show_measures (bool yn)
3787 if (_show_measures != yn) {
3790 if ((_show_measures = yn) == true) {
3792 tempo_lines->show();
3795 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3796 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3798 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3799 draw_measures (begin, end);
3807 Editor::toggle_follow_playhead ()
3809 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3811 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3812 set_follow_playhead (tact->get_active());
3816 /** @param yn true to follow playhead, otherwise false.
3817 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3820 Editor::set_follow_playhead (bool yn, bool catch_up)
3822 if (_follow_playhead != yn) {
3823 if ((_follow_playhead = yn) == true && catch_up) {
3825 reset_x_origin_to_follow_playhead ();
3832 Editor::toggle_stationary_playhead ()
3834 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3836 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3837 set_stationary_playhead (tact->get_active());
3842 Editor::set_stationary_playhead (bool yn)
3844 if (_stationary_playhead != yn) {
3845 if ((_stationary_playhead = yn) == true) {
3847 // FIXME need a 3.0 equivalent of this 2.X call
3848 // update_current_screen ();
3855 Editor::playlist_selector () const
3857 return *_playlist_selector;
3861 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3865 switch (_snap_type) {
3870 case SnapToBeatDiv128:
3873 case SnapToBeatDiv64:
3876 case SnapToBeatDiv32:
3879 case SnapToBeatDiv28:
3882 case SnapToBeatDiv24:
3885 case SnapToBeatDiv20:
3888 case SnapToBeatDiv16:
3891 case SnapToBeatDiv14:
3894 case SnapToBeatDiv12:
3897 case SnapToBeatDiv10:
3900 case SnapToBeatDiv8:
3903 case SnapToBeatDiv7:
3906 case SnapToBeatDiv6:
3909 case SnapToBeatDiv5:
3912 case SnapToBeatDiv4:
3915 case SnapToBeatDiv3:
3918 case SnapToBeatDiv2:
3924 return _session->tempo_map().meter_at (position).divisions_per_bar();
3929 case SnapToTimecodeFrame:
3930 case SnapToTimecodeSeconds:
3931 case SnapToTimecodeMinutes:
3934 case SnapToRegionStart:
3935 case SnapToRegionEnd:
3936 case SnapToRegionSync:
3937 case SnapToRegionBoundary:
3947 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3951 ret = nudge_clock->current_duration (pos);
3952 next = ret + 1; /* XXXX fix me */
3958 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3960 ArdourDialog dialog (_("Playlist Deletion"));
3961 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3962 "If it is kept, its audio files will not be cleaned.\n"
3963 "If it is deleted, audio files used by it alone will be cleaned."),
3966 dialog.set_position (WIN_POS_CENTER);
3967 dialog.get_vbox()->pack_start (label);
3971 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3972 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3973 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3975 switch (dialog.run ()) {
3976 case RESPONSE_ACCEPT:
3977 /* delete the playlist */
3981 case RESPONSE_REJECT:
3982 /* keep the playlist */
3994 Editor::audio_region_selection_covers (framepos_t where)
3996 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3997 if ((*a)->region()->covers (where)) {
4006 Editor::prepare_for_cleanup ()
4008 cut_buffer->clear_regions ();
4009 cut_buffer->clear_playlists ();
4011 selection->clear_regions ();
4012 selection->clear_playlists ();
4014 _regions->suspend_redisplay ();
4018 Editor::finish_cleanup ()
4020 _regions->resume_redisplay ();
4024 Editor::transport_loop_location()
4027 return _session->locations()->auto_loop_location();
4034 Editor::transport_punch_location()
4037 return _session->locations()->auto_punch_location();
4044 Editor::control_layout_scroll (GdkEventScroll* ev)
4046 /* Just forward to the normal canvas scroll method. The coordinate
4047 systems are different but since the canvas is always larger than the
4048 track headers, and aligned with the trackview area, this will work.
4050 In the not too distant future this layout is going away anyway and
4051 headers will be on the canvas.
4053 return canvas_scroll_event (ev, false);
4057 Editor::session_state_saved (string)
4060 _snapshots->redisplay ();
4064 Editor::update_tearoff_visibility()
4066 bool visible = Config->get_keep_tearoffs();
4067 _mouse_mode_tearoff->set_visible (visible);
4068 _tools_tearoff->set_visible (visible);
4069 if (_zoom_tearoff) {
4070 _zoom_tearoff->set_visible (visible);
4075 Editor::reattach_all_tearoffs ()
4077 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4078 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4079 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4083 Editor::maximise_editing_space ()
4095 Editor::restore_editing_space ()
4107 * Make new playlists for a given track and also any others that belong
4108 * to the same active route group with the `select' property.
4113 Editor::new_playlists (TimeAxisView* v)
4115 begin_reversible_command (_("new 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_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4119 commit_reversible_command ();
4123 * Use a copy of the current playlist for a given track and also any others that belong
4124 * to the same active route group with the `select' property.
4129 Editor::copy_playlists (TimeAxisView* v)
4131 begin_reversible_command (_("copy playlists"));
4132 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4133 _session->playlists->get (playlists);
4134 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4135 commit_reversible_command ();
4138 /** Clear the current playlist for a given track and also any others that belong
4139 * to the same active route group with the `select' property.
4144 Editor::clear_playlists (TimeAxisView* v)
4146 begin_reversible_command (_("clear playlists"));
4147 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4148 _session->playlists->get (playlists);
4149 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4150 commit_reversible_command ();
4154 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4156 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4160 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4162 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4166 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4168 atv.clear_playlist ();
4172 Editor::on_key_press_event (GdkEventKey* ev)
4174 return key_press_focus_accelerator_handler (*this, ev);
4178 Editor::on_key_release_event (GdkEventKey* ev)
4180 return Gtk::Window::on_key_release_event (ev);
4181 // return key_press_focus_accelerator_handler (*this, ev);
4184 /** Queue up a change to the viewport x origin.
4185 * @param frame New x origin.
4188 Editor::reset_x_origin (framepos_t frame)
4190 pending_visual_change.add (VisualChange::TimeOrigin);
4191 pending_visual_change.time_origin = frame;
4192 ensure_visual_change_idle_handler ();
4196 Editor::reset_y_origin (double y)
4198 pending_visual_change.add (VisualChange::YOrigin);
4199 pending_visual_change.y_origin = y;
4200 ensure_visual_change_idle_handler ();
4204 Editor::reset_zoom (framecnt_t spp)
4206 if (spp == samples_per_pixel) {
4210 pending_visual_change.add (VisualChange::ZoomLevel);
4211 pending_visual_change.samples_per_pixel = spp;
4212 ensure_visual_change_idle_handler ();
4216 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4218 reset_x_origin (frame);
4221 if (!no_save_visual) {
4222 undo_visual_stack.push_back (current_visual_state(false));
4226 Editor::VisualState::VisualState (bool with_tracks)
4227 : gui_state (with_tracks ? new GUIObjectState : 0)
4231 Editor::VisualState::~VisualState ()
4236 Editor::VisualState*
4237 Editor::current_visual_state (bool with_tracks)
4239 VisualState* vs = new VisualState (with_tracks);
4240 vs->y_position = vertical_adjustment.get_value();
4241 vs->samples_per_pixel = samples_per_pixel;
4242 vs->leftmost_frame = leftmost_frame;
4243 vs->zoom_focus = zoom_focus;
4246 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4253 Editor::undo_visual_state ()
4255 if (undo_visual_stack.empty()) {
4259 VisualState* vs = undo_visual_stack.back();
4260 undo_visual_stack.pop_back();
4263 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4265 use_visual_state (*vs);
4269 Editor::redo_visual_state ()
4271 if (redo_visual_stack.empty()) {
4275 VisualState* vs = redo_visual_stack.back();
4276 redo_visual_stack.pop_back();
4278 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4280 use_visual_state (*vs);
4284 Editor::swap_visual_state ()
4286 if (undo_visual_stack.empty()) {
4287 redo_visual_state ();
4289 undo_visual_state ();
4294 Editor::use_visual_state (VisualState& vs)
4296 PBD::Unwinder<bool> nsv (no_save_visual, true);
4297 DisplaySuspender ds;
4299 vertical_adjustment.set_value (vs.y_position);
4301 set_zoom_focus (vs.zoom_focus);
4302 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4305 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4307 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4308 (*i)->reset_visual_state ();
4312 _routes->update_visibility ();
4315 /** This is the core function that controls the zoom level of the canvas. It is called
4316 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4317 * @param spp new number of samples per pixel
4320 Editor::set_samples_per_pixel (framecnt_t spp)
4326 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4327 const framecnt_t lots_of_pixels = 4000;
4329 /* if the zoom level is greater than what you'd get trying to display 3
4330 * days of audio on a really big screen, then it's too big.
4333 if (spp * lots_of_pixels > three_days) {
4337 samples_per_pixel = spp;
4340 tempo_lines->tempo_map_changed();
4343 bool const showing_time_selection = selection->time.length() > 0;
4345 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4346 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4347 (*i)->reshow_selection (selection->time);
4351 ZoomChanged (); /* EMIT_SIGNAL */
4353 ArdourCanvas::GtkCanvasViewport* c;
4355 c = get_track_canvas();
4357 c->canvas()->zoomed ();
4360 if (playhead_cursor) {
4361 playhead_cursor->set_position (playhead_cursor->current_frame ());
4364 refresh_location_display();
4365 _summary->set_overlays_dirty ();
4367 update_marker_labels ();
4373 Editor::queue_visual_videotimeline_update ()
4376 * pending_visual_change.add (VisualChange::VideoTimeline);
4377 * or maybe even more specific: which videotimeline-image
4378 * currently it calls update_video_timeline() to update
4379 * _all outdated_ images on the video-timeline.
4380 * see 'exposeimg()' in video_image_frame.cc
4382 ensure_visual_change_idle_handler ();
4386 Editor::ensure_visual_change_idle_handler ()
4388 if (pending_visual_change.idle_handler_id < 0) {
4389 // see comment in add_to_idle_resize above.
4390 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 20, _idle_visual_changer, this, NULL);
4391 pending_visual_change.being_handled = false;
4396 Editor::_idle_visual_changer (void* arg)
4398 return static_cast<Editor*>(arg)->idle_visual_changer ();
4402 Editor::idle_visual_changer ()
4404 /* set_horizontal_position() below (and maybe other calls) call
4405 gtk_main_iteration(), so it's possible that a signal will be handled
4406 half-way through this method. If this signal wants an
4407 idle_visual_changer we must schedule another one after this one, so
4408 mark the idle_handler_id as -1 here to allow that. Also make a note
4409 that we are doing the visual change, so that changes in response to
4410 super-rapid-screen-update can be dropped if we are still processing
4414 pending_visual_change.idle_handler_id = -1;
4415 pending_visual_change.being_handled = true;
4417 VisualChange vc = pending_visual_change;
4419 pending_visual_change.pending = (VisualChange::Type) 0;
4421 visual_changer (vc);
4423 pending_visual_change.being_handled = false;
4425 return 0; /* this is always a one-shot call */
4429 Editor::visual_changer (const VisualChange& vc)
4431 double const last_time_origin = horizontal_position ();
4433 if (vc.pending & VisualChange::ZoomLevel) {
4434 set_samples_per_pixel (vc.samples_per_pixel);
4436 compute_fixed_ruler_scale ();
4438 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4439 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4441 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4442 current_bbt_points_begin, current_bbt_points_end);
4443 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4444 current_bbt_points_begin, current_bbt_points_end);
4445 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4447 update_video_timeline();
4450 if (vc.pending & VisualChange::TimeOrigin) {
4451 set_horizontal_position (vc.time_origin / samples_per_pixel);
4454 if (vc.pending & VisualChange::YOrigin) {
4455 vertical_adjustment.set_value (vc.y_origin);
4458 if (last_time_origin == horizontal_position ()) {
4459 /* changed signal not emitted */
4460 update_fixed_rulers ();
4461 redisplay_tempo (true);
4464 if (!(vc.pending & VisualChange::ZoomLevel)) {
4465 update_video_timeline();
4468 _summary->set_overlays_dirty ();
4471 struct EditorOrderTimeAxisSorter {
4472 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4473 return a->order () < b->order ();
4478 Editor::sort_track_selection (TrackViewList& sel)
4480 EditorOrderTimeAxisSorter cmp;
4485 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4488 framepos_t where = 0;
4489 EditPoint ep = _edit_point;
4491 if(Profile->get_mixbus())
4492 if (ep == EditAtSelectedMarker)
4495 if (from_context_menu && (ep == EditAtMouse)) {
4496 return canvas_event_sample (&context_click_event, 0, 0);
4499 if (entered_marker) {
4500 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4501 return entered_marker->position();
4504 if (ignore_playhead && ep == EditAtPlayhead) {
4505 ep = EditAtSelectedMarker;
4509 case EditAtPlayhead:
4510 where = _session->audible_frame();
4511 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4514 case EditAtSelectedMarker:
4515 if (!selection->markers.empty()) {
4517 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4520 where = loc->start();
4524 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4532 if (!mouse_frame (where, ignored)) {
4533 /* XXX not right but what can we do ? */
4537 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4545 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4547 if (!_session) return;
4549 begin_reversible_command (cmd);
4553 if ((tll = transport_loop_location()) == 0) {
4554 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4555 XMLNode &before = _session->locations()->get_state();
4556 _session->locations()->add (loc, true);
4557 _session->set_auto_loop_location (loc);
4558 XMLNode &after = _session->locations()->get_state();
4559 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4561 XMLNode &before = tll->get_state();
4562 tll->set_hidden (false, this);
4563 tll->set (start, end);
4564 XMLNode &after = tll->get_state();
4565 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4568 commit_reversible_command ();
4572 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4574 if (!_session) return;
4576 begin_reversible_command (cmd);
4580 if ((tpl = transport_punch_location()) == 0) {
4581 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4582 XMLNode &before = _session->locations()->get_state();
4583 _session->locations()->add (loc, true);
4584 _session->set_auto_punch_location (loc);
4585 XMLNode &after = _session->locations()->get_state();
4586 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4589 XMLNode &before = tpl->get_state();
4590 tpl->set_hidden (false, this);
4591 tpl->set (start, end);
4592 XMLNode &after = tpl->get_state();
4593 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4596 commit_reversible_command ();
4599 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4600 * @param rs List to which found regions are added.
4601 * @param where Time to look at.
4602 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4605 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4607 const TrackViewList* tracks;
4610 tracks = &track_views;
4615 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4617 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4620 boost::shared_ptr<Track> tr;
4621 boost::shared_ptr<Playlist> pl;
4623 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4625 boost::shared_ptr<RegionList> regions = pl->regions_at (
4626 (framepos_t) floor ( (double) where * tr->speed()));
4628 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4629 RegionView* rv = rtv->view()->find_view (*i);
4640 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4642 const TrackViewList* tracks;
4645 tracks = &track_views;
4650 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4651 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4653 boost::shared_ptr<Track> tr;
4654 boost::shared_ptr<Playlist> pl;
4656 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4658 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4659 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4661 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4663 RegionView* rv = rtv->view()->find_view (*i);
4674 /** Get regions using the following method:
4676 * Make a region list using:
4677 * (a) any selected regions
4678 * (b) the intersection of any selected tracks and the edit point(*)
4679 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4681 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4683 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4687 Editor::get_regions_from_selection_and_edit_point ()
4689 RegionSelection regions;
4691 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4692 regions.add (entered_regionview);
4694 regions = selection->regions;
4697 if ( regions.empty() ) {
4698 TrackViewList tracks = selection->tracks;
4700 if (!tracks.empty()) {
4701 /* no region selected or entered, but some selected tracks:
4702 * act on all regions on the selected tracks at the edit point
4704 framepos_t const where = get_preferred_edit_position ();
4705 get_regions_at(regions, where, tracks);
4712 /** Get regions using the following method:
4714 * Make a region list using:
4715 * (a) any selected regions
4716 * (b) the intersection of any selected tracks and the edit point(*)
4717 * (c) if neither exists, then whatever region is under the mouse
4719 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4721 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4724 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4726 RegionSelection regions;
4728 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4729 regions.add (entered_regionview);
4731 regions = selection->regions;
4734 if ( regions.empty() ) {
4735 TrackViewList tracks = selection->tracks;
4737 if (!tracks.empty()) {
4738 /* no region selected or entered, but some selected tracks:
4739 * act on all regions on the selected tracks at the edit point
4741 get_regions_at(regions, pos, tracks);
4748 /** Start with regions that are selected, or the entered regionview if none are selected.
4749 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4750 * of the regions that we started with.
4754 Editor::get_regions_from_selection_and_entered ()
4756 RegionSelection regions = selection->regions;
4758 if (regions.empty() && entered_regionview) {
4759 regions.add (entered_regionview);
4766 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4768 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4770 RouteTimeAxisView* tatv;
4772 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4774 boost::shared_ptr<Playlist> pl;
4775 vector<boost::shared_ptr<Region> > results;
4777 boost::shared_ptr<Track> tr;
4779 if ((tr = tatv->track()) == 0) {
4784 if ((pl = (tr->playlist())) != 0) {
4785 if (src_comparison) {
4786 pl->get_source_equivalent_regions (region, results);
4788 pl->get_region_list_equivalent_regions (region, results);
4792 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4793 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4794 regions.push_back (marv);
4803 Editor::show_rhythm_ferret ()
4805 if (rhythm_ferret == 0) {
4806 rhythm_ferret = new RhythmFerret(*this);
4809 rhythm_ferret->set_session (_session);
4810 rhythm_ferret->show ();
4811 rhythm_ferret->present ();
4815 Editor::first_idle ()
4817 MessageDialog* dialog = 0;
4819 if (track_views.size() > 1) {
4820 dialog = new MessageDialog (
4822 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4826 ARDOUR_UI::instance()->flush_pending ();
4829 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4833 // first idle adds route children (automation tracks), so we need to redisplay here
4834 _routes->redisplay ();
4841 Editor::_idle_resize (gpointer arg)
4843 return ((Editor*)arg)->idle_resize ();
4847 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4849 if (resize_idle_id < 0) {
4850 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4851 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4852 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4854 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4855 _pending_resize_amount = 0;
4858 /* make a note of the smallest resulting height, so that we can clamp the
4859 lower limit at TimeAxisView::hSmall */
4861 int32_t min_resulting = INT32_MAX;
4863 _pending_resize_amount += h;
4864 _pending_resize_view = view;
4866 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4868 if (selection->tracks.contains (_pending_resize_view)) {
4869 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4870 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4874 if (min_resulting < 0) {
4879 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4880 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4884 /** Handle pending resizing of tracks */
4886 Editor::idle_resize ()
4888 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4890 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4891 selection->tracks.contains (_pending_resize_view)) {
4893 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4894 if (*i != _pending_resize_view) {
4895 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4900 _pending_resize_amount = 0;
4901 _group_tabs->set_dirty ();
4902 resize_idle_id = -1;
4910 ENSURE_GUI_THREAD (*this, &Editor::located);
4913 playhead_cursor->set_position (_session->audible_frame ());
4914 if (_follow_playhead && !_pending_initial_locate) {
4915 reset_x_origin_to_follow_playhead ();
4919 _pending_locate_request = false;
4920 _pending_initial_locate = false;
4924 Editor::region_view_added (RegionView *)
4926 _summary->set_background_dirty ();
4930 Editor::region_view_removed ()
4932 _summary->set_background_dirty ();
4936 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4938 TrackViewList::const_iterator j = track_views.begin ();
4939 while (j != track_views.end()) {
4940 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4941 if (rtv && rtv->route() == r) {
4952 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4956 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4957 TimeAxisView* tv = axis_view_from_route (*i);
4967 Editor::suspend_route_redisplay ()
4970 _routes->suspend_redisplay();
4975 Editor::resume_route_redisplay ()
4978 _routes->resume_redisplay();
4983 Editor::add_routes (RouteList& routes)
4985 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4987 RouteTimeAxisView *rtv;
4988 list<RouteTimeAxisView*> new_views;
4990 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4991 boost::shared_ptr<Route> route = (*x);
4993 if (route->is_auditioner() || route->is_monitor()) {
4997 DataType dt = route->input()->default_type();
4999 if (dt == ARDOUR::DataType::AUDIO) {
5000 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5001 rtv->set_route (route);
5002 } else if (dt == ARDOUR::DataType::MIDI) {
5003 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5004 rtv->set_route (route);
5006 throw unknown_type();
5009 new_views.push_back (rtv);
5010 track_views.push_back (rtv);
5012 rtv->effective_gain_display ();
5014 if (internal_editing()) {
5015 rtv->enter_internal_edit_mode ();
5017 rtv->leave_internal_edit_mode ();
5020 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5021 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5024 if (new_views.size() > 0) {
5025 _routes->routes_added (new_views);
5026 _summary->routes_added (new_views);
5029 if (show_editor_mixer_when_tracks_arrive) {
5030 show_editor_mixer (true);
5033 editor_list_button.set_sensitive (true);
5037 Editor::timeaxisview_deleted (TimeAxisView *tv)
5039 if (tv == entered_track) {
5043 if (_session && _session->deletion_in_progress()) {
5044 /* the situation is under control */
5048 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5050 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5052 _routes->route_removed (tv);
5054 TimeAxisView::Children c = tv->get_child_list ();
5055 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5056 if (entered_track == i->get()) {
5061 /* remove it from the list of track views */
5063 TrackViewList::iterator i;
5065 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5066 i = track_views.erase (i);
5069 /* update whatever the current mixer strip is displaying, if revelant */
5071 boost::shared_ptr<Route> route;
5074 route = rtav->route ();
5077 if (current_mixer_strip && current_mixer_strip->route() == route) {
5079 TimeAxisView* next_tv;
5081 if (track_views.empty()) {
5083 } else if (i == track_views.end()) {
5084 next_tv = track_views.front();
5091 set_selected_mixer_strip (*next_tv);
5093 /* make the editor mixer strip go away setting the
5094 * button to inactive (which also unticks the menu option)
5097 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5103 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5105 if (apply_to_selection) {
5106 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5108 TrackSelection::iterator j = i;
5111 hide_track_in_display (*i, false);
5116 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5118 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5119 // this will hide the mixer strip
5120 set_selected_mixer_strip (*tv);
5123 _routes->hide_track_in_display (*tv);
5128 Editor::sync_track_view_list_and_routes ()
5130 track_views = TrackViewList (_routes->views ());
5132 _summary->set_dirty ();
5133 _group_tabs->set_dirty ();
5135 return false; // do not call again (until needed)
5139 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5141 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5146 /** Find a RouteTimeAxisView by the ID of its route */
5148 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5150 RouteTimeAxisView* v;
5152 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5153 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5154 if(v->route()->id() == id) {
5164 Editor::fit_route_group (RouteGroup *g)
5166 TrackViewList ts = axis_views_from_routes (g->route_list ());
5171 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5173 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5176 _session->cancel_audition ();
5180 if (_session->is_auditioning()) {
5181 _session->cancel_audition ();
5182 if (r == last_audition_region) {
5187 _session->audition_region (r);
5188 last_audition_region = r;
5193 Editor::hide_a_region (boost::shared_ptr<Region> r)
5195 r->set_hidden (true);
5199 Editor::show_a_region (boost::shared_ptr<Region> r)
5201 r->set_hidden (false);
5205 Editor::audition_region_from_region_list ()
5207 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5211 Editor::hide_region_from_region_list ()
5213 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5217 Editor::show_region_in_region_list ()
5219 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5223 Editor::step_edit_status_change (bool yn)
5226 start_step_editing ();
5228 stop_step_editing ();
5233 Editor::start_step_editing ()
5235 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5239 Editor::stop_step_editing ()
5241 step_edit_connection.disconnect ();
5245 Editor::check_step_edit ()
5247 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5248 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5250 mtv->check_step_edit ();
5254 return true; // do it again, till we stop
5258 Editor::scroll_press (Direction dir)
5260 ++_scroll_callbacks;
5262 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5263 /* delay the first auto-repeat */
5269 scroll_backward (1);
5277 scroll_up_one_track ();
5281 scroll_down_one_track ();
5285 /* do hacky auto-repeat */
5286 if (!_scroll_connection.connected ()) {
5288 _scroll_connection = Glib::signal_timeout().connect (
5289 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5292 _scroll_callbacks = 0;
5299 Editor::scroll_release ()
5301 _scroll_connection.disconnect ();
5304 /** Queue a change for the Editor viewport x origin to follow the playhead */
5306 Editor::reset_x_origin_to_follow_playhead ()
5308 framepos_t const frame = playhead_cursor->current_frame ();
5310 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5312 if (_session->transport_speed() < 0) {
5314 if (frame > (current_page_samples() / 2)) {
5315 center_screen (frame-(current_page_samples()/2));
5317 center_screen (current_page_samples()/2);
5324 if (frame < leftmost_frame) {
5326 if (_session->transport_rolling()) {
5327 /* rolling; end up with the playhead at the right of the page */
5328 l = frame - current_page_samples ();
5330 /* not rolling: end up with the playhead 1/4 of the way along the page */
5331 l = frame - current_page_samples() / 4;
5335 if (_session->transport_rolling()) {
5336 /* rolling: end up with the playhead on the left of the page */
5339 /* not rolling: end up with the playhead 3/4 of the way along the page */
5340 l = frame - 3 * current_page_samples() / 4;
5348 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5354 Editor::super_rapid_screen_update ()
5356 if (!_session || !_session->engine().running()) {
5360 /* METERING / MIXER STRIPS */
5362 /* update track meters, if required */
5363 if (is_mapped() && meters_running) {
5364 RouteTimeAxisView* rtv;
5365 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5366 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5367 rtv->fast_update ();
5372 /* and any current mixer strip */
5373 if (current_mixer_strip) {
5374 current_mixer_strip->fast_update ();
5377 /* PLAYHEAD AND VIEWPORT */
5379 framepos_t const frame = _session->audible_frame();
5381 /* There are a few reasons why we might not update the playhead / viewport stuff:
5383 * 1. we don't update things when there's a pending locate request, otherwise
5384 * when the editor requests a locate there is a chance that this method
5385 * will move the playhead before the locate request is processed, causing
5387 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5388 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5391 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5393 last_update_frame = frame;
5395 if (!_dragging_playhead) {
5396 playhead_cursor->set_position (frame);
5399 if (!_stationary_playhead) {
5401 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5402 /* We only do this if we aren't already
5403 handling a visual change (ie if
5404 pending_visual_change.being_handled is
5405 false) so that these requests don't stack
5406 up there are too many of them to handle in
5409 reset_x_origin_to_follow_playhead ();
5414 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5418 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5419 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5420 if (target <= 0.0) {
5423 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5424 target = (target * 0.15) + (current * 0.85);
5430 set_horizontal_position (current);
5439 Editor::session_going_away ()
5441 _have_idled = false;
5443 _session_connections.drop_connections ();
5445 super_rapid_screen_update_connection.disconnect ();
5447 selection->clear ();
5448 cut_buffer->clear ();
5450 clicked_regionview = 0;
5451 clicked_axisview = 0;
5452 clicked_routeview = 0;
5453 entered_regionview = 0;
5455 last_update_frame = 0;
5458 playhead_cursor->hide ();
5460 /* rip everything out of the list displays */
5464 _route_groups->clear ();
5466 /* do this first so that deleting a track doesn't reset cms to null
5467 and thus cause a leak.
5470 if (current_mixer_strip) {
5471 if (current_mixer_strip->get_parent() != 0) {
5472 global_hpacker.remove (*current_mixer_strip);
5474 delete current_mixer_strip;
5475 current_mixer_strip = 0;
5478 /* delete all trackviews */
5480 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5483 track_views.clear ();
5485 nudge_clock->set_session (0);
5487 editor_list_button.set_active(false);
5488 editor_list_button.set_sensitive(false);
5490 /* clear tempo/meter rulers */
5491 remove_metric_marks ();
5493 clear_marker_display ();
5495 stop_step_editing ();
5497 /* get rid of any existing editor mixer strip */
5499 WindowTitle title(Glib::get_application_name());
5500 title += _("Editor");
5502 set_title (title.get_string());
5504 SessionHandlePtr::session_going_away ();
5509 Editor::show_editor_list (bool yn)
5512 _the_notebook.show ();
5514 _the_notebook.hide ();
5519 Editor::change_region_layering_order (bool from_context_menu)
5521 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5523 if (!clicked_routeview) {
5524 if (layering_order_editor) {
5525 layering_order_editor->hide ();
5530 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5536 boost::shared_ptr<Playlist> pl = track->playlist();
5542 if (layering_order_editor == 0) {
5543 layering_order_editor = new RegionLayeringOrderEditor (*this);
5546 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5547 layering_order_editor->maybe_present ();
5551 Editor::update_region_layering_order_editor ()
5553 if (layering_order_editor && layering_order_editor->is_visible ()) {
5554 change_region_layering_order (true);
5559 Editor::setup_fade_images ()
5561 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5562 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5563 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5564 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5565 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5567 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5568 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5569 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5570 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5571 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5573 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5574 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5575 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5576 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5577 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5579 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5580 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5581 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5582 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5583 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5587 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5589 Editor::action_menu_item (std::string const & name)
5591 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5594 return *manage (a->create_menu_item ());
5598 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5600 EventBox* b = manage (new EventBox);
5601 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5602 Label* l = manage (new Label (name));
5606 _the_notebook.append_page (widget, *b);
5610 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5612 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5613 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5616 if (ev->type == GDK_2BUTTON_PRESS) {
5618 /* double-click on a notebook tab shrinks or expands the notebook */
5620 if (_notebook_shrunk) {
5621 if (pre_notebook_shrink_pane_width) {
5622 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5624 _notebook_shrunk = false;
5626 pre_notebook_shrink_pane_width = edit_pane.get_position();
5628 /* this expands the LHS of the edit pane to cover the notebook
5629 PAGE but leaves the tabs visible.
5631 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5632 _notebook_shrunk = true;
5640 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5642 using namespace Menu_Helpers;
5644 MenuList& items = _control_point_context_menu.items ();
5647 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5648 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5649 if (!can_remove_control_point (item)) {
5650 items.back().set_sensitive (false);
5653 _control_point_context_menu.popup (event->button.button, event->button.time);
5657 Editor::zoom_vertical_modifier_released()
5659 _stepping_axis_view = 0;
5663 Editor::ui_parameter_changed (string parameter)
5665 if (parameter == "icon-set") {
5666 while (!_cursor_stack.empty()) {
5667 _cursor_stack.pop();
5669 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5670 } else if (parameter == "draggable-playhead") {
5671 if (_verbose_cursor) {
5672 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());