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);
2206 playhead_cursor->set_position (pos);
2208 playhead_cursor->set_position (0);
2211 if ((prop = node.property ("mixer-width"))) {
2212 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2215 if ((prop = node.property ("zoom-focus"))) {
2216 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2219 if ((prop = node.property ("zoom"))) {
2220 /* older versions of ardour used floating point samples_per_pixel */
2221 double f = PBD::atof (prop->value());
2222 reset_zoom (llrintf (f));
2224 reset_zoom (samples_per_pixel);
2227 if ((prop = node.property ("visible-track-count"))) {
2228 set_visible_track_count (PBD::atoi (prop->value()));
2231 if ((prop = node.property ("snap-to"))) {
2232 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2235 if ((prop = node.property ("snap-mode"))) {
2236 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2239 if ((prop = node.property ("internal-snap-to"))) {
2240 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2243 if ((prop = node.property ("internal-snap-mode"))) {
2244 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2247 if ((prop = node.property ("pre-internal-snap-to"))) {
2248 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2252 if ((prop = node.property ("pre-internal-snap-mode"))) {
2253 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2256 if ((prop = node.property ("mouse-mode"))) {
2257 MouseMode m = str2mousemode(prop->value());
2258 set_mouse_mode (m, true);
2260 set_mouse_mode (MouseObject, true);
2263 if ((prop = node.property ("left-frame")) != 0) {
2265 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2269 reset_x_origin (pos);
2273 if ((prop = node.property ("y-origin")) != 0) {
2274 reset_y_origin (atof (prop->value ()));
2277 if ((prop = node.property ("internal-edit"))) {
2278 bool yn = string_is_affirmative (prop->value());
2279 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2281 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2282 tact->set_active (!yn);
2283 tact->set_active (yn);
2287 if ((prop = node.property ("join-object-range"))) {
2288 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2289 bool yn = string_is_affirmative (prop->value());
2291 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2292 tact->set_active (!yn);
2293 tact->set_active (yn);
2295 set_mouse_mode(mouse_mode, true);
2298 if ((prop = node.property ("edit-point"))) {
2299 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2302 if ((prop = node.property ("show-measures"))) {
2303 bool yn = string_is_affirmative (prop->value());
2304 _show_measures = yn;
2305 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2307 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2308 /* do it twice to force the change */
2309 tact->set_active (!yn);
2310 tact->set_active (yn);
2314 if ((prop = node.property ("follow-playhead"))) {
2315 bool yn = string_is_affirmative (prop->value());
2316 set_follow_playhead (yn);
2317 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2319 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2320 if (tact->get_active() != yn) {
2321 tact->set_active (yn);
2326 if ((prop = node.property ("stationary-playhead"))) {
2327 bool yn = string_is_affirmative (prop->value());
2328 set_stationary_playhead (yn);
2329 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2331 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2332 if (tact->get_active() != yn) {
2333 tact->set_active (yn);
2338 if ((prop = node.property ("region-list-sort-type"))) {
2339 RegionListSortType st;
2340 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2343 if ((prop = node.property ("show-editor-mixer"))) {
2345 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2348 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2349 bool yn = string_is_affirmative (prop->value());
2351 /* do it twice to force the change */
2353 tact->set_active (!yn);
2354 tact->set_active (yn);
2357 if ((prop = node.property ("show-editor-list"))) {
2359 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2362 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2363 bool yn = string_is_affirmative (prop->value());
2365 /* do it twice to force the change */
2367 tact->set_active (!yn);
2368 tact->set_active (yn);
2371 if ((prop = node.property (X_("editor-list-page")))) {
2372 _the_notebook.set_current_page (atoi (prop->value ()));
2375 if ((prop = node.property (X_("show-marker-lines")))) {
2376 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2378 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2379 bool yn = string_is_affirmative (prop->value ());
2381 tact->set_active (!yn);
2382 tact->set_active (yn);
2385 XMLNodeList children = node.children ();
2386 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2387 selection->set_state (**i, Stateful::current_state_version);
2388 _regions->set_state (**i);
2391 if ((prop = node.property ("maximised"))) {
2392 bool yn = string_is_affirmative (prop->value());
2393 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2395 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2396 bool fs = tact && tact->get_active();
2398 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2402 if ((prop = node.property ("nudge-clock-value"))) {
2404 sscanf (prop->value().c_str(), "%" PRId64, &f);
2405 nudge_clock->set (f);
2407 nudge_clock->set_mode (AudioClock::Timecode);
2408 nudge_clock->set (_session->frame_rate() * 5, true);
2415 Editor::get_state ()
2417 XMLNode* node = new XMLNode ("Editor");
2420 id().print (buf, sizeof (buf));
2421 node->add_property ("id", buf);
2423 if (is_realized()) {
2424 Glib::RefPtr<Gdk::Window> win = get_window();
2426 int x, y, width, height;
2427 win->get_root_origin(x, y);
2428 win->get_size(width, height);
2430 XMLNode* geometry = new XMLNode ("geometry");
2432 snprintf(buf, sizeof(buf), "%d", width);
2433 geometry->add_property("x-size", string(buf));
2434 snprintf(buf, sizeof(buf), "%d", height);
2435 geometry->add_property("y-size", string(buf));
2436 snprintf(buf, sizeof(buf), "%d", x);
2437 geometry->add_property("x-pos", string(buf));
2438 snprintf(buf, sizeof(buf), "%d", y);
2439 geometry->add_property("y-pos", string(buf));
2440 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2441 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2442 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2443 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2444 geometry->add_property("edit-vertical-pane-pos", string(buf));
2446 node->add_child_nocopy (*geometry);
2449 maybe_add_mixer_strip_width (*node);
2451 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2453 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2454 node->add_property ("zoom", buf);
2455 node->add_property ("snap-to", enum_2_string (_snap_type));
2456 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2457 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2458 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2459 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2460 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2461 node->add_property ("edit-point", enum_2_string (_edit_point));
2462 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2463 node->add_property ("visible-track-count", buf);
2465 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2466 node->add_property ("playhead", buf);
2467 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2468 node->add_property ("left-frame", buf);
2469 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2470 node->add_property ("y-origin", buf);
2472 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2473 node->add_property ("maximised", _maximised ? "yes" : "no");
2474 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2475 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2476 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2477 node->add_property ("mouse-mode", enum2str(mouse_mode));
2478 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2479 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2481 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2483 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2484 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2487 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2489 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2490 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2493 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2494 node->add_property (X_("editor-list-page"), buf);
2496 if (button_bindings) {
2497 XMLNode* bb = new XMLNode (X_("Buttons"));
2498 button_bindings->save (*bb);
2499 node->add_child_nocopy (*bb);
2502 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2504 node->add_child_nocopy (selection->get_state ());
2505 node->add_child_nocopy (_regions->get_state ());
2507 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2508 node->add_property ("nudge-clock-value", buf);
2513 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2514 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2516 * @return pair: TimeAxisView that y is over, layer index.
2518 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2519 * in stacked or expanded region display mode, otherwise 0.
2521 std::pair<TimeAxisView *, double>
2522 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2524 if (!trackview_relative_offset) {
2525 y -= _trackview_group->canvas_origin().y;
2529 return std::make_pair ( (TimeAxisView *) 0, 0);
2532 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2534 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2541 return std::make_pair ( (TimeAxisView *) 0, 0);
2544 /** Snap a position to the grid, if appropriate, taking into account current
2545 * grid settings and also the state of any snap modifier keys that may be pressed.
2546 * @param start Position to snap.
2547 * @param event Event to get current key modifier information from, or 0.
2550 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2552 if (!_session || !event) {
2556 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2557 if (_snap_mode == SnapOff) {
2558 snap_to_internal (start, direction, for_mark);
2561 if (_snap_mode != SnapOff) {
2562 snap_to_internal (start, direction, for_mark);
2568 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2570 if (!_session || _snap_mode == SnapOff) {
2574 snap_to_internal (start, direction, for_mark);
2578 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2580 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2581 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2583 switch (_snap_type) {
2584 case SnapToTimecodeFrame:
2585 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2586 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2588 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2592 case SnapToTimecodeSeconds:
2593 if (_session->config.get_timecode_offset_negative()) {
2594 start += _session->config.get_timecode_offset ();
2596 start -= _session->config.get_timecode_offset ();
2598 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2599 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2601 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2604 if (_session->config.get_timecode_offset_negative()) {
2605 start -= _session->config.get_timecode_offset ();
2607 start += _session->config.get_timecode_offset ();
2611 case SnapToTimecodeMinutes:
2612 if (_session->config.get_timecode_offset_negative()) {
2613 start += _session->config.get_timecode_offset ();
2615 start -= _session->config.get_timecode_offset ();
2617 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2618 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2620 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2622 if (_session->config.get_timecode_offset_negative()) {
2623 start -= _session->config.get_timecode_offset ();
2625 start += _session->config.get_timecode_offset ();
2629 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2635 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2637 const framepos_t one_second = _session->frame_rate();
2638 const framepos_t one_minute = _session->frame_rate() * 60;
2639 framepos_t presnap = start;
2643 switch (_snap_type) {
2644 case SnapToTimecodeFrame:
2645 case SnapToTimecodeSeconds:
2646 case SnapToTimecodeMinutes:
2647 return timecode_snap_to_internal (start, direction, for_mark);
2650 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2651 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2653 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2658 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2659 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2661 start = (framepos_t) floor ((double) start / one_second) * one_second;
2666 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2667 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2669 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2674 start = _session->tempo_map().round_to_bar (start, direction);
2678 start = _session->tempo_map().round_to_beat (start, direction);
2681 case SnapToBeatDiv128:
2682 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2684 case SnapToBeatDiv64:
2685 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2687 case SnapToBeatDiv32:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2690 case SnapToBeatDiv28:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2693 case SnapToBeatDiv24:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2696 case SnapToBeatDiv20:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2699 case SnapToBeatDiv16:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2702 case SnapToBeatDiv14:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2705 case SnapToBeatDiv12:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2708 case SnapToBeatDiv10:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2711 case SnapToBeatDiv8:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2714 case SnapToBeatDiv7:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2717 case SnapToBeatDiv6:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2720 case SnapToBeatDiv5:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2723 case SnapToBeatDiv4:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2726 case SnapToBeatDiv3:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2729 case SnapToBeatDiv2:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2738 _session->locations()->marks_either_side (start, before, after);
2740 if (before == max_framepos && after == max_framepos) {
2741 /* No marks to snap to, so just don't snap */
2743 } else if (before == max_framepos) {
2745 } else if (after == max_framepos) {
2747 } else if (before != max_framepos && after != max_framepos) {
2748 /* have before and after */
2749 if ((start - before) < (after - start)) {
2758 case SnapToRegionStart:
2759 case SnapToRegionEnd:
2760 case SnapToRegionSync:
2761 case SnapToRegionBoundary:
2762 if (!region_boundary_cache.empty()) {
2764 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2765 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2767 if (direction > 0) {
2768 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2770 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2773 if (next != region_boundary_cache.begin ()) {
2778 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2779 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2781 if (start > (p + n) / 2) {
2790 switch (_snap_mode) {
2796 if (presnap > start) {
2797 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2801 } else if (presnap < start) {
2802 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2808 /* handled at entry */
2816 Editor::setup_toolbar ()
2818 HBox* mode_box = manage(new HBox);
2819 mode_box->set_border_width (2);
2820 mode_box->set_spacing(2);
2822 HBox* mouse_mode_box = manage (new HBox);
2823 HBox* mouse_mode_hbox = manage (new HBox);
2824 VBox* mouse_mode_vbox = manage (new VBox);
2825 Alignment* mouse_mode_align = manage (new Alignment);
2827 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2828 mouse_mode_size_group->add_widget (smart_mode_button);
2829 mouse_mode_size_group->add_widget (mouse_move_button);
2830 mouse_mode_size_group->add_widget (mouse_cut_button);
2831 mouse_mode_size_group->add_widget (mouse_select_button);
2832 mouse_mode_size_group->add_widget (mouse_gain_button);
2833 mouse_mode_size_group->add_widget (mouse_timefx_button);
2834 mouse_mode_size_group->add_widget (mouse_audition_button);
2835 mouse_mode_size_group->add_widget (mouse_draw_button);
2836 mouse_mode_size_group->add_widget (internal_edit_button);
2838 mouse_mode_size_group->add_widget (zoom_in_button);
2839 mouse_mode_size_group->add_widget (zoom_out_button);
2840 mouse_mode_size_group->add_widget (zoom_preset_selector);
2841 mouse_mode_size_group->add_widget (zoom_out_full_button);
2842 mouse_mode_size_group->add_widget (zoom_focus_selector);
2844 mouse_mode_size_group->add_widget (tav_shrink_button);
2845 mouse_mode_size_group->add_widget (tav_expand_button);
2846 mouse_mode_size_group->add_widget (visible_tracks_selector);
2848 mouse_mode_size_group->add_widget (snap_type_selector);
2849 mouse_mode_size_group->add_widget (snap_mode_selector);
2851 mouse_mode_size_group->add_widget (edit_point_selector);
2852 mouse_mode_size_group->add_widget (edit_mode_selector);
2854 mouse_mode_size_group->add_widget (*nudge_clock);
2855 mouse_mode_size_group->add_widget (nudge_forward_button);
2856 mouse_mode_size_group->add_widget (nudge_backward_button);
2858 mouse_mode_hbox->set_spacing (2);
2860 if (!ARDOUR::Profile->get_trx()) {
2861 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2864 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2865 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2867 if (!ARDOUR::Profile->get_mixbus()) {
2868 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2871 if (!ARDOUR::Profile->get_trx()) {
2872 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2874 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2875 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2876 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 0);
2879 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2881 mouse_mode_align->add (*mouse_mode_vbox);
2882 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2884 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2886 edit_mode_selector.set_name ("mouse mode button");
2888 if (!ARDOUR::Profile->get_trx()) {
2889 mode_box->pack_start (edit_mode_selector, false, false);
2891 mode_box->pack_start (*mouse_mode_box, false, false);
2893 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2894 _mouse_mode_tearoff->set_name ("MouseModeBase");
2895 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2897 if (Profile->get_sae() || Profile->get_mixbus() ) {
2898 _mouse_mode_tearoff->set_can_be_torn_off (false);
2901 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2902 &_mouse_mode_tearoff->tearoff_window()));
2903 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2904 &_mouse_mode_tearoff->tearoff_window(), 1));
2905 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2906 &_mouse_mode_tearoff->tearoff_window()));
2907 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2908 &_mouse_mode_tearoff->tearoff_window(), 1));
2912 _zoom_box.set_spacing (2);
2913 _zoom_box.set_border_width (2);
2917 zoom_preset_selector.set_name ("zoom button");
2918 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2919 zoom_preset_selector.set_size_request (42, -1);
2921 zoom_in_button.set_name ("zoom button");
2922 zoom_in_button.set_image(::get_icon ("zoom_in"));
2923 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2924 zoom_in_button.set_related_action (act);
2926 zoom_out_button.set_name ("zoom button");
2927 zoom_out_button.set_image(::get_icon ("zoom_out"));
2928 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2929 zoom_out_button.set_related_action (act);
2931 zoom_out_full_button.set_name ("zoom button");
2932 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2933 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2934 zoom_out_full_button.set_related_action (act);
2936 zoom_focus_selector.set_name ("zoom button");
2938 if (ARDOUR::Profile->get_mixbus()) {
2939 _zoom_box.pack_start (zoom_preset_selector, false, false);
2940 } else if (ARDOUR::Profile->get_trx()) {
2941 mode_box->pack_start (zoom_out_button, false, false);
2942 mode_box->pack_start (zoom_in_button, false, false);
2944 _zoom_box.pack_start (zoom_out_button, false, false);
2945 _zoom_box.pack_start (zoom_in_button, false, false);
2946 _zoom_box.pack_start (zoom_out_full_button, false, false);
2947 _zoom_box.pack_start (zoom_focus_selector, false, false);
2950 /* Track zoom buttons */
2951 visible_tracks_selector.set_name ("zoom button");
2952 if (Profile->get_mixbus()) {
2953 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2954 visible_tracks_selector.set_size_request (42, -1);
2956 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2959 tav_expand_button.set_name ("zoom button");
2960 tav_expand_button.set_image(::get_icon ("tav_exp"));
2961 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2962 tav_expand_button.set_related_action (act);
2964 tav_shrink_button.set_name ("zoom button");
2965 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2966 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2967 tav_shrink_button.set_related_action (act);
2969 if (ARDOUR::Profile->get_mixbus()) {
2970 _zoom_box.pack_start (visible_tracks_selector);
2971 } else if (ARDOUR::Profile->get_trx()) {
2972 _zoom_box.pack_start (tav_shrink_button);
2973 _zoom_box.pack_start (tav_expand_button);
2975 _zoom_box.pack_start (visible_tracks_selector);
2976 _zoom_box.pack_start (tav_shrink_button);
2977 _zoom_box.pack_start (tav_expand_button);
2980 if (!ARDOUR::Profile->get_trx()) {
2981 _zoom_tearoff = manage (new TearOff (_zoom_box));
2983 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2984 &_zoom_tearoff->tearoff_window()));
2985 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2986 &_zoom_tearoff->tearoff_window(), 0));
2987 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2988 &_zoom_tearoff->tearoff_window()));
2989 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2990 &_zoom_tearoff->tearoff_window(), 0));
2993 if (Profile->get_sae() || Profile->get_mixbus() ) {
2994 _zoom_tearoff->set_can_be_torn_off (false);
2997 snap_box.set_spacing (2);
2998 snap_box.set_border_width (2);
3000 snap_type_selector.set_name ("mouse mode button");
3002 snap_mode_selector.set_name ("mouse mode button");
3004 edit_point_selector.set_name ("mouse mode button");
3006 snap_box.pack_start (snap_mode_selector, false, false);
3007 snap_box.pack_start (snap_type_selector, false, false);
3008 snap_box.pack_start (edit_point_selector, false, false);
3012 HBox *nudge_box = manage (new HBox);
3013 nudge_box->set_spacing (2);
3014 nudge_box->set_border_width (2);
3016 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3017 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3019 nudge_box->pack_start (nudge_backward_button, false, false);
3020 nudge_box->pack_start (nudge_forward_button, false, false);
3021 nudge_box->pack_start (*nudge_clock, false, false);
3024 /* Pack everything in... */
3026 HBox* hbox = manage (new HBox);
3027 hbox->set_spacing(2);
3029 _tools_tearoff = manage (new TearOff (*hbox));
3030 _tools_tearoff->set_name ("MouseModeBase");
3031 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3033 if (Profile->get_sae() || Profile->get_mixbus()) {
3034 _tools_tearoff->set_can_be_torn_off (false);
3037 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3038 &_tools_tearoff->tearoff_window()));
3039 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3040 &_tools_tearoff->tearoff_window(), 0));
3041 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3042 &_tools_tearoff->tearoff_window()));
3043 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3044 &_tools_tearoff->tearoff_window(), 0));
3046 toolbar_hbox.set_spacing (2);
3047 toolbar_hbox.set_border_width (1);
3049 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3050 if (!ARDOUR::Profile->get_trx()) {
3051 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3052 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3055 if (!ARDOUR::Profile->get_trx()) {
3056 hbox->pack_start (snap_box, false, false);
3057 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3058 hbox->pack_start (*nudge_box, false, false);
3060 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3063 hbox->pack_start (panic_box, false, false);
3067 toolbar_base.set_name ("ToolBarBase");
3068 toolbar_base.add (toolbar_hbox);
3070 _toolbar_viewport.add (toolbar_base);
3071 /* stick to the required height but allow width to vary if there's not enough room */
3072 _toolbar_viewport.set_size_request (1, -1);
3074 toolbar_frame.set_shadow_type (SHADOW_OUT);
3075 toolbar_frame.set_name ("BaseFrame");
3076 toolbar_frame.add (_toolbar_viewport);
3080 Editor::build_edit_point_menu ()
3082 using namespace Menu_Helpers;
3084 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3085 if(!Profile->get_mixbus())
3086 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3087 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3089 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3093 Editor::build_edit_mode_menu ()
3095 using namespace Menu_Helpers;
3097 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3098 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3099 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3100 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3102 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3106 Editor::build_snap_mode_menu ()
3108 using namespace Menu_Helpers;
3110 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3111 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3112 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3114 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3118 Editor::build_snap_type_menu ()
3120 using namespace Menu_Helpers;
3122 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3123 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3124 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3125 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3126 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3127 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3128 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3129 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3130 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3131 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3132 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3133 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3134 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3135 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3136 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3137 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3138 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3139 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3140 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3141 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3142 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3153 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3158 Editor::setup_tooltips ()
3160 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3161 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3162 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3163 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3164 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3165 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3166 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3167 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3168 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3169 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3170 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3171 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3172 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3173 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3174 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3175 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3176 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3177 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3178 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3179 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3180 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3181 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3182 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3183 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3184 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3188 Editor::convert_drop_to_paths (
3189 vector<string>& paths,
3190 const RefPtr<Gdk::DragContext>& /*context*/,
3193 const SelectionData& data,
3197 if (_session == 0) {
3201 vector<string> uris = data.get_uris();
3205 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3206 are actually URI lists. So do it by hand.
3209 if (data.get_target() != "text/plain") {
3213 /* Parse the "uri-list" format that Nautilus provides,
3214 where each pathname is delimited by \r\n.
3216 THERE MAY BE NO NULL TERMINATING CHAR!!!
3219 string txt = data.get_text();
3223 p = (char *) malloc (txt.length() + 1);
3224 txt.copy (p, txt.length(), 0);
3225 p[txt.length()] = '\0';
3231 while (g_ascii_isspace (*p))
3235 while (*q && (*q != '\n') && (*q != '\r')) {
3242 while (q > p && g_ascii_isspace (*q))
3247 uris.push_back (string (p, q - p + 1));
3251 p = strchr (p, '\n');
3263 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3264 if ((*i).substr (0,7) == "file://") {
3265 paths.push_back (Glib::filename_from_uri (*i));
3273 Editor::new_tempo_section ()
3278 Editor::map_transport_state ()
3280 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3282 if (_session && _session->transport_stopped()) {
3283 have_pending_keyboard_selection = false;
3286 update_loop_range_view ();
3292 Editor::begin_reversible_command (string name)
3295 _session->begin_reversible_command (name);
3300 Editor::begin_reversible_command (GQuark q)
3303 _session->begin_reversible_command (q);
3308 Editor::commit_reversible_command ()
3311 _session->commit_reversible_command ();
3316 Editor::history_changed ()
3320 if (undo_action && _session) {
3321 if (_session->undo_depth() == 0) {
3322 label = S_("Command|Undo");
3324 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3326 undo_action->property_label() = label;
3329 if (redo_action && _session) {
3330 if (_session->redo_depth() == 0) {
3333 label = string_compose(_("Redo (%1)"), _session->next_redo());
3335 redo_action->property_label() = label;
3340 Editor::duplicate_range (bool with_dialog)
3344 RegionSelection rs = get_regions_from_selection_and_entered ();
3346 if ( selection->time.length() == 0 && rs.empty()) {
3352 ArdourDialog win (_("Duplicate"));
3353 Label label (_("Number of duplications:"));
3354 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3355 SpinButton spinner (adjustment, 0.0, 1);
3358 win.get_vbox()->set_spacing (12);
3359 win.get_vbox()->pack_start (hbox);
3360 hbox.set_border_width (6);
3361 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3363 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3364 place, visually. so do this by hand.
3367 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3368 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3369 spinner.grab_focus();
3375 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3376 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3377 win.set_default_response (RESPONSE_ACCEPT);
3379 spinner.grab_focus ();
3381 switch (win.run ()) {
3382 case RESPONSE_ACCEPT:
3388 times = adjustment.get_value();
3391 if ((current_mouse_mode() == Editing::MouseRange)) {
3392 if (selection->time.length()) {
3393 duplicate_selection (times);
3395 } else if (get_smart_mode()) {
3396 if (selection->time.length()) {
3397 duplicate_selection (times);
3399 duplicate_some_regions (rs, times);
3401 duplicate_some_regions (rs, times);
3406 Editor::set_edit_mode (EditMode m)
3408 Config->set_edit_mode (m);
3412 Editor::cycle_edit_mode ()
3414 switch (Config->get_edit_mode()) {
3416 if (Profile->get_sae()) {
3417 Config->set_edit_mode (Lock);
3419 Config->set_edit_mode (Ripple);
3424 Config->set_edit_mode (Lock);
3427 Config->set_edit_mode (Slide);
3433 Editor::edit_mode_selection_done ( EditMode m )
3435 Config->set_edit_mode ( m );
3439 Editor::snap_type_selection_done (SnapType snaptype)
3441 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3443 ract->set_active ();
3448 Editor::snap_mode_selection_done (SnapMode mode)
3450 RefPtr<RadioAction> ract = snap_mode_action (mode);
3453 ract->set_active (true);
3458 Editor::cycle_edit_point (bool with_marker)
3460 if(Profile->get_mixbus())
3461 with_marker = false;
3463 switch (_edit_point) {
3465 set_edit_point_preference (EditAtPlayhead);
3467 case EditAtPlayhead:
3469 set_edit_point_preference (EditAtSelectedMarker);
3471 set_edit_point_preference (EditAtMouse);
3474 case EditAtSelectedMarker:
3475 set_edit_point_preference (EditAtMouse);
3481 Editor::edit_point_selection_done (EditPoint ep)
3483 set_edit_point_preference ( ep );
3487 Editor::build_zoom_focus_menu ()
3489 using namespace Menu_Helpers;
3491 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3492 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3493 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3494 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3495 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3496 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3498 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3502 Editor::zoom_focus_selection_done ( ZoomFocus f )
3504 RefPtr<RadioAction> ract = zoom_focus_action (f);
3506 ract->set_active ();
3511 Editor::build_track_count_menu ()
3513 using namespace Menu_Helpers;
3515 if (!Profile->get_mixbus()) {
3516 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3517 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3518 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3519 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3520 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3521 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3522 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3523 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3524 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3525 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3526 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3527 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3528 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3530 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3531 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3532 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3533 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3534 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3535 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3536 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3537 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3538 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3539 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3541 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3542 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3543 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3544 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3545 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3546 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3547 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3548 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3549 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3550 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3551 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3556 Editor::set_zoom_preset (int64_t ms)
3559 temporal_zoom_session();
3563 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3564 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3568 Editor::set_visible_track_count (int32_t n)
3570 _visible_track_count = n;
3572 /* if the canvas hasn't really been allocated any size yet, just
3573 record the desired number of visible tracks and return. when canvas
3574 allocation happens, we will get called again and then we can do the
3578 if (_visible_canvas_height <= 1) {
3585 if (_visible_track_count > 0) {
3586 h = trackviews_height() / _visible_track_count;
3587 std::ostringstream s;
3588 s << _visible_track_count;
3590 } else if (_visible_track_count == 0) {
3592 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3593 if ((*i)->marked_for_display()) {
3597 h = trackviews_height() / n;
3600 /* negative value means that the visible track count has
3601 been overridden by explicit track height changes.
3603 visible_tracks_selector.set_text (X_("*"));
3607 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3608 (*i)->set_height (h);
3611 if (str != visible_tracks_selector.get_text()) {
3612 visible_tracks_selector.set_text (str);
3617 Editor::override_visible_track_count ()
3619 _visible_track_count = -1;
3620 visible_tracks_selector.set_text ( _("*") );
3624 Editor::edit_controls_button_release (GdkEventButton* ev)
3626 if (Keyboard::is_context_menu_event (ev)) {
3627 ARDOUR_UI::instance()->add_route (this);
3628 } else if (ev->button == 1) {
3629 selection->clear_tracks ();
3636 Editor::mouse_select_button_release (GdkEventButton* ev)
3638 /* this handles just right-clicks */
3640 if (ev->button != 3) {
3648 Editor::set_zoom_focus (ZoomFocus f)
3650 string str = zoom_focus_strings[(int)f];
3652 if (str != zoom_focus_selector.get_text()) {
3653 zoom_focus_selector.set_text (str);
3656 if (zoom_focus != f) {
3663 Editor::cycle_zoom_focus ()
3665 switch (zoom_focus) {
3667 set_zoom_focus (ZoomFocusRight);
3669 case ZoomFocusRight:
3670 set_zoom_focus (ZoomFocusCenter);
3672 case ZoomFocusCenter:
3673 set_zoom_focus (ZoomFocusPlayhead);
3675 case ZoomFocusPlayhead:
3676 set_zoom_focus (ZoomFocusMouse);
3678 case ZoomFocusMouse:
3679 set_zoom_focus (ZoomFocusEdit);
3682 set_zoom_focus (ZoomFocusLeft);
3688 Editor::ensure_float (Window& win)
3690 win.set_transient_for (*this);
3694 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3696 /* recover or initialize pane positions. do this here rather than earlier because
3697 we don't want the positions to change the child allocations, which they seem to do.
3703 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3712 XMLNode* geometry = find_named_node (*node, "geometry");
3714 if (which == static_cast<Paned*> (&edit_pane)) {
3716 if (done & Horizontal) {
3720 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3721 _notebook_shrunk = string_is_affirmative (prop->value ());
3724 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3725 /* initial allocation is 90% to canvas, 10% to notebook */
3726 pos = (int) floor (alloc.get_width() * 0.90f);
3727 snprintf (buf, sizeof(buf), "%d", pos);
3729 pos = atoi (prop->value());
3732 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3733 edit_pane.set_position (pos);
3736 done = (Pane) (done | Horizontal);
3738 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3740 if (done & Vertical) {
3744 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3745 /* initial allocation is 90% to canvas, 10% to summary */
3746 pos = (int) floor (alloc.get_height() * 0.90f);
3747 snprintf (buf, sizeof(buf), "%d", pos);
3750 pos = atoi (prop->value());
3753 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3754 editor_summary_pane.set_position (pos);
3757 done = (Pane) (done | Vertical);
3762 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3764 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3765 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3766 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3767 top_hbox.remove (toolbar_frame);
3772 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3774 if (toolbar_frame.get_parent() == 0) {
3775 top_hbox.pack_end (toolbar_frame);
3780 Editor::set_show_measures (bool yn)
3782 if (_show_measures != yn) {
3785 if ((_show_measures = yn) == true) {
3787 tempo_lines->show();
3790 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3791 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3793 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3794 draw_measures (begin, end);
3802 Editor::toggle_follow_playhead ()
3804 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3806 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3807 set_follow_playhead (tact->get_active());
3811 /** @param yn true to follow playhead, otherwise false.
3812 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3815 Editor::set_follow_playhead (bool yn, bool catch_up)
3817 if (_follow_playhead != yn) {
3818 if ((_follow_playhead = yn) == true && catch_up) {
3820 reset_x_origin_to_follow_playhead ();
3827 Editor::toggle_stationary_playhead ()
3829 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3831 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3832 set_stationary_playhead (tact->get_active());
3837 Editor::set_stationary_playhead (bool yn)
3839 if (_stationary_playhead != yn) {
3840 if ((_stationary_playhead = yn) == true) {
3842 // FIXME need a 3.0 equivalent of this 2.X call
3843 // update_current_screen ();
3850 Editor::playlist_selector () const
3852 return *_playlist_selector;
3856 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3860 switch (_snap_type) {
3865 case SnapToBeatDiv128:
3868 case SnapToBeatDiv64:
3871 case SnapToBeatDiv32:
3874 case SnapToBeatDiv28:
3877 case SnapToBeatDiv24:
3880 case SnapToBeatDiv20:
3883 case SnapToBeatDiv16:
3886 case SnapToBeatDiv14:
3889 case SnapToBeatDiv12:
3892 case SnapToBeatDiv10:
3895 case SnapToBeatDiv8:
3898 case SnapToBeatDiv7:
3901 case SnapToBeatDiv6:
3904 case SnapToBeatDiv5:
3907 case SnapToBeatDiv4:
3910 case SnapToBeatDiv3:
3913 case SnapToBeatDiv2:
3919 return _session->tempo_map().meter_at (position).divisions_per_bar();
3924 case SnapToTimecodeFrame:
3925 case SnapToTimecodeSeconds:
3926 case SnapToTimecodeMinutes:
3929 case SnapToRegionStart:
3930 case SnapToRegionEnd:
3931 case SnapToRegionSync:
3932 case SnapToRegionBoundary:
3942 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3946 ret = nudge_clock->current_duration (pos);
3947 next = ret + 1; /* XXXX fix me */
3953 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3955 ArdourDialog dialog (_("Playlist Deletion"));
3956 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3957 "If it is kept, its audio files will not be cleaned.\n"
3958 "If it is deleted, audio files used by it alone will be cleaned."),
3961 dialog.set_position (WIN_POS_CENTER);
3962 dialog.get_vbox()->pack_start (label);
3966 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3967 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3968 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3970 switch (dialog.run ()) {
3971 case RESPONSE_ACCEPT:
3972 /* delete the playlist */
3976 case RESPONSE_REJECT:
3977 /* keep the playlist */
3989 Editor::audio_region_selection_covers (framepos_t where)
3991 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3992 if ((*a)->region()->covers (where)) {
4001 Editor::prepare_for_cleanup ()
4003 cut_buffer->clear_regions ();
4004 cut_buffer->clear_playlists ();
4006 selection->clear_regions ();
4007 selection->clear_playlists ();
4009 _regions->suspend_redisplay ();
4013 Editor::finish_cleanup ()
4015 _regions->resume_redisplay ();
4019 Editor::transport_loop_location()
4022 return _session->locations()->auto_loop_location();
4029 Editor::transport_punch_location()
4032 return _session->locations()->auto_punch_location();
4039 Editor::control_layout_scroll (GdkEventScroll* ev)
4041 /* Just forward to the normal canvas scroll method. The coordinate
4042 systems are different but since the canvas is always larger than the
4043 track headers, and aligned with the trackview area, this will work.
4045 In the not too distant future this layout is going away anyway and
4046 headers will be on the canvas.
4048 return canvas_scroll_event (ev, false);
4052 Editor::session_state_saved (string)
4055 _snapshots->redisplay ();
4059 Editor::update_tearoff_visibility()
4061 bool visible = Config->get_keep_tearoffs();
4062 _mouse_mode_tearoff->set_visible (visible);
4063 _tools_tearoff->set_visible (visible);
4064 if (_zoom_tearoff) {
4065 _zoom_tearoff->set_visible (visible);
4070 Editor::reattach_all_tearoffs ()
4072 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4073 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4074 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4078 Editor::maximise_editing_space ()
4090 Editor::restore_editing_space ()
4102 * Make new playlists for a given track and also any others that belong
4103 * to the same active route group with the `select' property.
4108 Editor::new_playlists (TimeAxisView* v)
4110 begin_reversible_command (_("new playlists"));
4111 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4112 _session->playlists->get (playlists);
4113 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4114 commit_reversible_command ();
4118 * Use a copy of the current playlist for a given track and also any others that belong
4119 * to the same active route group with the `select' property.
4124 Editor::copy_playlists (TimeAxisView* v)
4126 begin_reversible_command (_("copy playlists"));
4127 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4128 _session->playlists->get (playlists);
4129 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4130 commit_reversible_command ();
4133 /** Clear the current playlist for a given track and also any others that belong
4134 * to the same active route group with the `select' property.
4139 Editor::clear_playlists (TimeAxisView* v)
4141 begin_reversible_command (_("clear playlists"));
4142 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4143 _session->playlists->get (playlists);
4144 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4145 commit_reversible_command ();
4149 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4151 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4155 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4157 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4161 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4163 atv.clear_playlist ();
4167 Editor::on_key_press_event (GdkEventKey* ev)
4169 return key_press_focus_accelerator_handler (*this, ev);
4173 Editor::on_key_release_event (GdkEventKey* ev)
4175 return Gtk::Window::on_key_release_event (ev);
4176 // return key_press_focus_accelerator_handler (*this, ev);
4179 /** Queue up a change to the viewport x origin.
4180 * @param frame New x origin.
4183 Editor::reset_x_origin (framepos_t frame)
4185 pending_visual_change.add (VisualChange::TimeOrigin);
4186 pending_visual_change.time_origin = frame;
4187 ensure_visual_change_idle_handler ();
4191 Editor::reset_y_origin (double y)
4193 pending_visual_change.add (VisualChange::YOrigin);
4194 pending_visual_change.y_origin = y;
4195 ensure_visual_change_idle_handler ();
4199 Editor::reset_zoom (framecnt_t spp)
4201 if (spp == samples_per_pixel) {
4205 pending_visual_change.add (VisualChange::ZoomLevel);
4206 pending_visual_change.samples_per_pixel = spp;
4207 ensure_visual_change_idle_handler ();
4211 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4213 reset_x_origin (frame);
4216 if (!no_save_visual) {
4217 undo_visual_stack.push_back (current_visual_state(false));
4221 Editor::VisualState::VisualState (bool with_tracks)
4222 : gui_state (with_tracks ? new GUIObjectState : 0)
4226 Editor::VisualState::~VisualState ()
4231 Editor::VisualState*
4232 Editor::current_visual_state (bool with_tracks)
4234 VisualState* vs = new VisualState (with_tracks);
4235 vs->y_position = vertical_adjustment.get_value();
4236 vs->samples_per_pixel = samples_per_pixel;
4237 vs->leftmost_frame = leftmost_frame;
4238 vs->zoom_focus = zoom_focus;
4241 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4248 Editor::undo_visual_state ()
4250 if (undo_visual_stack.empty()) {
4254 VisualState* vs = undo_visual_stack.back();
4255 undo_visual_stack.pop_back();
4258 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4260 use_visual_state (*vs);
4264 Editor::redo_visual_state ()
4266 if (redo_visual_stack.empty()) {
4270 VisualState* vs = redo_visual_stack.back();
4271 redo_visual_stack.pop_back();
4273 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4275 use_visual_state (*vs);
4279 Editor::swap_visual_state ()
4281 if (undo_visual_stack.empty()) {
4282 redo_visual_state ();
4284 undo_visual_state ();
4289 Editor::use_visual_state (VisualState& vs)
4291 PBD::Unwinder<bool> nsv (no_save_visual, true);
4292 DisplaySuspender ds;
4294 vertical_adjustment.set_value (vs.y_position);
4296 set_zoom_focus (vs.zoom_focus);
4297 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4300 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4302 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4303 (*i)->reset_visual_state ();
4307 _routes->update_visibility ();
4310 /** This is the core function that controls the zoom level of the canvas. It is called
4311 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4312 * @param spp new number of samples per pixel
4315 Editor::set_samples_per_pixel (framecnt_t spp)
4321 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4322 const framecnt_t lots_of_pixels = 4000;
4324 /* if the zoom level is greater than what you'd get trying to display 3
4325 * days of audio on a really big screen, then it's too big.
4328 if (spp * lots_of_pixels > three_days) {
4332 samples_per_pixel = spp;
4335 tempo_lines->tempo_map_changed();
4338 bool const showing_time_selection = selection->time.length() > 0;
4340 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4341 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4342 (*i)->reshow_selection (selection->time);
4346 ZoomChanged (); /* EMIT_SIGNAL */
4348 ArdourCanvas::GtkCanvasViewport* c;
4350 c = get_track_canvas();
4352 c->canvas()->zoomed ();
4355 if (playhead_cursor) {
4356 playhead_cursor->set_position (playhead_cursor->current_frame ());
4359 refresh_location_display();
4360 _summary->set_overlays_dirty ();
4362 update_marker_labels ();
4368 Editor::queue_visual_videotimeline_update ()
4371 * pending_visual_change.add (VisualChange::VideoTimeline);
4372 * or maybe even more specific: which videotimeline-image
4373 * currently it calls update_video_timeline() to update
4374 * _all outdated_ images on the video-timeline.
4375 * see 'exposeimg()' in video_image_frame.cc
4377 ensure_visual_change_idle_handler ();
4381 Editor::ensure_visual_change_idle_handler ()
4383 if (pending_visual_change.idle_handler_id < 0) {
4384 // see comment in add_to_idle_resize above.
4385 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE + 20, _idle_visual_changer, this, NULL);
4386 pending_visual_change.being_handled = false;
4391 Editor::_idle_visual_changer (void* arg)
4393 return static_cast<Editor*>(arg)->idle_visual_changer ();
4397 Editor::idle_visual_changer ()
4399 /* set_horizontal_position() below (and maybe other calls) call
4400 gtk_main_iteration(), so it's possible that a signal will be handled
4401 half-way through this method. If this signal wants an
4402 idle_visual_changer we must schedule another one after this one, so
4403 mark the idle_handler_id as -1 here to allow that. Also make a note
4404 that we are doing the visual change, so that changes in response to
4405 super-rapid-screen-update can be dropped if we are still processing
4409 pending_visual_change.idle_handler_id = -1;
4410 pending_visual_change.being_handled = true;
4412 VisualChange vc = pending_visual_change;
4414 pending_visual_change.pending = (VisualChange::Type) 0;
4416 visual_changer (vc);
4418 pending_visual_change.being_handled = false;
4420 return 0; /* this is always a one-shot call */
4424 Editor::visual_changer (const VisualChange& vc)
4426 double const last_time_origin = horizontal_position ();
4428 if (vc.pending & VisualChange::ZoomLevel) {
4429 set_samples_per_pixel (vc.samples_per_pixel);
4431 compute_fixed_ruler_scale ();
4433 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4434 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4436 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4437 current_bbt_points_begin, current_bbt_points_end);
4438 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4439 current_bbt_points_begin, current_bbt_points_end);
4440 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4442 update_video_timeline();
4445 if (vc.pending & VisualChange::TimeOrigin) {
4446 set_horizontal_position (vc.time_origin / samples_per_pixel);
4449 if (vc.pending & VisualChange::YOrigin) {
4450 vertical_adjustment.set_value (vc.y_origin);
4453 if (last_time_origin == horizontal_position ()) {
4454 /* changed signal not emitted */
4455 update_fixed_rulers ();
4456 redisplay_tempo (true);
4459 if (!(vc.pending & VisualChange::ZoomLevel)) {
4460 update_video_timeline();
4463 _summary->set_overlays_dirty ();
4466 struct EditorOrderTimeAxisSorter {
4467 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4468 return a->order () < b->order ();
4473 Editor::sort_track_selection (TrackViewList& sel)
4475 EditorOrderTimeAxisSorter cmp;
4480 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4483 framepos_t where = 0;
4484 EditPoint ep = _edit_point;
4486 if(Profile->get_mixbus())
4487 if (ep == EditAtSelectedMarker)
4490 if (from_context_menu && (ep == EditAtMouse)) {
4491 return canvas_event_sample (&context_click_event, 0, 0);
4494 if (entered_marker) {
4495 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4496 return entered_marker->position();
4499 if (ignore_playhead && ep == EditAtPlayhead) {
4500 ep = EditAtSelectedMarker;
4504 case EditAtPlayhead:
4505 where = _session->audible_frame();
4506 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4509 case EditAtSelectedMarker:
4510 if (!selection->markers.empty()) {
4512 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4515 where = loc->start();
4519 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4527 if (!mouse_frame (where, ignored)) {
4528 /* XXX not right but what can we do ? */
4532 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4540 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4542 if (!_session) return;
4544 begin_reversible_command (cmd);
4548 if ((tll = transport_loop_location()) == 0) {
4549 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4550 XMLNode &before = _session->locations()->get_state();
4551 _session->locations()->add (loc, true);
4552 _session->set_auto_loop_location (loc);
4553 XMLNode &after = _session->locations()->get_state();
4554 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4556 XMLNode &before = tll->get_state();
4557 tll->set_hidden (false, this);
4558 tll->set (start, end);
4559 XMLNode &after = tll->get_state();
4560 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4563 commit_reversible_command ();
4567 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4569 if (!_session) return;
4571 begin_reversible_command (cmd);
4575 if ((tpl = transport_punch_location()) == 0) {
4576 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4577 XMLNode &before = _session->locations()->get_state();
4578 _session->locations()->add (loc, true);
4579 _session->set_auto_punch_location (loc);
4580 XMLNode &after = _session->locations()->get_state();
4581 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4584 XMLNode &before = tpl->get_state();
4585 tpl->set_hidden (false, this);
4586 tpl->set (start, end);
4587 XMLNode &after = tpl->get_state();
4588 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4591 commit_reversible_command ();
4594 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4595 * @param rs List to which found regions are added.
4596 * @param where Time to look at.
4597 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4600 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4602 const TrackViewList* tracks;
4605 tracks = &track_views;
4610 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4612 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4615 boost::shared_ptr<Track> tr;
4616 boost::shared_ptr<Playlist> pl;
4618 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4620 boost::shared_ptr<RegionList> regions = pl->regions_at (
4621 (framepos_t) floor ( (double) where * tr->speed()));
4623 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4624 RegionView* rv = rtv->view()->find_view (*i);
4635 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4637 const TrackViewList* tracks;
4640 tracks = &track_views;
4645 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4646 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4648 boost::shared_ptr<Track> tr;
4649 boost::shared_ptr<Playlist> pl;
4651 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4653 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4654 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4656 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4658 RegionView* rv = rtv->view()->find_view (*i);
4669 /** Get regions using the following method:
4671 * Make a region list using:
4672 * (a) any selected regions
4673 * (b) the intersection of any selected tracks and the edit point(*)
4674 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4676 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4678 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4682 Editor::get_regions_from_selection_and_edit_point ()
4684 RegionSelection regions;
4686 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4687 regions.add (entered_regionview);
4689 regions = selection->regions;
4692 if ( regions.empty() ) {
4693 TrackViewList tracks = selection->tracks;
4695 if (!tracks.empty()) {
4696 /* no region selected or entered, but some selected tracks:
4697 * act on all regions on the selected tracks at the edit point
4699 framepos_t const where = get_preferred_edit_position ();
4700 get_regions_at(regions, where, tracks);
4707 /** Get regions using the following method:
4709 * Make a region list using:
4710 * (a) any selected regions
4711 * (b) the intersection of any selected tracks and the edit point(*)
4712 * (c) if neither exists, then whatever region is under the mouse
4714 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4716 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4719 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4721 RegionSelection regions;
4723 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4724 regions.add (entered_regionview);
4726 regions = selection->regions;
4729 if ( regions.empty() ) {
4730 TrackViewList tracks = selection->tracks;
4732 if (!tracks.empty()) {
4733 /* no region selected or entered, but some selected tracks:
4734 * act on all regions on the selected tracks at the edit point
4736 get_regions_at(regions, pos, tracks);
4743 /** Start with regions that are selected, or the entered regionview if none are selected.
4744 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4745 * of the regions that we started with.
4749 Editor::get_regions_from_selection_and_entered ()
4751 RegionSelection regions = selection->regions;
4753 if (regions.empty() && entered_regionview) {
4754 regions.add (entered_regionview);
4761 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4763 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4765 RouteTimeAxisView* tatv;
4767 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4769 boost::shared_ptr<Playlist> pl;
4770 vector<boost::shared_ptr<Region> > results;
4772 boost::shared_ptr<Track> tr;
4774 if ((tr = tatv->track()) == 0) {
4779 if ((pl = (tr->playlist())) != 0) {
4780 if (src_comparison) {
4781 pl->get_source_equivalent_regions (region, results);
4783 pl->get_region_list_equivalent_regions (region, results);
4787 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4788 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4789 regions.push_back (marv);
4798 Editor::show_rhythm_ferret ()
4800 if (rhythm_ferret == 0) {
4801 rhythm_ferret = new RhythmFerret(*this);
4804 rhythm_ferret->set_session (_session);
4805 rhythm_ferret->show ();
4806 rhythm_ferret->present ();
4810 Editor::first_idle ()
4812 MessageDialog* dialog = 0;
4814 if (track_views.size() > 1) {
4815 dialog = new MessageDialog (
4817 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4821 ARDOUR_UI::instance()->flush_pending ();
4824 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4828 // first idle adds route children (automation tracks), so we need to redisplay here
4829 _routes->redisplay ();
4836 Editor::_idle_resize (gpointer arg)
4838 return ((Editor*)arg)->idle_resize ();
4842 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4844 if (resize_idle_id < 0) {
4845 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4846 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4847 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4849 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4850 _pending_resize_amount = 0;
4853 /* make a note of the smallest resulting height, so that we can clamp the
4854 lower limit at TimeAxisView::hSmall */
4856 int32_t min_resulting = INT32_MAX;
4858 _pending_resize_amount += h;
4859 _pending_resize_view = view;
4861 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4863 if (selection->tracks.contains (_pending_resize_view)) {
4864 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4865 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4869 if (min_resulting < 0) {
4874 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4875 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4879 /** Handle pending resizing of tracks */
4881 Editor::idle_resize ()
4883 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4885 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4886 selection->tracks.contains (_pending_resize_view)) {
4888 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4889 if (*i != _pending_resize_view) {
4890 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4895 _pending_resize_amount = 0;
4896 _group_tabs->set_dirty ();
4897 resize_idle_id = -1;
4905 ENSURE_GUI_THREAD (*this, &Editor::located);
4908 playhead_cursor->set_position (_session->audible_frame ());
4909 if (_follow_playhead && !_pending_initial_locate) {
4910 reset_x_origin_to_follow_playhead ();
4914 _pending_locate_request = false;
4915 _pending_initial_locate = false;
4919 Editor::region_view_added (RegionView *)
4921 _summary->set_background_dirty ();
4925 Editor::region_view_removed ()
4927 _summary->set_background_dirty ();
4931 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4933 TrackViewList::const_iterator j = track_views.begin ();
4934 while (j != track_views.end()) {
4935 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4936 if (rtv && rtv->route() == r) {
4947 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4951 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4952 TimeAxisView* tv = axis_view_from_route (*i);
4962 Editor::suspend_route_redisplay ()
4965 _routes->suspend_redisplay();
4970 Editor::resume_route_redisplay ()
4973 _routes->resume_redisplay();
4978 Editor::add_routes (RouteList& routes)
4980 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4982 RouteTimeAxisView *rtv;
4983 list<RouteTimeAxisView*> new_views;
4985 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4986 boost::shared_ptr<Route> route = (*x);
4988 if (route->is_auditioner() || route->is_monitor()) {
4992 DataType dt = route->input()->default_type();
4994 if (dt == ARDOUR::DataType::AUDIO) {
4995 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4996 rtv->set_route (route);
4997 } else if (dt == ARDOUR::DataType::MIDI) {
4998 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4999 rtv->set_route (route);
5001 throw unknown_type();
5004 new_views.push_back (rtv);
5005 track_views.push_back (rtv);
5007 rtv->effective_gain_display ();
5009 if (internal_editing()) {
5010 rtv->enter_internal_edit_mode ();
5012 rtv->leave_internal_edit_mode ();
5015 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5016 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5019 if (new_views.size() > 0) {
5020 _routes->routes_added (new_views);
5021 _summary->routes_added (new_views);
5024 if (show_editor_mixer_when_tracks_arrive) {
5025 show_editor_mixer (true);
5028 editor_list_button.set_sensitive (true);
5032 Editor::timeaxisview_deleted (TimeAxisView *tv)
5034 if (tv == entered_track) {
5038 if (_session && _session->deletion_in_progress()) {
5039 /* the situation is under control */
5043 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5045 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5047 _routes->route_removed (tv);
5049 TimeAxisView::Children c = tv->get_child_list ();
5050 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5051 if (entered_track == i->get()) {
5056 /* remove it from the list of track views */
5058 TrackViewList::iterator i;
5060 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5061 i = track_views.erase (i);
5064 /* update whatever the current mixer strip is displaying, if revelant */
5066 boost::shared_ptr<Route> route;
5069 route = rtav->route ();
5072 if (current_mixer_strip && current_mixer_strip->route() == route) {
5074 TimeAxisView* next_tv;
5076 if (track_views.empty()) {
5078 } else if (i == track_views.end()) {
5079 next_tv = track_views.front();
5086 set_selected_mixer_strip (*next_tv);
5088 /* make the editor mixer strip go away setting the
5089 * button to inactive (which also unticks the menu option)
5092 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5098 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5100 if (apply_to_selection) {
5101 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5103 TrackSelection::iterator j = i;
5106 hide_track_in_display (*i, false);
5111 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5113 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5114 // this will hide the mixer strip
5115 set_selected_mixer_strip (*tv);
5118 _routes->hide_track_in_display (*tv);
5123 Editor::sync_track_view_list_and_routes ()
5125 track_views = TrackViewList (_routes->views ());
5127 _summary->set_dirty ();
5128 _group_tabs->set_dirty ();
5130 return false; // do not call again (until needed)
5134 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5136 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5141 /** Find a RouteTimeAxisView by the ID of its route */
5143 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5145 RouteTimeAxisView* v;
5147 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5148 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5149 if(v->route()->id() == id) {
5159 Editor::fit_route_group (RouteGroup *g)
5161 TrackViewList ts = axis_views_from_routes (g->route_list ());
5166 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5168 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5171 _session->cancel_audition ();
5175 if (_session->is_auditioning()) {
5176 _session->cancel_audition ();
5177 if (r == last_audition_region) {
5182 _session->audition_region (r);
5183 last_audition_region = r;
5188 Editor::hide_a_region (boost::shared_ptr<Region> r)
5190 r->set_hidden (true);
5194 Editor::show_a_region (boost::shared_ptr<Region> r)
5196 r->set_hidden (false);
5200 Editor::audition_region_from_region_list ()
5202 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5206 Editor::hide_region_from_region_list ()
5208 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5212 Editor::show_region_in_region_list ()
5214 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5218 Editor::step_edit_status_change (bool yn)
5221 start_step_editing ();
5223 stop_step_editing ();
5228 Editor::start_step_editing ()
5230 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5234 Editor::stop_step_editing ()
5236 step_edit_connection.disconnect ();
5240 Editor::check_step_edit ()
5242 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5243 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5245 mtv->check_step_edit ();
5249 return true; // do it again, till we stop
5253 Editor::scroll_press (Direction dir)
5255 ++_scroll_callbacks;
5257 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5258 /* delay the first auto-repeat */
5264 scroll_backward (1);
5272 scroll_up_one_track ();
5276 scroll_down_one_track ();
5280 /* do hacky auto-repeat */
5281 if (!_scroll_connection.connected ()) {
5283 _scroll_connection = Glib::signal_timeout().connect (
5284 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5287 _scroll_callbacks = 0;
5294 Editor::scroll_release ()
5296 _scroll_connection.disconnect ();
5299 /** Queue a change for the Editor viewport x origin to follow the playhead */
5301 Editor::reset_x_origin_to_follow_playhead ()
5303 framepos_t const frame = playhead_cursor->current_frame ();
5305 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5307 if (_session->transport_speed() < 0) {
5309 if (frame > (current_page_samples() / 2)) {
5310 center_screen (frame-(current_page_samples()/2));
5312 center_screen (current_page_samples()/2);
5319 if (frame < leftmost_frame) {
5321 if (_session->transport_rolling()) {
5322 /* rolling; end up with the playhead at the right of the page */
5323 l = frame - current_page_samples ();
5325 /* not rolling: end up with the playhead 1/4 of the way along the page */
5326 l = frame - current_page_samples() / 4;
5330 if (_session->transport_rolling()) {
5331 /* rolling: end up with the playhead on the left of the page */
5334 /* not rolling: end up with the playhead 3/4 of the way along the page */
5335 l = frame - 3 * current_page_samples() / 4;
5343 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5349 Editor::super_rapid_screen_update ()
5351 if (!_session || !_session->engine().running()) {
5355 /* METERING / MIXER STRIPS */
5357 /* update track meters, if required */
5358 if (is_mapped() && meters_running) {
5359 RouteTimeAxisView* rtv;
5360 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5361 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5362 rtv->fast_update ();
5367 /* and any current mixer strip */
5368 if (current_mixer_strip) {
5369 current_mixer_strip->fast_update ();
5372 /* PLAYHEAD AND VIEWPORT */
5374 framepos_t const frame = _session->audible_frame();
5376 /* There are a few reasons why we might not update the playhead / viewport stuff:
5378 * 1. we don't update things when there's a pending locate request, otherwise
5379 * when the editor requests a locate there is a chance that this method
5380 * will move the playhead before the locate request is processed, causing
5382 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5383 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5386 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5388 last_update_frame = frame;
5390 if (!_dragging_playhead) {
5391 playhead_cursor->set_position (frame);
5394 if (!_stationary_playhead) {
5396 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5397 /* We only do this if we aren't already
5398 handling a visual change (ie if
5399 pending_visual_change.being_handled is
5400 false) so that these requests don't stack
5401 up there are too many of them to handle in
5404 reset_x_origin_to_follow_playhead ();
5409 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5413 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5414 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5415 if (target <= 0.0) {
5418 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5419 target = (target * 0.15) + (current * 0.85);
5425 set_horizontal_position (current);
5434 Editor::session_going_away ()
5436 _have_idled = false;
5438 _session_connections.drop_connections ();
5440 super_rapid_screen_update_connection.disconnect ();
5442 selection->clear ();
5443 cut_buffer->clear ();
5445 clicked_regionview = 0;
5446 clicked_axisview = 0;
5447 clicked_routeview = 0;
5448 entered_regionview = 0;
5450 last_update_frame = 0;
5453 playhead_cursor->hide ();
5455 /* rip everything out of the list displays */
5459 _route_groups->clear ();
5461 /* do this first so that deleting a track doesn't reset cms to null
5462 and thus cause a leak.
5465 if (current_mixer_strip) {
5466 if (current_mixer_strip->get_parent() != 0) {
5467 global_hpacker.remove (*current_mixer_strip);
5469 delete current_mixer_strip;
5470 current_mixer_strip = 0;
5473 /* delete all trackviews */
5475 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5478 track_views.clear ();
5480 nudge_clock->set_session (0);
5482 editor_list_button.set_active(false);
5483 editor_list_button.set_sensitive(false);
5485 /* clear tempo/meter rulers */
5486 remove_metric_marks ();
5488 clear_marker_display ();
5490 stop_step_editing ();
5492 /* get rid of any existing editor mixer strip */
5494 WindowTitle title(Glib::get_application_name());
5495 title += _("Editor");
5497 set_title (title.get_string());
5499 SessionHandlePtr::session_going_away ();
5504 Editor::show_editor_list (bool yn)
5507 _the_notebook.show ();
5509 _the_notebook.hide ();
5514 Editor::change_region_layering_order (bool from_context_menu)
5516 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5518 if (!clicked_routeview) {
5519 if (layering_order_editor) {
5520 layering_order_editor->hide ();
5525 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5531 boost::shared_ptr<Playlist> pl = track->playlist();
5537 if (layering_order_editor == 0) {
5538 layering_order_editor = new RegionLayeringOrderEditor (*this);
5541 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5542 layering_order_editor->maybe_present ();
5546 Editor::update_region_layering_order_editor ()
5548 if (layering_order_editor && layering_order_editor->is_visible ()) {
5549 change_region_layering_order (true);
5554 Editor::setup_fade_images ()
5556 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5557 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5558 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5559 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5560 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5562 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5563 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5564 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5565 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5566 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5568 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5569 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5570 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5571 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5572 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5574 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5575 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5576 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5577 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5578 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5582 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5584 Editor::action_menu_item (std::string const & name)
5586 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5589 return *manage (a->create_menu_item ());
5593 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5595 EventBox* b = manage (new EventBox);
5596 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5597 Label* l = manage (new Label (name));
5601 _the_notebook.append_page (widget, *b);
5605 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5607 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5608 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5611 if (ev->type == GDK_2BUTTON_PRESS) {
5613 /* double-click on a notebook tab shrinks or expands the notebook */
5615 if (_notebook_shrunk) {
5616 if (pre_notebook_shrink_pane_width) {
5617 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5619 _notebook_shrunk = false;
5621 pre_notebook_shrink_pane_width = edit_pane.get_position();
5623 /* this expands the LHS of the edit pane to cover the notebook
5624 PAGE but leaves the tabs visible.
5626 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5627 _notebook_shrunk = true;
5635 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5637 using namespace Menu_Helpers;
5639 MenuList& items = _control_point_context_menu.items ();
5642 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5643 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5644 if (!can_remove_control_point (item)) {
5645 items.back().set_sensitive (false);
5648 _control_point_context_menu.popup (event->button.button, event->button.time);
5652 Editor::zoom_vertical_modifier_released()
5654 _stepping_axis_view = 0;
5658 Editor::ui_parameter_changed (string parameter)
5660 if (parameter == "icon-set") {
5661 while (!_cursor_stack.empty()) {
5662 _cursor_stack.pop();
5664 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5665 } else if (parameter == "draggable-playhead") {
5666 if (_verbose_cursor) {
5667 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());