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);
308 _selection_memento = new SelectionMemento ();
311 clicked_regionview = 0;
312 clicked_axisview = 0;
313 clicked_routeview = 0;
314 clicked_control_point = 0;
315 last_update_frame = 0;
318 _drags = new DragManager (this);
321 current_mixer_strip = 0;
324 snap_type_strings = I18N (_snap_type_strings);
325 snap_mode_strings = I18N (_snap_mode_strings);
326 zoom_focus_strings = I18N (_zoom_focus_strings);
327 edit_mode_strings = I18N (_edit_mode_strings);
328 edit_point_strings = I18N (_edit_point_strings);
329 #ifdef USE_RUBBERBAND
330 rb_opt_strings = I18N (_rb_opt_strings);
334 build_edit_mode_menu();
335 build_zoom_focus_menu();
336 build_track_count_menu();
337 build_snap_mode_menu();
338 build_snap_type_menu();
339 build_edit_point_menu();
341 snap_threshold = 5.0;
342 bbt_beat_subdivision = 4;
343 _visible_canvas_width = 0;
344 _visible_canvas_height = 0;
345 autoscroll_horizontal_allowed = false;
346 autoscroll_vertical_allowed = false;
351 current_interthread_info = 0;
352 _show_measures = true;
354 show_gain_after_trim = false;
356 have_pending_keyboard_selection = false;
357 _follow_playhead = true;
358 _stationary_playhead = false;
359 editor_ruler_menu = 0;
360 no_ruler_shown_update = false;
362 range_marker_menu = 0;
363 marker_menu_item = 0;
364 tempo_or_meter_marker_menu = 0;
365 transport_marker_menu = 0;
366 new_transport_marker_menu = 0;
367 editor_mixer_strip_width = Wide;
368 show_editor_mixer_when_tracks_arrive = false;
369 region_edit_menu_split_multichannel_item = 0;
370 region_edit_menu_split_item = 0;
373 current_stepping_trackview = 0;
375 entered_regionview = 0;
377 clear_entered_track = false;
380 button_release_can_deselect = true;
381 _dragging_playhead = false;
382 _dragging_edit_point = false;
383 select_new_marker = false;
385 layering_order_editor = 0;
386 no_save_visual = false;
388 within_track_canvas = false;
390 scrubbing_direction = 0;
394 location_marker_color = ARDOUR_UI::config()->color ("location marker");
395 location_range_color = ARDOUR_UI::config()->color ("location range");
396 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
397 location_loop_color = ARDOUR_UI::config()->color ("location loop");
398 location_punch_color = ARDOUR_UI::config()->color ("location punch");
400 zoom_focus = ZoomFocusLeft;
401 _edit_point = EditAtMouse;
402 _visible_track_count = -1;
404 samples_per_pixel = 2048; /* too early to use reset_zoom () */
406 _scroll_callbacks = 0;
408 bbt_label.set_name ("EditorRulerLabel");
409 bbt_label.set_size_request (-1, (int)timebar_height);
410 bbt_label.set_alignment (1.0, 0.5);
411 bbt_label.set_padding (5,0);
413 bbt_label.set_no_show_all();
414 minsec_label.set_name ("EditorRulerLabel");
415 minsec_label.set_size_request (-1, (int)timebar_height);
416 minsec_label.set_alignment (1.0, 0.5);
417 minsec_label.set_padding (5,0);
418 minsec_label.hide ();
419 minsec_label.set_no_show_all();
420 timecode_label.set_name ("EditorRulerLabel");
421 timecode_label.set_size_request (-1, (int)timebar_height);
422 timecode_label.set_alignment (1.0, 0.5);
423 timecode_label.set_padding (5,0);
424 timecode_label.hide ();
425 timecode_label.set_no_show_all();
426 samples_label.set_name ("EditorRulerLabel");
427 samples_label.set_size_request (-1, (int)timebar_height);
428 samples_label.set_alignment (1.0, 0.5);
429 samples_label.set_padding (5,0);
430 samples_label.hide ();
431 samples_label.set_no_show_all();
433 tempo_label.set_name ("EditorRulerLabel");
434 tempo_label.set_size_request (-1, (int)timebar_height);
435 tempo_label.set_alignment (1.0, 0.5);
436 tempo_label.set_padding (5,0);
438 tempo_label.set_no_show_all();
440 meter_label.set_name ("EditorRulerLabel");
441 meter_label.set_size_request (-1, (int)timebar_height);
442 meter_label.set_alignment (1.0, 0.5);
443 meter_label.set_padding (5,0);
445 meter_label.set_no_show_all();
447 if (Profile->get_trx()) {
448 mark_label.set_text (_("Markers"));
450 mark_label.set_name ("EditorRulerLabel");
451 mark_label.set_size_request (-1, (int)timebar_height);
452 mark_label.set_alignment (1.0, 0.5);
453 mark_label.set_padding (5,0);
455 mark_label.set_no_show_all();
457 cd_mark_label.set_name ("EditorRulerLabel");
458 cd_mark_label.set_size_request (-1, (int)timebar_height);
459 cd_mark_label.set_alignment (1.0, 0.5);
460 cd_mark_label.set_padding (5,0);
461 cd_mark_label.hide();
462 cd_mark_label.set_no_show_all();
464 videotl_bar_height = 4;
465 videotl_label.set_name ("EditorRulerLabel");
466 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
467 videotl_label.set_alignment (1.0, 0.5);
468 videotl_label.set_padding (5,0);
469 videotl_label.hide();
470 videotl_label.set_no_show_all();
472 range_mark_label.set_name ("EditorRulerLabel");
473 range_mark_label.set_size_request (-1, (int)timebar_height);
474 range_mark_label.set_alignment (1.0, 0.5);
475 range_mark_label.set_padding (5,0);
476 range_mark_label.hide();
477 range_mark_label.set_no_show_all();
479 transport_mark_label.set_name ("EditorRulerLabel");
480 transport_mark_label.set_size_request (-1, (int)timebar_height);
481 transport_mark_label.set_alignment (1.0, 0.5);
482 transport_mark_label.set_padding (5,0);
483 transport_mark_label.hide();
484 transport_mark_label.set_no_show_all();
486 initialize_canvas ();
488 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
490 _summary = new EditorSummary (this);
492 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
493 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
495 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
497 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
498 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
500 edit_controls_vbox.set_spacing (0);
501 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
502 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
504 HBox* h = manage (new HBox);
505 _group_tabs = new EditorGroupTabs (this);
506 if (!ARDOUR::Profile->get_trx()) {
507 h->pack_start (*_group_tabs, PACK_SHRINK);
509 h->pack_start (edit_controls_vbox);
510 controls_layout.add (*h);
512 controls_layout.set_name ("EditControlsBase");
513 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
514 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
515 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
517 _cursors = new MouseCursors;
518 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
519 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
521 /* Push default cursor to ever-present bottom of cursor stack. */
522 push_canvas_cursor(_cursors->grabber);
524 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
526 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
527 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
528 pad_line_1->set_outline_color (0xFF0000FF);
534 edit_packer.set_col_spacings (0);
535 edit_packer.set_row_spacings (0);
536 edit_packer.set_homogeneous (false);
537 edit_packer.set_border_width (0);
538 edit_packer.set_name ("EditorWindow");
540 time_bars_event_box.add (time_bars_vbox);
541 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
542 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
544 /* labels for the time bars */
545 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
547 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
549 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
551 bottom_hbox.set_border_width (2);
552 bottom_hbox.set_spacing (3);
554 _route_groups = new EditorRouteGroups (this);
555 _routes = new EditorRoutes (this);
556 _regions = new EditorRegions (this);
557 _snapshots = new EditorSnapshots (this);
558 _locations = new EditorLocations (this);
560 /* these are static location signals */
562 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
563 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
564 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
566 add_notebook_page (_("Regions"), _regions->widget ());
567 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
568 add_notebook_page (_("Snapshots"), _snapshots->widget ());
569 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
570 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
572 _the_notebook.set_show_tabs (true);
573 _the_notebook.set_scrollable (true);
574 _the_notebook.popup_disable ();
575 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
576 _the_notebook.show_all ();
578 _notebook_shrunk = false;
580 editor_summary_pane.pack1(edit_packer);
582 Button* summary_arrows_left_left = manage (new Button);
583 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
584 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
585 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
587 Button* summary_arrows_left_right = manage (new Button);
588 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
589 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
590 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
592 VBox* summary_arrows_left = manage (new VBox);
593 summary_arrows_left->pack_start (*summary_arrows_left_left);
594 summary_arrows_left->pack_start (*summary_arrows_left_right);
596 Button* summary_arrows_right_up = manage (new Button);
597 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
598 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
599 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
601 Button* summary_arrows_right_down = manage (new Button);
602 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
603 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
604 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
606 VBox* summary_arrows_right = manage (new VBox);
607 summary_arrows_right->pack_start (*summary_arrows_right_up);
608 summary_arrows_right->pack_start (*summary_arrows_right_down);
610 Frame* summary_frame = manage (new Frame);
611 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
613 summary_frame->add (*_summary);
614 summary_frame->show ();
616 _summary_hbox.pack_start (*summary_arrows_left, false, false);
617 _summary_hbox.pack_start (*summary_frame, true, true);
618 _summary_hbox.pack_start (*summary_arrows_right, false, false);
620 if (!ARDOUR::Profile->get_trx()) {
621 editor_summary_pane.pack2 (_summary_hbox);
624 edit_pane.pack1 (editor_summary_pane, true, true);
625 if (!ARDOUR::Profile->get_trx()) {
626 edit_pane.pack2 (_the_notebook, false, true);
629 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
631 /* XXX: editor_summary_pane might need similar to the edit_pane */
633 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
635 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
636 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
638 top_hbox.pack_start (toolbar_frame);
640 HBox *hbox = manage (new HBox);
641 hbox->pack_start (edit_pane, true, true);
643 global_vpacker.pack_start (top_hbox, false, false);
644 global_vpacker.pack_start (*hbox, true, true);
646 global_hpacker.pack_start (global_vpacker, true, true);
648 set_name ("EditorWindow");
649 add_accel_group (ActionManager::ui_manager->get_accel_group());
651 status_bar_hpacker.show ();
653 vpacker.pack_end (status_bar_hpacker, false, false);
654 vpacker.pack_end (global_hpacker, true, true);
656 /* register actions now so that set_state() can find them and set toggles/checks etc */
659 /* when we start using our own keybinding system for the editor, this
660 * will be uncommented
666 set_zoom_focus (zoom_focus);
667 set_visible_track_count (_visible_track_count);
668 _snap_type = SnapToBeat;
669 set_snap_to (_snap_type);
670 _snap_mode = SnapOff;
671 set_snap_mode (_snap_mode);
672 set_mouse_mode (MouseObject, true);
673 pre_internal_mouse_mode = MouseObject;
674 pre_internal_snap_type = _snap_type;
675 pre_internal_snap_mode = _snap_mode;
676 internal_snap_type = _snap_type;
677 internal_snap_mode = _snap_mode;
678 set_edit_point_preference (EditAtMouse, true);
680 _playlist_selector = new PlaylistSelector();
681 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
683 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
687 nudge_forward_button.set_name ("nudge button");
688 nudge_forward_button.set_image(::get_icon("nudge_right"));
690 nudge_backward_button.set_name ("nudge button");
691 nudge_backward_button.set_image(::get_icon("nudge_left"));
693 fade_context_menu.set_name ("ArdourContextMenu");
695 /* icons, titles, WM stuff */
697 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
698 Glib::RefPtr<Gdk::Pixbuf> icon;
700 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
701 window_icons.push_back (icon);
703 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
704 window_icons.push_back (icon);
706 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
707 window_icons.push_back (icon);
709 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
710 window_icons.push_back (icon);
712 if (!window_icons.empty()) {
713 // set_icon_list (window_icons);
714 set_default_icon_list (window_icons);
717 WindowTitle title(Glib::get_application_name());
718 title += _("Editor");
719 set_title (title.get_string());
720 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
723 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
725 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
726 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
728 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
730 /* allow external control surfaces/protocols to do various things */
732 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
733 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
734 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
735 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
736 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
737 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
738 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
739 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
740 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
741 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
742 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
743 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
744 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
745 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
747 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
748 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
749 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
750 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
751 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
753 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
755 /* problematic: has to return a value and thus cannot be x-thread */
757 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
759 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
760 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
762 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
764 _ignore_region_action = false;
765 _last_region_menu_was_main = false;
766 _popup_region_menu_item = 0;
768 _ignore_follow_edits = false;
770 _show_marker_lines = false;
772 /* Button bindings */
774 button_bindings = new Bindings;
776 XMLNode* node = button_settings();
778 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
779 button_bindings->load (**i);
785 /* grab current parameter state */
786 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
787 ARDOUR_UI::config()->map_parameters (pc);
789 setup_fade_images ();
796 delete button_bindings;
798 delete _route_groups;
799 delete _track_canvas_viewport;
805 Editor::button_settings () const
807 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
808 XMLNode* node = find_named_node (*settings, X_("Buttons"));
811 node = new XMLNode (X_("Buttons"));
818 Editor::add_toplevel_menu (Container& cont)
820 vpacker.pack_start (cont, false, false);
825 Editor::add_transport_frame (Container& cont)
827 if(ARDOUR::Profile->get_mixbus()) {
828 global_vpacker.pack_start (cont, false, false);
829 global_vpacker.reorder_child (cont, 0);
832 vpacker.pack_start (cont, false, false);
837 Editor::get_smart_mode () const
839 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
843 Editor::catch_vanishing_regionview (RegionView *rv)
845 /* note: the selection will take care of the vanishing
846 audioregionview by itself.
849 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
853 if (clicked_regionview == rv) {
854 clicked_regionview = 0;
857 if (entered_regionview == rv) {
858 set_entered_regionview (0);
861 if (!_all_region_actions_sensitized) {
862 sensitize_all_region_actions (true);
867 Editor::set_entered_regionview (RegionView* rv)
869 if (rv == entered_regionview) {
873 if (entered_regionview) {
874 entered_regionview->exited ();
877 entered_regionview = rv;
879 if (entered_regionview != 0) {
880 entered_regionview->entered ();
883 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
884 /* This RegionView entry might have changed what region actions
885 are allowed, so sensitize them all in case a key is pressed.
887 sensitize_all_region_actions (true);
892 Editor::set_entered_track (TimeAxisView* tav)
895 entered_track->exited ();
901 entered_track->entered ();
906 Editor::show_window ()
908 if (!is_visible ()) {
912 /* XXX: this is a bit unfortunate; it would probably
913 be nicer if we could just call show () above rather
914 than needing the show_all ()
917 /* re-hide stuff if necessary */
918 editor_list_button_toggled ();
919 parameter_changed ("show-summary");
920 parameter_changed ("show-group-tabs");
921 parameter_changed ("show-zoom-tools");
923 /* now reset all audio_time_axis heights, because widgets might need
929 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
930 tv = (static_cast<TimeAxisView*>(*i));
934 if (current_mixer_strip) {
935 current_mixer_strip->hide_things ();
936 current_mixer_strip->parameter_changed ("mixer-element-visibility");
944 Editor::instant_save ()
946 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
951 _session->add_instant_xml(get_state());
953 Config->add_instant_xml(get_state());
958 Editor::control_vertical_zoom_in_all ()
960 tav_zoom_smooth (false, true);
964 Editor::control_vertical_zoom_out_all ()
966 tav_zoom_smooth (true, true);
970 Editor::control_vertical_zoom_in_selected ()
972 tav_zoom_smooth (false, false);
976 Editor::control_vertical_zoom_out_selected ()
978 tav_zoom_smooth (true, false);
982 Editor::control_view (uint32_t view)
984 goto_visual_state (view);
988 Editor::control_unselect ()
990 selection->clear_tracks ();
994 Editor::control_select (uint32_t rid, Selection::Operation op)
996 /* handles the (static) signal from the ControlProtocol class that
997 * requests setting the selected track to a given RID
1004 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1010 TimeAxisView* tav = axis_view_from_route (r);
1014 case Selection::Add:
1015 selection->add (tav);
1017 case Selection::Toggle:
1018 selection->toggle (tav);
1020 case Selection::Extend:
1022 case Selection::Set:
1023 selection->set (tav);
1027 selection->clear_tracks ();
1032 Editor::control_step_tracks_up ()
1034 scroll_tracks_up_line ();
1038 Editor::control_step_tracks_down ()
1040 scroll_tracks_down_line ();
1044 Editor::control_scroll (float fraction)
1046 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1052 double step = fraction * current_page_samples();
1055 _control_scroll_target is an optional<T>
1057 it acts like a pointer to an framepos_t, with
1058 a operator conversion to boolean to check
1059 that it has a value could possibly use
1060 playhead_cursor->current_frame to store the
1061 value and a boolean in the class to know
1062 when it's out of date
1065 if (!_control_scroll_target) {
1066 _control_scroll_target = _session->transport_frame();
1067 _dragging_playhead = true;
1070 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1071 *_control_scroll_target = 0;
1072 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1073 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1075 *_control_scroll_target += (framepos_t) trunc (step);
1078 /* move visuals, we'll catch up with it later */
1080 playhead_cursor->set_position (*_control_scroll_target);
1081 UpdateAllTransportClocks (*_control_scroll_target);
1083 if (*_control_scroll_target > (current_page_samples() / 2)) {
1084 /* try to center PH in window */
1085 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1091 Now we do a timeout to actually bring the session to the right place
1092 according to the playhead. This is to avoid reading disk buffers on every
1093 call to control_scroll, which is driven by ScrollTimeline and therefore
1094 probably by a control surface wheel which can generate lots of events.
1096 /* cancel the existing timeout */
1098 control_scroll_connection.disconnect ();
1100 /* add the next timeout */
1102 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1106 Editor::deferred_control_scroll (framepos_t /*target*/)
1108 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1109 // reset for next stream
1110 _control_scroll_target = boost::none;
1111 _dragging_playhead = false;
1116 Editor::access_action (std::string action_group, std::string action_item)
1122 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1125 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1133 Editor::on_realize ()
1135 Window::on_realize ();
1138 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1139 start_lock_event_timing ();
1142 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1146 Editor::start_lock_event_timing ()
1148 /* check if we should lock the GUI every 30 seconds */
1150 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1154 Editor::generic_event_handler (GdkEvent* ev)
1157 case GDK_BUTTON_PRESS:
1158 case GDK_BUTTON_RELEASE:
1159 case GDK_MOTION_NOTIFY:
1161 case GDK_KEY_RELEASE:
1162 gettimeofday (&last_event_time, 0);
1165 case GDK_LEAVE_NOTIFY:
1166 switch (ev->crossing.detail) {
1167 case GDK_NOTIFY_UNKNOWN:
1168 case GDK_NOTIFY_INFERIOR:
1169 case GDK_NOTIFY_ANCESTOR:
1171 case GDK_NOTIFY_VIRTUAL:
1172 case GDK_NOTIFY_NONLINEAR:
1173 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1174 /* leaving window, so reset focus, thus ending any and
1175 all text entry operations.
1190 Editor::lock_timeout_callback ()
1192 struct timeval now, delta;
1194 gettimeofday (&now, 0);
1196 timersub (&now, &last_event_time, &delta);
1198 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1200 /* don't call again. Returning false will effectively
1201 disconnect us from the timer callback.
1203 unlock() will call start_lock_event_timing() to get things
1213 Editor::map_position_change (framepos_t frame)
1215 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1217 if (_session == 0) {
1221 if (_follow_playhead) {
1222 center_screen (frame);
1225 playhead_cursor->set_position (frame);
1229 Editor::center_screen (framepos_t frame)
1231 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1233 /* if we're off the page, then scroll.
1236 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1237 center_screen_internal (frame, page);
1242 Editor::center_screen_internal (framepos_t frame, float page)
1247 frame -= (framepos_t) page;
1252 reset_x_origin (frame);
1257 Editor::update_title ()
1259 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1262 bool dirty = _session->dirty();
1264 string session_name;
1266 if (_session->snap_name() != _session->name()) {
1267 session_name = _session->snap_name();
1269 session_name = _session->name();
1273 session_name = "*" + session_name;
1276 WindowTitle title(session_name);
1277 title += Glib::get_application_name();
1278 set_title (title.get_string());
1280 /* ::session_going_away() will have taken care of it */
1285 Editor::set_session (Session *t)
1287 SessionHandlePtr::set_session (t);
1293 _playlist_selector->set_session (_session);
1294 nudge_clock->set_session (_session);
1295 _summary->set_session (_session);
1296 _group_tabs->set_session (_session);
1297 _route_groups->set_session (_session);
1298 _regions->set_session (_session);
1299 _snapshots->set_session (_session);
1300 _routes->set_session (_session);
1301 _locations->set_session (_session);
1303 if (rhythm_ferret) {
1304 rhythm_ferret->set_session (_session);
1307 if (analysis_window) {
1308 analysis_window->set_session (_session);
1312 sfbrowser->set_session (_session);
1315 compute_fixed_ruler_scale ();
1317 /* Make sure we have auto loop and auto punch ranges */
1319 Location* loc = _session->locations()->auto_loop_location();
1321 loc->set_name (_("Loop"));
1324 loc = _session->locations()->auto_punch_location();
1327 loc->set_name (_("Punch"));
1330 refresh_location_display ();
1332 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1333 the selected Marker; this needs the LocationMarker list to be available.
1335 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1336 set_state (*node, Stateful::loading_state_version);
1338 /* catch up with the playhead */
1340 _session->request_locate (playhead_cursor->current_frame ());
1341 _pending_initial_locate = true;
1345 /* These signals can all be emitted by a non-GUI thread. Therefore the
1346 handlers for them must not attempt to directly interact with the GUI,
1347 but use PBD::Signal<T>::connect() which accepts an event loop
1348 ("context") where the handler will be asked to run.
1351 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1352 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1353 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1354 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1355 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1356 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1357 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1358 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1359 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1360 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1361 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1362 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1363 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1365 playhead_cursor->show ();
1367 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1368 Config->map_parameters (pc);
1369 _session->config.map_parameters (pc);
1371 restore_ruler_visibility ();
1372 //tempo_map_changed (PropertyChange (0));
1373 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1375 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1376 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1379 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1380 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1383 switch (_snap_type) {
1384 case SnapToRegionStart:
1385 case SnapToRegionEnd:
1386 case SnapToRegionSync:
1387 case SnapToRegionBoundary:
1388 build_region_boundary_cache ();
1395 /* register for undo history */
1396 _session->register_with_memento_command_factory(id(), this);
1397 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1399 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1401 start_updating_meters ();
1405 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1407 if (a->get_name() == "RegionMenu") {
1408 /* When the main menu's region menu is opened, we setup the actions so that they look right
1409 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1410 so we resensitize all region actions when the entered regionview or the region selection
1411 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1412 happens after the region context menu is opened. So we set a flag here, too.
1416 sensitize_the_right_region_actions ();
1417 _last_region_menu_was_main = true;
1422 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1424 using namespace Menu_Helpers;
1426 void (Editor::*emf)(FadeShape);
1427 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1430 images = &_xfade_in_images;
1431 emf = &Editor::set_fade_in_shape;
1433 images = &_xfade_out_images;
1434 emf = &Editor::set_fade_out_shape;
1439 _("Linear (for highly correlated material)"),
1440 *(*images)[FadeLinear],
1441 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1445 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1449 _("Constant power"),
1450 *(*images)[FadeConstantPower],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1454 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 *(*images)[FadeSymmetric],
1460 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSlow],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *(*images)[FadeFast],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 /** Pop up a context menu for when the user clicks on a start crossfade */
1487 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1489 using namespace Menu_Helpers;
1490 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1495 MenuList& items (xfade_in_context_menu.items());
1498 if (arv->audio_region()->fade_in_active()) {
1499 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1501 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1504 items.push_back (SeparatorElem());
1505 fill_xfade_menu (items, true);
1507 xfade_in_context_menu.popup (button, time);
1510 /** Pop up a context menu for when the user clicks on an end crossfade */
1512 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1514 using namespace Menu_Helpers;
1515 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1520 MenuList& items (xfade_out_context_menu.items());
1523 if (arv->audio_region()->fade_out_active()) {
1524 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1526 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1529 items.push_back (SeparatorElem());
1530 fill_xfade_menu (items, false);
1532 xfade_out_context_menu.popup (button, time);
1536 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1538 using namespace Menu_Helpers;
1539 Menu* (Editor::*build_menu_function)();
1542 switch (item_type) {
1544 case RegionViewName:
1545 case RegionViewNameHighlight:
1546 case LeftFrameHandle:
1547 case RightFrameHandle:
1548 if (with_selection) {
1549 build_menu_function = &Editor::build_track_selection_context_menu;
1551 build_menu_function = &Editor::build_track_region_context_menu;
1556 if (with_selection) {
1557 build_menu_function = &Editor::build_track_selection_context_menu;
1559 build_menu_function = &Editor::build_track_context_menu;
1564 if (clicked_routeview->track()) {
1565 build_menu_function = &Editor::build_track_context_menu;
1567 build_menu_function = &Editor::build_track_bus_context_menu;
1572 /* probably shouldn't happen but if it does, we don't care */
1576 menu = (this->*build_menu_function)();
1577 menu->set_name ("ArdourContextMenu");
1579 /* now handle specific situations */
1581 switch (item_type) {
1583 case RegionViewName:
1584 case RegionViewNameHighlight:
1585 case LeftFrameHandle:
1586 case RightFrameHandle:
1587 if (!with_selection) {
1588 if (region_edit_menu_split_item) {
1589 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1590 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1592 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1595 if (region_edit_menu_split_multichannel_item) {
1596 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1597 region_edit_menu_split_multichannel_item->set_sensitive (true);
1599 region_edit_menu_split_multichannel_item->set_sensitive (false);
1612 /* probably shouldn't happen but if it does, we don't care */
1616 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1618 /* Bounce to disk */
1620 using namespace Menu_Helpers;
1621 MenuList& edit_items = menu->items();
1623 edit_items.push_back (SeparatorElem());
1625 switch (clicked_routeview->audio_track()->freeze_state()) {
1626 case AudioTrack::NoFreeze:
1627 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1630 case AudioTrack::Frozen:
1631 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1634 case AudioTrack::UnFrozen:
1635 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1641 if (item_type == StreamItem && clicked_routeview) {
1642 clicked_routeview->build_underlay_menu(menu);
1645 /* When the region menu is opened, we setup the actions so that they look right
1648 sensitize_the_right_region_actions ();
1649 _last_region_menu_was_main = false;
1651 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1652 menu->popup (button, time);
1656 Editor::build_track_context_menu ()
1658 using namespace Menu_Helpers;
1660 MenuList& edit_items = track_context_menu.items();
1663 add_dstream_context_items (edit_items);
1664 return &track_context_menu;
1668 Editor::build_track_bus_context_menu ()
1670 using namespace Menu_Helpers;
1672 MenuList& edit_items = track_context_menu.items();
1675 add_bus_context_items (edit_items);
1676 return &track_context_menu;
1680 Editor::build_track_region_context_menu ()
1682 using namespace Menu_Helpers;
1683 MenuList& edit_items = track_region_context_menu.items();
1686 /* we've just cleared the track region context menu, so the menu that these
1687 two items were on will have disappeared; stop them dangling.
1689 region_edit_menu_split_item = 0;
1690 region_edit_menu_split_multichannel_item = 0;
1692 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1695 boost::shared_ptr<Track> tr;
1696 boost::shared_ptr<Playlist> pl;
1698 if ((tr = rtv->track())) {
1699 add_region_context_items (edit_items, tr);
1703 add_dstream_context_items (edit_items);
1705 return &track_region_context_menu;
1709 Editor::analyze_region_selection ()
1711 if (analysis_window == 0) {
1712 analysis_window = new AnalysisWindow();
1715 analysis_window->set_session(_session);
1717 analysis_window->show_all();
1720 analysis_window->set_regionmode();
1721 analysis_window->analyze();
1723 analysis_window->present();
1727 Editor::analyze_range_selection()
1729 if (analysis_window == 0) {
1730 analysis_window = new AnalysisWindow();
1733 analysis_window->set_session(_session);
1735 analysis_window->show_all();
1738 analysis_window->set_rangemode();
1739 analysis_window->analyze();
1741 analysis_window->present();
1745 Editor::build_track_selection_context_menu ()
1747 using namespace Menu_Helpers;
1748 MenuList& edit_items = track_selection_context_menu.items();
1749 edit_items.clear ();
1751 add_selection_context_items (edit_items);
1752 // edit_items.push_back (SeparatorElem());
1753 // add_dstream_context_items (edit_items);
1755 return &track_selection_context_menu;
1759 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1761 using namespace Menu_Helpers;
1763 /* OK, stick the region submenu at the top of the list, and then add
1767 RegionSelection rs = get_regions_from_selection_and_entered ();
1769 string::size_type pos = 0;
1770 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1772 /* we have to hack up the region name because "_" has a special
1773 meaning for menu titles.
1776 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1777 menu_item_name.replace (pos, 1, "__");
1781 if (_popup_region_menu_item == 0) {
1782 _popup_region_menu_item = new MenuItem (menu_item_name);
1783 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1784 _popup_region_menu_item->show ();
1786 _popup_region_menu_item->set_label (menu_item_name);
1789 const framepos_t position = get_preferred_edit_position (false, true);
1791 edit_items.push_back (*_popup_region_menu_item);
1792 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1793 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1795 edit_items.push_back (SeparatorElem());
1798 /** Add context menu items relevant to selection ranges.
1799 * @param edit_items List to add the items to.
1802 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1804 using namespace Menu_Helpers;
1806 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1807 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1809 edit_items.push_back (SeparatorElem());
1810 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1812 edit_items.push_back (SeparatorElem());
1813 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1815 edit_items.push_back (SeparatorElem());
1817 edit_items.push_back (
1819 _("Move Range Start to Previous Region Boundary"),
1820 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1824 edit_items.push_back (
1826 _("Move Range Start to Next Region Boundary"),
1827 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1831 edit_items.push_back (
1833 _("Move Range End to Previous Region Boundary"),
1834 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1838 edit_items.push_back (
1840 _("Move Range End to Next Region Boundary"),
1841 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1845 edit_items.push_back (SeparatorElem());
1846 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1847 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1849 edit_items.push_back (SeparatorElem());
1850 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1852 edit_items.push_back (SeparatorElem());
1853 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1854 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1855 edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1857 edit_items.push_back (SeparatorElem());
1858 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1860 edit_items.push_back (SeparatorElem());
1861 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1862 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1863 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1867 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1868 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1869 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1870 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1871 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1872 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1878 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1880 using namespace Menu_Helpers;
1884 Menu *play_menu = manage (new Menu);
1885 MenuList& play_items = play_menu->items();
1886 play_menu->set_name ("ArdourContextMenu");
1888 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1889 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1890 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1891 play_items.push_back (SeparatorElem());
1892 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1894 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1898 Menu *select_menu = manage (new Menu);
1899 MenuList& select_items = select_menu->items();
1900 select_menu->set_name ("ArdourContextMenu");
1902 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1903 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1904 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1905 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1906 select_items.push_back (SeparatorElem());
1907 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1908 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1909 select_items.push_back (SeparatorElem());
1910 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1911 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1912 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1913 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1914 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1915 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1916 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1918 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1922 Menu *cutnpaste_menu = manage (new Menu);
1923 MenuList& cutnpaste_items = cutnpaste_menu->items();
1924 cutnpaste_menu->set_name ("ArdourContextMenu");
1926 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1927 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1928 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1930 cutnpaste_items.push_back (SeparatorElem());
1932 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1933 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1935 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1937 /* Adding new material */
1939 edit_items.push_back (SeparatorElem());
1940 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1941 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1945 Menu *nudge_menu = manage (new Menu());
1946 MenuList& nudge_items = nudge_menu->items();
1947 nudge_menu->set_name ("ArdourContextMenu");
1949 edit_items.push_back (SeparatorElem());
1950 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1951 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1952 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1953 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1955 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1959 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1961 using namespace Menu_Helpers;
1965 Menu *play_menu = manage (new Menu);
1966 MenuList& play_items = play_menu->items();
1967 play_menu->set_name ("ArdourContextMenu");
1969 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1970 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1971 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1975 Menu *select_menu = manage (new Menu);
1976 MenuList& select_items = select_menu->items();
1977 select_menu->set_name ("ArdourContextMenu");
1979 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1980 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1981 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1982 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1983 select_items.push_back (SeparatorElem());
1984 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1985 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1986 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1987 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1989 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1993 Menu *cutnpaste_menu = manage (new Menu);
1994 MenuList& cutnpaste_items = cutnpaste_menu->items();
1995 cutnpaste_menu->set_name ("ArdourContextMenu");
1997 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1998 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1999 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2001 Menu *nudge_menu = manage (new Menu());
2002 MenuList& nudge_items = nudge_menu->items();
2003 nudge_menu->set_name ("ArdourContextMenu");
2005 edit_items.push_back (SeparatorElem());
2006 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2007 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2008 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2009 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2011 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2015 Editor::snap_type() const
2021 Editor::snap_mode() const
2027 Editor::set_snap_to (SnapType st)
2029 unsigned int snap_ind = (unsigned int)st;
2033 if (snap_ind > snap_type_strings.size() - 1) {
2035 _snap_type = (SnapType)snap_ind;
2038 string str = snap_type_strings[snap_ind];
2040 if (str != snap_type_selector.get_text()) {
2041 snap_type_selector.set_text (str);
2046 switch (_snap_type) {
2047 case SnapToBeatDiv128:
2048 case SnapToBeatDiv64:
2049 case SnapToBeatDiv32:
2050 case SnapToBeatDiv28:
2051 case SnapToBeatDiv24:
2052 case SnapToBeatDiv20:
2053 case SnapToBeatDiv16:
2054 case SnapToBeatDiv14:
2055 case SnapToBeatDiv12:
2056 case SnapToBeatDiv10:
2057 case SnapToBeatDiv8:
2058 case SnapToBeatDiv7:
2059 case SnapToBeatDiv6:
2060 case SnapToBeatDiv5:
2061 case SnapToBeatDiv4:
2062 case SnapToBeatDiv3:
2063 case SnapToBeatDiv2: {
2064 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2065 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2067 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2068 current_bbt_points_begin, current_bbt_points_end);
2069 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2070 current_bbt_points_begin, current_bbt_points_end);
2071 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2075 case SnapToRegionStart:
2076 case SnapToRegionEnd:
2077 case SnapToRegionSync:
2078 case SnapToRegionBoundary:
2079 build_region_boundary_cache ();
2087 SnapChanged (); /* EMIT SIGNAL */
2091 Editor::set_snap_mode (SnapMode mode)
2093 string str = snap_mode_strings[(int)mode];
2095 if (internal_editing()) {
2096 internal_snap_mode = mode;
2098 pre_internal_snap_mode = mode;
2103 if (str != snap_mode_selector.get_text ()) {
2104 snap_mode_selector.set_text (str);
2110 Editor::set_edit_point_preference (EditPoint ep, bool force)
2112 bool changed = (_edit_point != ep);
2115 if (Profile->get_mixbus())
2116 if (ep == EditAtSelectedMarker)
2117 ep = EditAtPlayhead;
2119 string str = edit_point_strings[(int)ep];
2120 if (str != edit_point_selector.get_text ()) {
2121 edit_point_selector.set_text (str);
2124 update_all_enter_cursors();
2126 if (!force && !changed) {
2130 const char* action=NULL;
2132 switch (_edit_point) {
2133 case EditAtPlayhead:
2134 action = "edit-at-playhead";
2136 case EditAtSelectedMarker:
2137 action = "edit-at-marker";
2140 action = "edit-at-mouse";
2144 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2146 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2150 bool in_track_canvas;
2152 if (!mouse_frame (foo, in_track_canvas)) {
2153 in_track_canvas = false;
2156 reset_canvas_action_sensitivity (in_track_canvas);
2162 Editor::set_state (const XMLNode& node, int /*version*/)
2164 const XMLProperty* prop;
2171 g.base_width = default_width;
2172 g.base_height = default_height;
2176 if ((geometry = find_named_node (node, "geometry")) != 0) {
2180 if ((prop = geometry->property("x_size")) == 0) {
2181 prop = geometry->property ("x-size");
2184 g.base_width = atoi(prop->value());
2186 if ((prop = geometry->property("y_size")) == 0) {
2187 prop = geometry->property ("y-size");
2190 g.base_height = atoi(prop->value());
2193 if ((prop = geometry->property ("x_pos")) == 0) {
2194 prop = geometry->property ("x-pos");
2197 x = atoi (prop->value());
2200 if ((prop = geometry->property ("y_pos")) == 0) {
2201 prop = geometry->property ("y-pos");
2204 y = atoi (prop->value());
2208 set_default_size (g.base_width, g.base_height);
2211 if (_session && (prop = node.property ("playhead"))) {
2213 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2215 playhead_cursor->set_position (pos);
2217 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2218 playhead_cursor->set_position (0);
2221 playhead_cursor->set_position (0);
2224 if ((prop = node.property ("mixer-width"))) {
2225 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2228 if ((prop = node.property ("zoom-focus"))) {
2229 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2232 if ((prop = node.property ("zoom"))) {
2233 /* older versions of ardour used floating point samples_per_pixel */
2234 double f = PBD::atof (prop->value());
2235 reset_zoom (llrintf (f));
2237 reset_zoom (samples_per_pixel);
2240 if ((prop = node.property ("visible-track-count"))) {
2241 set_visible_track_count (PBD::atoi (prop->value()));
2244 if ((prop = node.property ("snap-to"))) {
2245 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2248 if ((prop = node.property ("snap-mode"))) {
2249 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2252 if ((prop = node.property ("internal-snap-to"))) {
2253 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2256 if ((prop = node.property ("internal-snap-mode"))) {
2257 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2260 if ((prop = node.property ("pre-internal-snap-to"))) {
2261 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2264 if ((prop = node.property ("pre-internal-snap-mode"))) {
2265 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2268 if ((prop = node.property ("mouse-mode"))) {
2269 MouseMode m = str2mousemode(prop->value());
2270 set_mouse_mode (m, true);
2272 set_mouse_mode (MouseObject, true);
2275 if ((prop = node.property ("left-frame")) != 0) {
2277 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2281 reset_x_origin (pos);
2285 if ((prop = node.property ("y-origin")) != 0) {
2286 reset_y_origin (atof (prop->value ()));
2289 if ((prop = node.property ("join-object-range"))) {
2290 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2291 bool yn = string_is_affirmative (prop->value());
2293 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2294 tact->set_active (!yn);
2295 tact->set_active (yn);
2297 set_mouse_mode(mouse_mode, true);
2300 if ((prop = node.property ("edit-point"))) {
2301 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2304 if ((prop = node.property ("show-measures"))) {
2305 bool yn = string_is_affirmative (prop->value());
2306 _show_measures = yn;
2307 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2309 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2310 /* do it twice to force the change */
2311 tact->set_active (!yn);
2312 tact->set_active (yn);
2316 if ((prop = node.property ("follow-playhead"))) {
2317 bool yn = string_is_affirmative (prop->value());
2318 set_follow_playhead (yn);
2319 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2321 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322 if (tact->get_active() != yn) {
2323 tact->set_active (yn);
2328 if ((prop = node.property ("stationary-playhead"))) {
2329 bool yn = string_is_affirmative (prop->value());
2330 set_stationary_playhead (yn);
2331 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2333 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2334 if (tact->get_active() != yn) {
2335 tact->set_active (yn);
2340 if ((prop = node.property ("region-list-sort-type"))) {
2341 RegionListSortType st;
2342 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2345 if ((prop = node.property ("show-editor-mixer"))) {
2347 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2350 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2351 bool yn = string_is_affirmative (prop->value());
2353 /* do it twice to force the change */
2355 tact->set_active (!yn);
2356 tact->set_active (yn);
2359 if ((prop = node.property ("show-editor-list"))) {
2361 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2364 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2365 bool yn = string_is_affirmative (prop->value());
2367 /* do it twice to force the change */
2369 tact->set_active (!yn);
2370 tact->set_active (yn);
2373 if ((prop = node.property (X_("editor-list-page")))) {
2374 _the_notebook.set_current_page (atoi (prop->value ()));
2377 if ((prop = node.property (X_("show-marker-lines")))) {
2378 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2380 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2381 bool yn = string_is_affirmative (prop->value ());
2383 tact->set_active (!yn);
2384 tact->set_active (yn);
2387 XMLNodeList children = node.children ();
2388 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2389 selection->set_state (**i, Stateful::current_state_version);
2390 _regions->set_state (**i);
2393 if ((prop = node.property ("maximised"))) {
2394 bool yn = string_is_affirmative (prop->value());
2395 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2397 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2398 bool fs = tact && tact->get_active();
2400 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2404 if ((prop = node.property ("nudge-clock-value"))) {
2406 sscanf (prop->value().c_str(), "%" PRId64, &f);
2407 nudge_clock->set (f);
2409 nudge_clock->set_mode (AudioClock::Timecode);
2410 nudge_clock->set (_session->frame_rate() * 5, true);
2417 Editor::get_state ()
2419 XMLNode* node = new XMLNode ("Editor");
2422 id().print (buf, sizeof (buf));
2423 node->add_property ("id", buf);
2425 if (is_realized()) {
2426 Glib::RefPtr<Gdk::Window> win = get_window();
2428 int x, y, width, height;
2429 win->get_root_origin(x, y);
2430 win->get_size(width, height);
2432 XMLNode* geometry = new XMLNode ("geometry");
2434 snprintf(buf, sizeof(buf), "%d", width);
2435 geometry->add_property("x-size", string(buf));
2436 snprintf(buf, sizeof(buf), "%d", height);
2437 geometry->add_property("y-size", string(buf));
2438 snprintf(buf, sizeof(buf), "%d", x);
2439 geometry->add_property("x-pos", string(buf));
2440 snprintf(buf, sizeof(buf), "%d", y);
2441 geometry->add_property("y-pos", string(buf));
2442 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2443 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2444 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2445 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2446 geometry->add_property("edit-vertical-pane-pos", string(buf));
2448 node->add_child_nocopy (*geometry);
2451 maybe_add_mixer_strip_width (*node);
2453 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2455 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2456 node->add_property ("zoom", buf);
2457 node->add_property ("snap-to", enum_2_string (_snap_type));
2458 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2459 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2460 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2461 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2462 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2463 node->add_property ("edit-point", enum_2_string (_edit_point));
2464 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2465 node->add_property ("visible-track-count", buf);
2467 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2468 node->add_property ("playhead", buf);
2469 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2470 node->add_property ("left-frame", buf);
2471 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2472 node->add_property ("y-origin", buf);
2474 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2475 node->add_property ("maximised", _maximised ? "yes" : "no");
2476 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2477 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2478 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2479 node->add_property ("mouse-mode", enum2str(mouse_mode));
2480 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2482 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2484 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2485 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2488 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2490 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2491 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2494 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2495 node->add_property (X_("editor-list-page"), buf);
2497 if (button_bindings) {
2498 XMLNode* bb = new XMLNode (X_("Buttons"));
2499 button_bindings->save (*bb);
2500 node->add_child_nocopy (*bb);
2503 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2505 node->add_child_nocopy (selection->get_state ());
2506 node->add_child_nocopy (_regions->get_state ());
2508 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2509 node->add_property ("nudge-clock-value", buf);
2514 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2515 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2517 * @return pair: TimeAxisView that y is over, layer index.
2519 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2520 * in stacked or expanded region display mode, otherwise 0.
2522 std::pair<TimeAxisView *, double>
2523 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2525 if (!trackview_relative_offset) {
2526 y -= _trackview_group->canvas_origin().y;
2530 return std::make_pair ( (TimeAxisView *) 0, 0);
2533 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2535 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2542 return std::make_pair ( (TimeAxisView *) 0, 0);
2545 /** Snap a position to the grid, if appropriate, taking into account current
2546 * grid settings and also the state of any snap modifier keys that may be pressed.
2547 * @param start Position to snap.
2548 * @param event Event to get current key modifier information from, or 0.
2551 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2553 if (!_session || !event) {
2557 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2558 if (_snap_mode == SnapOff) {
2559 snap_to_internal (start, direction, for_mark);
2562 if (_snap_mode != SnapOff) {
2563 snap_to_internal (start, direction, for_mark);
2569 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2571 if (!_session || _snap_mode == SnapOff) {
2575 snap_to_internal (start, direction, for_mark);
2579 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2581 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2582 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2584 switch (_snap_type) {
2585 case SnapToTimecodeFrame:
2586 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2587 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2588 /* start is already on a whole timecode frame, do nothing */
2589 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2590 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2592 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2596 case SnapToTimecodeSeconds:
2597 if (_session->config.get_timecode_offset_negative()) {
2598 start += _session->config.get_timecode_offset ();
2600 start -= _session->config.get_timecode_offset ();
2602 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2603 (start % one_timecode_second == 0)) {
2604 /* start is already on a whole second, do nothing */
2605 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2606 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2608 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2611 if (_session->config.get_timecode_offset_negative()) {
2612 start -= _session->config.get_timecode_offset ();
2614 start += _session->config.get_timecode_offset ();
2618 case SnapToTimecodeMinutes:
2619 if (_session->config.get_timecode_offset_negative()) {
2620 start += _session->config.get_timecode_offset ();
2622 start -= _session->config.get_timecode_offset ();
2624 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2625 (start % one_timecode_minute == 0)) {
2626 /* start is already on a whole minute, do nothing */
2627 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2628 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2630 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2632 if (_session->config.get_timecode_offset_negative()) {
2633 start -= _session->config.get_timecode_offset ();
2635 start += _session->config.get_timecode_offset ();
2639 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2640 abort(); /*NOTREACHED*/
2645 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2647 const framepos_t one_second = _session->frame_rate();
2648 const framepos_t one_minute = _session->frame_rate() * 60;
2649 framepos_t presnap = start;
2653 switch (_snap_type) {
2654 case SnapToTimecodeFrame:
2655 case SnapToTimecodeSeconds:
2656 case SnapToTimecodeMinutes:
2657 return timecode_snap_to_internal (start, direction, for_mark);
2660 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2661 start % (one_second/75) == 0) {
2662 /* start is already on a whole CD frame, do nothing */
2663 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2664 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2666 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2671 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2672 start % one_second == 0) {
2673 /* start is already on a whole second, do nothing */
2674 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2675 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2677 start = (framepos_t) floor ((double) start / one_second) * one_second;
2682 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2683 start % one_minute == 0) {
2684 /* start is already on a whole minute, do nothing */
2685 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2686 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2688 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2693 start = _session->tempo_map().round_to_bar (start, direction);
2697 start = _session->tempo_map().round_to_beat (start, direction);
2700 case SnapToBeatDiv128:
2701 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2703 case SnapToBeatDiv64:
2704 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2706 case SnapToBeatDiv32:
2707 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2709 case SnapToBeatDiv28:
2710 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2712 case SnapToBeatDiv24:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2715 case SnapToBeatDiv20:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2718 case SnapToBeatDiv16:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2721 case SnapToBeatDiv14:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2724 case SnapToBeatDiv12:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2727 case SnapToBeatDiv10:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2730 case SnapToBeatDiv8:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2733 case SnapToBeatDiv7:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2736 case SnapToBeatDiv6:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2739 case SnapToBeatDiv5:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2742 case SnapToBeatDiv4:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2745 case SnapToBeatDiv3:
2746 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2748 case SnapToBeatDiv2:
2749 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2757 _session->locations()->marks_either_side (start, before, after);
2759 if (before == max_framepos && after == max_framepos) {
2760 /* No marks to snap to, so just don't snap */
2762 } else if (before == max_framepos) {
2764 } else if (after == max_framepos) {
2766 } else if (before != max_framepos && after != max_framepos) {
2767 /* have before and after */
2768 if ((start - before) < (after - start)) {
2777 case SnapToRegionStart:
2778 case SnapToRegionEnd:
2779 case SnapToRegionSync:
2780 case SnapToRegionBoundary:
2781 if (!region_boundary_cache.empty()) {
2783 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2784 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2786 if (direction > 0) {
2787 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2789 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2792 if (next != region_boundary_cache.begin ()) {
2797 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2798 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2800 if (start > (p + n) / 2) {
2809 switch (_snap_mode) {
2815 if (presnap > start) {
2816 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2820 } else if (presnap < start) {
2821 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2827 /* handled at entry */
2835 Editor::setup_toolbar ()
2837 HBox* mode_box = manage(new HBox);
2838 mode_box->set_border_width (2);
2839 mode_box->set_spacing(2);
2841 HBox* mouse_mode_box = manage (new HBox);
2842 HBox* mouse_mode_hbox = manage (new HBox);
2843 VBox* mouse_mode_vbox = manage (new VBox);
2844 Alignment* mouse_mode_align = manage (new Alignment);
2846 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2847 mouse_mode_size_group->add_widget (smart_mode_button);
2848 mouse_mode_size_group->add_widget (mouse_move_button);
2849 mouse_mode_size_group->add_widget (mouse_cut_button);
2850 mouse_mode_size_group->add_widget (mouse_select_button);
2851 mouse_mode_size_group->add_widget (mouse_timefx_button);
2852 mouse_mode_size_group->add_widget (mouse_audition_button);
2853 mouse_mode_size_group->add_widget (mouse_draw_button);
2854 mouse_mode_size_group->add_widget (mouse_content_button);
2856 mouse_mode_size_group->add_widget (zoom_in_button);
2857 mouse_mode_size_group->add_widget (zoom_out_button);
2858 mouse_mode_size_group->add_widget (zoom_preset_selector);
2859 mouse_mode_size_group->add_widget (zoom_out_full_button);
2860 mouse_mode_size_group->add_widget (zoom_focus_selector);
2862 mouse_mode_size_group->add_widget (tav_shrink_button);
2863 mouse_mode_size_group->add_widget (tav_expand_button);
2864 mouse_mode_size_group->add_widget (visible_tracks_selector);
2866 mouse_mode_size_group->add_widget (snap_type_selector);
2867 mouse_mode_size_group->add_widget (snap_mode_selector);
2869 mouse_mode_size_group->add_widget (edit_point_selector);
2870 mouse_mode_size_group->add_widget (edit_mode_selector);
2872 mouse_mode_size_group->add_widget (*nudge_clock);
2873 mouse_mode_size_group->add_widget (nudge_forward_button);
2874 mouse_mode_size_group->add_widget (nudge_backward_button);
2876 mouse_mode_hbox->set_spacing (2);
2878 if (!ARDOUR::Profile->get_trx()) {
2879 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2882 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2883 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2885 if (!ARDOUR::Profile->get_mixbus()) {
2886 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2889 if (!ARDOUR::Profile->get_trx()) {
2890 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2891 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2896 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2898 mouse_mode_align->add (*mouse_mode_vbox);
2899 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2901 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2903 edit_mode_selector.set_name ("mouse mode button");
2905 if (!ARDOUR::Profile->get_trx()) {
2906 mode_box->pack_start (edit_mode_selector, false, false);
2908 mode_box->pack_start (*mouse_mode_box, false, false);
2910 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2911 _mouse_mode_tearoff->set_name ("MouseModeBase");
2912 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2914 if (Profile->get_sae() || Profile->get_mixbus() ) {
2915 _mouse_mode_tearoff->set_can_be_torn_off (false);
2918 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2919 &_mouse_mode_tearoff->tearoff_window()));
2920 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2921 &_mouse_mode_tearoff->tearoff_window(), 1));
2922 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2923 &_mouse_mode_tearoff->tearoff_window()));
2924 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2925 &_mouse_mode_tearoff->tearoff_window(), 1));
2929 _zoom_box.set_spacing (2);
2930 _zoom_box.set_border_width (2);
2934 zoom_preset_selector.set_name ("zoom button");
2935 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2936 zoom_preset_selector.set_size_request (42, -1);
2938 zoom_in_button.set_name ("zoom button");
2939 zoom_in_button.set_image(::get_icon ("zoom_in"));
2940 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2941 zoom_in_button.set_related_action (act);
2943 zoom_out_button.set_name ("zoom button");
2944 zoom_out_button.set_image(::get_icon ("zoom_out"));
2945 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2946 zoom_out_button.set_related_action (act);
2948 zoom_out_full_button.set_name ("zoom button");
2949 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2950 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2951 zoom_out_full_button.set_related_action (act);
2953 zoom_focus_selector.set_name ("zoom button");
2955 if (ARDOUR::Profile->get_mixbus()) {
2956 _zoom_box.pack_start (zoom_preset_selector, false, false);
2957 } else if (ARDOUR::Profile->get_trx()) {
2958 mode_box->pack_start (zoom_out_button, false, false);
2959 mode_box->pack_start (zoom_in_button, false, false);
2961 _zoom_box.pack_start (zoom_out_button, false, false);
2962 _zoom_box.pack_start (zoom_in_button, false, false);
2963 _zoom_box.pack_start (zoom_out_full_button, false, false);
2964 _zoom_box.pack_start (zoom_focus_selector, false, false);
2967 /* Track zoom buttons */
2968 visible_tracks_selector.set_name ("zoom button");
2969 if (Profile->get_mixbus()) {
2970 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2971 visible_tracks_selector.set_size_request (42, -1);
2973 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2976 tav_expand_button.set_name ("zoom button");
2977 tav_expand_button.set_image(::get_icon ("tav_exp"));
2978 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2979 tav_expand_button.set_related_action (act);
2981 tav_shrink_button.set_name ("zoom button");
2982 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2983 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2984 tav_shrink_button.set_related_action (act);
2986 if (ARDOUR::Profile->get_mixbus()) {
2987 _zoom_box.pack_start (visible_tracks_selector);
2988 } else if (ARDOUR::Profile->get_trx()) {
2989 _zoom_box.pack_start (tav_shrink_button);
2990 _zoom_box.pack_start (tav_expand_button);
2992 _zoom_box.pack_start (visible_tracks_selector);
2993 _zoom_box.pack_start (tav_shrink_button);
2994 _zoom_box.pack_start (tav_expand_button);
2997 if (!ARDOUR::Profile->get_trx()) {
2998 _zoom_tearoff = manage (new TearOff (_zoom_box));
3000 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3001 &_zoom_tearoff->tearoff_window()));
3002 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3003 &_zoom_tearoff->tearoff_window(), 0));
3004 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3005 &_zoom_tearoff->tearoff_window()));
3006 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3007 &_zoom_tearoff->tearoff_window(), 0));
3010 if (Profile->get_sae() || Profile->get_mixbus() ) {
3011 _zoom_tearoff->set_can_be_torn_off (false);
3014 snap_box.set_spacing (2);
3015 snap_box.set_border_width (2);
3017 snap_type_selector.set_name ("mouse mode button");
3019 snap_mode_selector.set_name ("mouse mode button");
3021 edit_point_selector.set_name ("mouse mode button");
3023 snap_box.pack_start (snap_mode_selector, false, false);
3024 snap_box.pack_start (snap_type_selector, false, false);
3025 snap_box.pack_start (edit_point_selector, false, false);
3029 HBox *nudge_box = manage (new HBox);
3030 nudge_box->set_spacing (2);
3031 nudge_box->set_border_width (2);
3033 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3034 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3036 nudge_box->pack_start (nudge_backward_button, false, false);
3037 nudge_box->pack_start (nudge_forward_button, false, false);
3038 nudge_box->pack_start (*nudge_clock, false, false);
3041 /* Pack everything in... */
3043 HBox* hbox = manage (new HBox);
3044 hbox->set_spacing(2);
3046 _tools_tearoff = manage (new TearOff (*hbox));
3047 _tools_tearoff->set_name ("MouseModeBase");
3048 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3050 if (Profile->get_sae() || Profile->get_mixbus()) {
3051 _tools_tearoff->set_can_be_torn_off (false);
3054 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3055 &_tools_tearoff->tearoff_window()));
3056 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3057 &_tools_tearoff->tearoff_window(), 0));
3058 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3059 &_tools_tearoff->tearoff_window()));
3060 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3061 &_tools_tearoff->tearoff_window(), 0));
3063 toolbar_hbox.set_spacing (2);
3064 toolbar_hbox.set_border_width (1);
3066 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3067 if (!ARDOUR::Profile->get_trx()) {
3068 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3069 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3072 if (!ARDOUR::Profile->get_trx()) {
3073 hbox->pack_start (snap_box, false, false);
3074 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3075 hbox->pack_start (*nudge_box, false, false);
3077 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3080 hbox->pack_start (panic_box, false, false);
3084 toolbar_base.set_name ("ToolBarBase");
3085 toolbar_base.add (toolbar_hbox);
3087 _toolbar_viewport.add (toolbar_base);
3088 /* stick to the required height but allow width to vary if there's not enough room */
3089 _toolbar_viewport.set_size_request (1, -1);
3091 toolbar_frame.set_shadow_type (SHADOW_OUT);
3092 toolbar_frame.set_name ("BaseFrame");
3093 toolbar_frame.add (_toolbar_viewport);
3097 Editor::build_edit_point_menu ()
3099 using namespace Menu_Helpers;
3101 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3102 if(!Profile->get_mixbus())
3103 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3104 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3106 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3110 Editor::build_edit_mode_menu ()
3112 using namespace Menu_Helpers;
3114 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3115 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3116 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3117 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3119 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3123 Editor::build_snap_mode_menu ()
3125 using namespace Menu_Helpers;
3127 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3128 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3129 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3131 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3135 Editor::build_snap_type_menu ()
3137 using namespace Menu_Helpers;
3139 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3140 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3141 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3142 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3170 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3175 Editor::setup_tooltips ()
3177 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3178 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3179 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3180 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Grab/Select Objects"));
3181 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3182 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3183 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3184 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Edit Contents (notes and automation)"));
3185 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3186 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3187 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3188 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3189 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3190 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3191 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3192 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3193 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3194 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3195 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3196 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3197 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3198 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3199 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3200 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3204 Editor::convert_drop_to_paths (
3205 vector<string>& paths,
3206 const RefPtr<Gdk::DragContext>& /*context*/,
3209 const SelectionData& data,
3213 if (_session == 0) {
3217 vector<string> uris = data.get_uris();
3221 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3222 are actually URI lists. So do it by hand.
3225 if (data.get_target() != "text/plain") {
3229 /* Parse the "uri-list" format that Nautilus provides,
3230 where each pathname is delimited by \r\n.
3232 THERE MAY BE NO NULL TERMINATING CHAR!!!
3235 string txt = data.get_text();
3239 p = (char *) malloc (txt.length() + 1);
3240 txt.copy (p, txt.length(), 0);
3241 p[txt.length()] = '\0';
3247 while (g_ascii_isspace (*p))
3251 while (*q && (*q != '\n') && (*q != '\r')) {
3258 while (q > p && g_ascii_isspace (*q))
3263 uris.push_back (string (p, q - p + 1));
3267 p = strchr (p, '\n');
3279 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3280 if ((*i).substr (0,7) == "file://") {
3281 paths.push_back (Glib::filename_from_uri (*i));
3289 Editor::new_tempo_section ()
3294 Editor::map_transport_state ()
3296 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3298 if (_session && _session->transport_stopped()) {
3299 have_pending_keyboard_selection = false;
3302 update_loop_range_view ();
3308 Editor::begin_reversible_command (string name)
3311 before.push_back (&_selection_memento->get_state ());
3312 _session->begin_reversible_command (name);
3317 Editor::begin_reversible_command (GQuark q)
3320 before.push_back (&_selection_memento->get_state ());
3321 _session->begin_reversible_command (q);
3326 Editor::commit_reversible_command ()
3329 if (before.size() == 1) {
3330 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3333 if (!before.empty()) {
3337 _session->commit_reversible_command ();
3342 Editor::history_changed ()
3346 if (undo_action && _session) {
3347 if (_session->undo_depth() == 0) {
3348 label = S_("Command|Undo");
3350 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3352 undo_action->property_label() = label;
3355 if (redo_action && _session) {
3356 if (_session->redo_depth() == 0) {
3359 label = string_compose(_("Redo (%1)"), _session->next_redo());
3361 redo_action->property_label() = label;
3366 Editor::duplicate_range (bool with_dialog)
3370 RegionSelection rs = get_regions_from_selection_and_entered ();
3372 if ( selection->time.length() == 0 && rs.empty()) {
3378 ArdourDialog win (_("Duplicate"));
3379 Label label (_("Number of duplications:"));
3380 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3381 SpinButton spinner (adjustment, 0.0, 1);
3384 win.get_vbox()->set_spacing (12);
3385 win.get_vbox()->pack_start (hbox);
3386 hbox.set_border_width (6);
3387 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3389 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3390 place, visually. so do this by hand.
3393 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3394 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3395 spinner.grab_focus();
3401 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3402 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3403 win.set_default_response (RESPONSE_ACCEPT);
3405 spinner.grab_focus ();
3407 switch (win.run ()) {
3408 case RESPONSE_ACCEPT:
3414 times = adjustment.get_value();
3417 if ((current_mouse_mode() == Editing::MouseRange)) {
3418 if (selection->time.length()) {
3419 duplicate_selection (times);
3421 } else if (get_smart_mode()) {
3422 if (selection->time.length()) {
3423 duplicate_selection (times);
3425 duplicate_some_regions (rs, times);
3427 duplicate_some_regions (rs, times);
3432 Editor::set_edit_mode (EditMode m)
3434 Config->set_edit_mode (m);
3438 Editor::cycle_edit_mode ()
3440 switch (Config->get_edit_mode()) {
3442 if (Profile->get_sae()) {
3443 Config->set_edit_mode (Lock);
3445 Config->set_edit_mode (Ripple);
3450 Config->set_edit_mode (Lock);
3453 Config->set_edit_mode (Slide);
3459 Editor::edit_mode_selection_done ( EditMode m )
3461 Config->set_edit_mode ( m );
3465 Editor::snap_type_selection_done (SnapType snaptype)
3467 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3469 ract->set_active ();
3474 Editor::snap_mode_selection_done (SnapMode mode)
3476 RefPtr<RadioAction> ract = snap_mode_action (mode);
3479 ract->set_active (true);
3484 Editor::cycle_edit_point (bool with_marker)
3486 if(Profile->get_mixbus())
3487 with_marker = false;
3489 switch (_edit_point) {
3491 set_edit_point_preference (EditAtPlayhead);
3493 case EditAtPlayhead:
3495 set_edit_point_preference (EditAtSelectedMarker);
3497 set_edit_point_preference (EditAtMouse);
3500 case EditAtSelectedMarker:
3501 set_edit_point_preference (EditAtMouse);
3507 Editor::edit_point_selection_done (EditPoint ep)
3509 set_edit_point_preference ( ep );
3513 Editor::build_zoom_focus_menu ()
3515 using namespace Menu_Helpers;
3517 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3518 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3519 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3520 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3521 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3522 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3524 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3528 Editor::zoom_focus_selection_done ( ZoomFocus f )
3530 RefPtr<RadioAction> ract = zoom_focus_action (f);
3532 ract->set_active ();
3537 Editor::build_track_count_menu ()
3539 using namespace Menu_Helpers;
3541 if (!Profile->get_mixbus()) {
3542 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3543 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3544 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3545 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3546 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3547 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3548 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3549 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3550 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3551 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3552 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3553 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3554 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3556 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3557 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3558 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3559 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3560 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3561 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3562 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3563 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3564 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3565 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3567 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3568 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3569 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3570 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3571 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3572 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3573 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3574 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3575 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3576 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3577 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3582 Editor::set_zoom_preset (int64_t ms)
3585 temporal_zoom_session();
3589 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3590 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3594 Editor::set_visible_track_count (int32_t n)
3596 _visible_track_count = n;
3598 /* if the canvas hasn't really been allocated any size yet, just
3599 record the desired number of visible tracks and return. when canvas
3600 allocation happens, we will get called again and then we can do the
3604 if (_visible_canvas_height <= 1) {
3610 DisplaySuspender ds;
3612 if (_visible_track_count > 0) {
3613 h = trackviews_height() / _visible_track_count;
3614 std::ostringstream s;
3615 s << _visible_track_count;
3617 } else if (_visible_track_count == 0) {
3619 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3620 if ((*i)->marked_for_display()) {
3624 h = trackviews_height() / n;
3627 /* negative value means that the visible track count has
3628 been overridden by explicit track height changes.
3630 visible_tracks_selector.set_text (X_("*"));
3634 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3635 (*i)->set_height (h);
3638 if (str != visible_tracks_selector.get_text()) {
3639 visible_tracks_selector.set_text (str);
3644 Editor::override_visible_track_count ()
3646 _visible_track_count = -1;
3647 visible_tracks_selector.set_text ( _("*") );
3651 Editor::edit_controls_button_release (GdkEventButton* ev)
3653 if (Keyboard::is_context_menu_event (ev)) {
3654 ARDOUR_UI::instance()->add_route (this);
3655 } else if (ev->button == 1) {
3656 selection->clear_tracks ();
3663 Editor::mouse_select_button_release (GdkEventButton* ev)
3665 /* this handles just right-clicks */
3667 if (ev->button != 3) {
3675 Editor::set_zoom_focus (ZoomFocus f)
3677 string str = zoom_focus_strings[(int)f];
3679 if (str != zoom_focus_selector.get_text()) {
3680 zoom_focus_selector.set_text (str);
3683 if (zoom_focus != f) {
3690 Editor::cycle_zoom_focus ()
3692 switch (zoom_focus) {
3694 set_zoom_focus (ZoomFocusRight);
3696 case ZoomFocusRight:
3697 set_zoom_focus (ZoomFocusCenter);
3699 case ZoomFocusCenter:
3700 set_zoom_focus (ZoomFocusPlayhead);
3702 case ZoomFocusPlayhead:
3703 set_zoom_focus (ZoomFocusMouse);
3705 case ZoomFocusMouse:
3706 set_zoom_focus (ZoomFocusEdit);
3709 set_zoom_focus (ZoomFocusLeft);
3715 Editor::ensure_float (Window& win)
3717 win.set_transient_for (*this);
3721 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3723 /* recover or initialize pane positions. do this here rather than earlier because
3724 we don't want the positions to change the child allocations, which they seem to do.
3730 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3739 XMLNode* geometry = find_named_node (*node, "geometry");
3741 if (which == static_cast<Paned*> (&edit_pane)) {
3743 if (done & Horizontal) {
3747 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3748 _notebook_shrunk = string_is_affirmative (prop->value ());
3751 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3752 /* initial allocation is 90% to canvas, 10% to notebook */
3753 pos = (int) floor (alloc.get_width() * 0.90f);
3754 snprintf (buf, sizeof(buf), "%d", pos);
3756 pos = atoi (prop->value());
3759 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3760 edit_pane.set_position (pos);
3763 done = (Pane) (done | Horizontal);
3765 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3767 if (done & Vertical) {
3771 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3772 /* initial allocation is 90% to canvas, 10% to summary */
3773 pos = (int) floor (alloc.get_height() * 0.90f);
3774 snprintf (buf, sizeof(buf), "%d", pos);
3777 pos = atoi (prop->value());
3780 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3781 editor_summary_pane.set_position (pos);
3784 done = (Pane) (done | Vertical);
3789 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3791 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3792 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3793 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3794 top_hbox.remove (toolbar_frame);
3799 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3801 if (toolbar_frame.get_parent() == 0) {
3802 top_hbox.pack_end (toolbar_frame);
3807 Editor::set_show_measures (bool yn)
3809 if (_show_measures != yn) {
3812 if ((_show_measures = yn) == true) {
3814 tempo_lines->show();
3817 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3818 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3820 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3821 draw_measures (begin, end);
3829 Editor::toggle_follow_playhead ()
3831 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3833 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3834 set_follow_playhead (tact->get_active());
3838 /** @param yn true to follow playhead, otherwise false.
3839 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3842 Editor::set_follow_playhead (bool yn, bool catch_up)
3844 if (_follow_playhead != yn) {
3845 if ((_follow_playhead = yn) == true && catch_up) {
3847 reset_x_origin_to_follow_playhead ();
3854 Editor::toggle_stationary_playhead ()
3856 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3858 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3859 set_stationary_playhead (tact->get_active());
3864 Editor::set_stationary_playhead (bool yn)
3866 if (_stationary_playhead != yn) {
3867 if ((_stationary_playhead = yn) == true) {
3869 // FIXME need a 3.0 equivalent of this 2.X call
3870 // update_current_screen ();
3877 Editor::playlist_selector () const
3879 return *_playlist_selector;
3883 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3885 if (paste_count == 0) {
3886 /* don't bother calculating an offset that will be zero anyway */
3890 /* calculate basic unsnapped multi-paste offset */
3891 framecnt_t offset = paste_count * duration;
3893 /* snap offset so pos + offset is aligned to the grid */
3894 framepos_t offset_pos = pos + offset;
3895 snap_to(offset_pos, RoundUpMaybe);
3896 offset = offset_pos - pos;
3902 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3906 switch (_snap_type) {
3908 return Evoral::MusicalTime(1.0);
3911 case SnapToBeatDiv128:
3912 return Evoral::MusicalTime(1.0/128.0);
3914 case SnapToBeatDiv64:
3915 return Evoral::MusicalTime(1.0/64.0);
3917 case SnapToBeatDiv32:
3918 return Evoral::MusicalTime(1.0/32.0);
3920 case SnapToBeatDiv28:
3921 return Evoral::MusicalTime(1.0/28.0);
3923 case SnapToBeatDiv24:
3924 return Evoral::MusicalTime(1.0/24.0);
3926 case SnapToBeatDiv20:
3927 return Evoral::MusicalTime(1.0/20.0);
3929 case SnapToBeatDiv16:
3930 return Evoral::MusicalTime(1.0/16.0);
3932 case SnapToBeatDiv14:
3933 return Evoral::MusicalTime(1.0/14.0);
3935 case SnapToBeatDiv12:
3936 return Evoral::MusicalTime(1.0/12.0);
3938 case SnapToBeatDiv10:
3939 return Evoral::MusicalTime(1.0/10.0);
3941 case SnapToBeatDiv8:
3942 return Evoral::MusicalTime(1.0/8.0);
3944 case SnapToBeatDiv7:
3945 return Evoral::MusicalTime(1.0/7.0);
3947 case SnapToBeatDiv6:
3948 return Evoral::MusicalTime(1.0/6.0);
3950 case SnapToBeatDiv5:
3951 return Evoral::MusicalTime(1.0/5.0);
3953 case SnapToBeatDiv4:
3954 return Evoral::MusicalTime(1.0/4.0);
3956 case SnapToBeatDiv3:
3957 return Evoral::MusicalTime(1.0/3.0);
3959 case SnapToBeatDiv2:
3960 return Evoral::MusicalTime(1.0/2.0);
3965 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3970 case SnapToTimecodeFrame:
3971 case SnapToTimecodeSeconds:
3972 case SnapToTimecodeMinutes:
3975 case SnapToRegionStart:
3976 case SnapToRegionEnd:
3977 case SnapToRegionSync:
3978 case SnapToRegionBoundary:
3984 return Evoral::MusicalTime();
3988 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3992 ret = nudge_clock->current_duration (pos);
3993 next = ret + 1; /* XXXX fix me */
3999 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4001 ArdourDialog dialog (_("Playlist Deletion"));
4002 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4003 "If it is kept, its audio files will not be cleaned.\n"
4004 "If it is deleted, audio files used by it alone will be cleaned."),
4007 dialog.set_position (WIN_POS_CENTER);
4008 dialog.get_vbox()->pack_start (label);
4012 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4013 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4014 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4016 switch (dialog.run ()) {
4017 case RESPONSE_ACCEPT:
4018 /* delete the playlist */
4022 case RESPONSE_REJECT:
4023 /* keep the playlist */
4035 Editor::audio_region_selection_covers (framepos_t where)
4037 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4038 if ((*a)->region()->covers (where)) {
4047 Editor::prepare_for_cleanup ()
4049 cut_buffer->clear_regions ();
4050 cut_buffer->clear_playlists ();
4052 selection->clear_regions ();
4053 selection->clear_playlists ();
4055 _regions->suspend_redisplay ();
4059 Editor::finish_cleanup ()
4061 _regions->resume_redisplay ();
4065 Editor::transport_loop_location()
4068 return _session->locations()->auto_loop_location();
4075 Editor::transport_punch_location()
4078 return _session->locations()->auto_punch_location();
4085 Editor::control_layout_scroll (GdkEventScroll* ev)
4087 /* Just forward to the normal canvas scroll method. The coordinate
4088 systems are different but since the canvas is always larger than the
4089 track headers, and aligned with the trackview area, this will work.
4091 In the not too distant future this layout is going away anyway and
4092 headers will be on the canvas.
4094 return canvas_scroll_event (ev, false);
4098 Editor::session_state_saved (string)
4101 _snapshots->redisplay ();
4105 Editor::update_tearoff_visibility()
4107 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4108 _mouse_mode_tearoff->set_visible (visible);
4109 _tools_tearoff->set_visible (visible);
4110 if (_zoom_tearoff) {
4111 _zoom_tearoff->set_visible (visible);
4116 Editor::reattach_all_tearoffs ()
4118 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4119 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4120 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4124 Editor::maximise_editing_space ()
4136 Editor::restore_editing_space ()
4148 * Make new playlists for a given track and also any others that belong
4149 * to the same active route group with the `select' property.
4154 Editor::new_playlists (TimeAxisView* v)
4156 begin_reversible_command (_("new playlists"));
4157 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4158 _session->playlists->get (playlists);
4159 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4160 commit_reversible_command ();
4164 * Use a copy of the current playlist for a given track and also any others that belong
4165 * to the same active route group with the `select' property.
4170 Editor::copy_playlists (TimeAxisView* v)
4172 begin_reversible_command (_("copy playlists"));
4173 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4174 _session->playlists->get (playlists);
4175 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4176 commit_reversible_command ();
4179 /** Clear the current playlist for a given track and also any others that belong
4180 * to the same active route group with the `select' property.
4185 Editor::clear_playlists (TimeAxisView* v)
4187 begin_reversible_command (_("clear playlists"));
4188 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4189 _session->playlists->get (playlists);
4190 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4191 commit_reversible_command ();
4195 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4197 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4201 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4203 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4207 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4209 atv.clear_playlist ();
4213 Editor::on_key_press_event (GdkEventKey* ev)
4215 return key_press_focus_accelerator_handler (*this, ev);
4219 Editor::on_key_release_event (GdkEventKey* ev)
4221 return Gtk::Window::on_key_release_event (ev);
4222 // return key_press_focus_accelerator_handler (*this, ev);
4226 Editor::get_y_origin () const
4228 return vertical_adjustment.get_value ();
4231 /** Queue up a change to the viewport x origin.
4232 * @param frame New x origin.
4235 Editor::reset_x_origin (framepos_t frame)
4237 pending_visual_change.add (VisualChange::TimeOrigin);
4238 pending_visual_change.time_origin = frame;
4239 ensure_visual_change_idle_handler ();
4243 Editor::reset_y_origin (double y)
4245 pending_visual_change.add (VisualChange::YOrigin);
4246 pending_visual_change.y_origin = y;
4247 ensure_visual_change_idle_handler ();
4251 Editor::reset_zoom (framecnt_t spp)
4253 if (spp == samples_per_pixel) {
4257 pending_visual_change.add (VisualChange::ZoomLevel);
4258 pending_visual_change.samples_per_pixel = spp;
4259 ensure_visual_change_idle_handler ();
4263 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4265 reset_x_origin (frame);
4268 if (!no_save_visual) {
4269 undo_visual_stack.push_back (current_visual_state(false));
4273 Editor::VisualState::VisualState (bool with_tracks)
4274 : gui_state (with_tracks ? new GUIObjectState : 0)
4278 Editor::VisualState::~VisualState ()
4283 Editor::VisualState*
4284 Editor::current_visual_state (bool with_tracks)
4286 VisualState* vs = new VisualState (with_tracks);
4287 vs->y_position = vertical_adjustment.get_value();
4288 vs->samples_per_pixel = samples_per_pixel;
4289 vs->leftmost_frame = leftmost_frame;
4290 vs->zoom_focus = zoom_focus;
4293 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4300 Editor::undo_visual_state ()
4302 if (undo_visual_stack.empty()) {
4306 VisualState* vs = undo_visual_stack.back();
4307 undo_visual_stack.pop_back();
4310 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4313 use_visual_state (*vs);
4318 Editor::redo_visual_state ()
4320 if (redo_visual_stack.empty()) {
4324 VisualState* vs = redo_visual_stack.back();
4325 redo_visual_stack.pop_back();
4327 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4328 // why do we check here?
4329 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4332 use_visual_state (*vs);
4337 Editor::swap_visual_state ()
4339 if (undo_visual_stack.empty()) {
4340 redo_visual_state ();
4342 undo_visual_state ();
4347 Editor::use_visual_state (VisualState& vs)
4349 PBD::Unwinder<bool> nsv (no_save_visual, true);
4350 DisplaySuspender ds;
4352 vertical_adjustment.set_value (vs.y_position);
4354 set_zoom_focus (vs.zoom_focus);
4355 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4358 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4360 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4361 (*i)->reset_visual_state ();
4365 _routes->update_visibility ();
4368 /** This is the core function that controls the zoom level of the canvas. It is called
4369 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4370 * @param spp new number of samples per pixel
4373 Editor::set_samples_per_pixel (framecnt_t spp)
4379 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4380 const framecnt_t lots_of_pixels = 4000;
4382 /* if the zoom level is greater than what you'd get trying to display 3
4383 * days of audio on a really big screen, then it's too big.
4386 if (spp * lots_of_pixels > three_days) {
4390 samples_per_pixel = spp;
4393 tempo_lines->tempo_map_changed();
4396 bool const showing_time_selection = selection->time.length() > 0;
4398 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4399 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4400 (*i)->reshow_selection (selection->time);
4404 ZoomChanged (); /* EMIT_SIGNAL */
4406 ArdourCanvas::GtkCanvasViewport* c;
4408 c = get_track_canvas();
4410 c->canvas()->zoomed ();
4413 if (playhead_cursor) {
4414 playhead_cursor->set_position (playhead_cursor->current_frame ());
4417 refresh_location_display();
4418 _summary->set_overlays_dirty ();
4420 update_marker_labels ();
4426 Editor::queue_visual_videotimeline_update ()
4429 * pending_visual_change.add (VisualChange::VideoTimeline);
4430 * or maybe even more specific: which videotimeline-image
4431 * currently it calls update_video_timeline() to update
4432 * _all outdated_ images on the video-timeline.
4433 * see 'exposeimg()' in video_image_frame.cc
4435 ensure_visual_change_idle_handler ();
4439 Editor::ensure_visual_change_idle_handler ()
4441 if (pending_visual_change.idle_handler_id < 0) {
4442 // see comment in add_to_idle_resize above.
4443 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4444 pending_visual_change.being_handled = false;
4449 Editor::_idle_visual_changer (void* arg)
4451 return static_cast<Editor*>(arg)->idle_visual_changer ();
4455 Editor::idle_visual_changer ()
4457 /* set_horizontal_position() below (and maybe other calls) call
4458 gtk_main_iteration(), so it's possible that a signal will be handled
4459 half-way through this method. If this signal wants an
4460 idle_visual_changer we must schedule another one after this one, so
4461 mark the idle_handler_id as -1 here to allow that. Also make a note
4462 that we are doing the visual change, so that changes in response to
4463 super-rapid-screen-update can be dropped if we are still processing
4467 pending_visual_change.idle_handler_id = -1;
4468 pending_visual_change.being_handled = true;
4470 VisualChange vc = pending_visual_change;
4472 pending_visual_change.pending = (VisualChange::Type) 0;
4474 visual_changer (vc);
4476 pending_visual_change.being_handled = false;
4478 return 0; /* this is always a one-shot call */
4482 Editor::visual_changer (const VisualChange& vc)
4484 double const last_time_origin = horizontal_position ();
4486 if (vc.pending & VisualChange::ZoomLevel) {
4487 set_samples_per_pixel (vc.samples_per_pixel);
4489 compute_fixed_ruler_scale ();
4491 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4492 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4494 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4495 current_bbt_points_begin, current_bbt_points_end);
4496 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4497 current_bbt_points_begin, current_bbt_points_end);
4498 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4500 update_video_timeline();
4503 if (vc.pending & VisualChange::TimeOrigin) {
4504 set_horizontal_position (vc.time_origin / samples_per_pixel);
4507 if (vc.pending & VisualChange::YOrigin) {
4508 vertical_adjustment.set_value (vc.y_origin);
4511 if (last_time_origin == horizontal_position ()) {
4512 /* changed signal not emitted */
4513 update_fixed_rulers ();
4514 redisplay_tempo (true);
4517 if (!(vc.pending & VisualChange::ZoomLevel)) {
4518 update_video_timeline();
4521 _summary->set_overlays_dirty ();
4524 struct EditorOrderTimeAxisSorter {
4525 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4526 return a->order () < b->order ();
4531 Editor::sort_track_selection (TrackViewList& sel)
4533 EditorOrderTimeAxisSorter cmp;
4538 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4541 framepos_t where = 0;
4542 EditPoint ep = _edit_point;
4544 if(Profile->get_mixbus())
4545 if (ep == EditAtSelectedMarker)
4548 if (from_context_menu && (ep == EditAtMouse)) {
4549 return canvas_event_sample (&context_click_event, 0, 0);
4552 if (entered_marker) {
4553 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4554 return entered_marker->position();
4557 if (ignore_playhead && ep == EditAtPlayhead) {
4558 ep = EditAtSelectedMarker;
4562 case EditAtPlayhead:
4563 where = _session->audible_frame();
4564 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4567 case EditAtSelectedMarker:
4568 if (!selection->markers.empty()) {
4570 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4573 where = loc->start();
4577 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4585 if (!mouse_frame (where, ignored)) {
4586 /* XXX not right but what can we do ? */
4590 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4598 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4600 if (!_session) return;
4602 begin_reversible_command (cmd);
4606 if ((tll = transport_loop_location()) == 0) {
4607 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4608 XMLNode &before = _session->locations()->get_state();
4609 _session->locations()->add (loc, true);
4610 _session->set_auto_loop_location (loc);
4611 XMLNode &after = _session->locations()->get_state();
4612 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4614 XMLNode &before = tll->get_state();
4615 tll->set_hidden (false, this);
4616 tll->set (start, end);
4617 XMLNode &after = tll->get_state();
4618 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4621 commit_reversible_command ();
4625 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4627 if (!_session) return;
4629 begin_reversible_command (cmd);
4633 if ((tpl = transport_punch_location()) == 0) {
4634 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4635 XMLNode &before = _session->locations()->get_state();
4636 _session->locations()->add (loc, true);
4637 _session->set_auto_punch_location (loc);
4638 XMLNode &after = _session->locations()->get_state();
4639 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4641 XMLNode &before = tpl->get_state();
4642 tpl->set_hidden (false, this);
4643 tpl->set (start, end);
4644 XMLNode &after = tpl->get_state();
4645 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4648 commit_reversible_command ();
4651 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4652 * @param rs List to which found regions are added.
4653 * @param where Time to look at.
4654 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4657 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4659 const TrackViewList* tracks;
4662 tracks = &track_views;
4667 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4669 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4672 boost::shared_ptr<Track> tr;
4673 boost::shared_ptr<Playlist> pl;
4675 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4677 boost::shared_ptr<RegionList> regions = pl->regions_at (
4678 (framepos_t) floor ( (double) where * tr->speed()));
4680 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4681 RegionView* rv = rtv->view()->find_view (*i);
4692 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4694 const TrackViewList* tracks;
4697 tracks = &track_views;
4702 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4703 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4705 boost::shared_ptr<Track> tr;
4706 boost::shared_ptr<Playlist> pl;
4708 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4710 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4711 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4713 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4715 RegionView* rv = rtv->view()->find_view (*i);
4726 /** Get regions using the following method:
4728 * Make a region list using:
4729 * (a) any selected regions
4730 * (b) the intersection of any selected tracks and the edit point(*)
4731 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4733 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4735 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4739 Editor::get_regions_from_selection_and_edit_point ()
4741 RegionSelection regions;
4743 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4744 regions.add (entered_regionview);
4746 regions = selection->regions;
4749 if ( regions.empty() ) {
4750 TrackViewList tracks = selection->tracks;
4752 if (!tracks.empty()) {
4753 /* no region selected or entered, but some selected tracks:
4754 * act on all regions on the selected tracks at the edit point
4756 framepos_t const where = get_preferred_edit_position ();
4757 get_regions_at(regions, where, tracks);
4764 /** Get regions using the following method:
4766 * Make a region list using:
4767 * (a) any selected regions
4768 * (b) the intersection of any selected tracks and the edit point(*)
4769 * (c) if neither exists, then whatever region is under the mouse
4771 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4773 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4776 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4778 RegionSelection regions;
4780 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4781 regions.add (entered_regionview);
4783 regions = selection->regions;
4786 if ( regions.empty() ) {
4787 TrackViewList tracks = selection->tracks;
4789 if (!tracks.empty()) {
4790 /* no region selected or entered, but some selected tracks:
4791 * act on all regions on the selected tracks at the edit point
4793 get_regions_at(regions, pos, tracks);
4800 /** Start with regions that are selected, or the entered regionview if none are selected.
4801 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4802 * of the regions that we started with.
4806 Editor::get_regions_from_selection_and_entered ()
4808 RegionSelection regions = selection->regions;
4810 if (regions.empty() && entered_regionview) {
4811 regions.add (entered_regionview);
4818 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4820 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4821 RouteTimeAxisView* tatv;
4823 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4824 boost::shared_ptr<Playlist> pl;
4825 std::vector<boost::shared_ptr<Region> > results;
4826 boost::shared_ptr<Track> tr;
4828 if ((tr = tatv->track()) == 0) {
4833 if ((pl = (tr->playlist())) != 0) {
4834 boost::shared_ptr<Region> r = pl->region_by_id (id);
4836 RegionView* marv = tatv->view()->find_view (r);
4838 regions.push_back (marv);
4847 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4849 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4851 RouteTimeAxisView* tatv;
4853 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4855 boost::shared_ptr<Playlist> pl;
4856 vector<boost::shared_ptr<Region> > results;
4858 boost::shared_ptr<Track> tr;
4860 if ((tr = tatv->track()) == 0) {
4865 if ((pl = (tr->playlist())) != 0) {
4866 if (src_comparison) {
4867 pl->get_source_equivalent_regions (region, results);
4869 pl->get_region_list_equivalent_regions (region, results);
4873 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4874 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4875 regions.push_back (marv);
4884 Editor::show_rhythm_ferret ()
4886 if (rhythm_ferret == 0) {
4887 rhythm_ferret = new RhythmFerret(*this);
4890 rhythm_ferret->set_session (_session);
4891 rhythm_ferret->show ();
4892 rhythm_ferret->present ();
4896 Editor::first_idle ()
4898 MessageDialog* dialog = 0;
4900 if (track_views.size() > 1) {
4901 dialog = new MessageDialog (
4903 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4907 ARDOUR_UI::instance()->flush_pending ();
4910 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4914 // first idle adds route children (automation tracks), so we need to redisplay here
4915 _routes->redisplay ();
4922 Editor::_idle_resize (gpointer arg)
4924 return ((Editor*)arg)->idle_resize ();
4928 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4930 if (resize_idle_id < 0) {
4931 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4932 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4933 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4935 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4936 _pending_resize_amount = 0;
4939 /* make a note of the smallest resulting height, so that we can clamp the
4940 lower limit at TimeAxisView::hSmall */
4942 int32_t min_resulting = INT32_MAX;
4944 _pending_resize_amount += h;
4945 _pending_resize_view = view;
4947 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4949 if (selection->tracks.contains (_pending_resize_view)) {
4950 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4951 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4955 if (min_resulting < 0) {
4960 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4961 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4965 /** Handle pending resizing of tracks */
4967 Editor::idle_resize ()
4969 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4971 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4972 selection->tracks.contains (_pending_resize_view)) {
4974 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4975 if (*i != _pending_resize_view) {
4976 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4981 _pending_resize_amount = 0;
4982 _group_tabs->set_dirty ();
4983 resize_idle_id = -1;
4991 ENSURE_GUI_THREAD (*this, &Editor::located);
4994 playhead_cursor->set_position (_session->audible_frame ());
4995 if (_follow_playhead && !_pending_initial_locate) {
4996 reset_x_origin_to_follow_playhead ();
5000 _pending_locate_request = false;
5001 _pending_initial_locate = false;
5005 Editor::region_view_added (RegionView * rv)
5007 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5008 if (rv->region ()->id () == (*pr)) {
5009 selection->add (rv);
5010 selection->regions.pending.erase (pr);
5014 _summary->set_background_dirty ();
5018 Editor::region_view_removed ()
5020 _summary->set_background_dirty ();
5024 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5026 TrackViewList::const_iterator j = track_views.begin ();
5027 while (j != track_views.end()) {
5028 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5029 if (rtv && rtv->route() == r) {
5040 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5044 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5045 TimeAxisView* tv = axis_view_from_route (*i);
5055 Editor::suspend_route_redisplay ()
5058 _routes->suspend_redisplay();
5063 Editor::resume_route_redisplay ()
5066 _routes->resume_redisplay();
5071 Editor::add_routes (RouteList& routes)
5073 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5075 RouteTimeAxisView *rtv;
5076 list<RouteTimeAxisView*> new_views;
5078 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5079 boost::shared_ptr<Route> route = (*x);
5081 if (route->is_auditioner() || route->is_monitor()) {
5085 DataType dt = route->input()->default_type();
5087 if (dt == ARDOUR::DataType::AUDIO) {
5088 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5089 rtv->set_route (route);
5090 } else if (dt == ARDOUR::DataType::MIDI) {
5091 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5092 rtv->set_route (route);
5094 throw unknown_type();
5097 new_views.push_back (rtv);
5098 track_views.push_back (rtv);
5100 rtv->effective_gain_display ();
5102 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5103 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5106 if (new_views.size() > 0) {
5107 _routes->routes_added (new_views);
5108 _summary->routes_added (new_views);
5111 if (show_editor_mixer_when_tracks_arrive) {
5112 show_editor_mixer (true);
5115 editor_list_button.set_sensitive (true);
5119 Editor::timeaxisview_deleted (TimeAxisView *tv)
5121 if (tv == entered_track) {
5125 if (_session && _session->deletion_in_progress()) {
5126 /* the situation is under control */
5130 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5132 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5134 _routes->route_removed (tv);
5136 TimeAxisView::Children c = tv->get_child_list ();
5137 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5138 if (entered_track == i->get()) {
5143 /* remove it from the list of track views */
5145 TrackViewList::iterator i;
5147 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5148 i = track_views.erase (i);
5151 /* update whatever the current mixer strip is displaying, if revelant */
5153 boost::shared_ptr<Route> route;
5156 route = rtav->route ();
5159 if (current_mixer_strip && current_mixer_strip->route() == route) {
5161 TimeAxisView* next_tv;
5163 if (track_views.empty()) {
5165 } else if (i == track_views.end()) {
5166 next_tv = track_views.front();
5173 set_selected_mixer_strip (*next_tv);
5175 /* make the editor mixer strip go away setting the
5176 * button to inactive (which also unticks the menu option)
5179 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5185 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5187 if (apply_to_selection) {
5188 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5190 TrackSelection::iterator j = i;
5193 hide_track_in_display (*i, false);
5198 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5200 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5201 // this will hide the mixer strip
5202 set_selected_mixer_strip (*tv);
5205 _routes->hide_track_in_display (*tv);
5210 Editor::sync_track_view_list_and_routes ()
5212 track_views = TrackViewList (_routes->views ());
5214 _summary->set_dirty ();
5215 _group_tabs->set_dirty ();
5217 return false; // do not call again (until needed)
5221 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5223 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5228 /** Find a RouteTimeAxisView by the ID of its route */
5230 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5232 RouteTimeAxisView* v;
5234 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5235 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5236 if(v->route()->id() == id) {
5246 Editor::fit_route_group (RouteGroup *g)
5248 TrackViewList ts = axis_views_from_routes (g->route_list ());
5253 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5255 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5258 _session->cancel_audition ();
5262 if (_session->is_auditioning()) {
5263 _session->cancel_audition ();
5264 if (r == last_audition_region) {
5269 _session->audition_region (r);
5270 last_audition_region = r;
5275 Editor::hide_a_region (boost::shared_ptr<Region> r)
5277 r->set_hidden (true);
5281 Editor::show_a_region (boost::shared_ptr<Region> r)
5283 r->set_hidden (false);
5287 Editor::audition_region_from_region_list ()
5289 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5293 Editor::hide_region_from_region_list ()
5295 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5299 Editor::show_region_in_region_list ()
5301 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5305 Editor::step_edit_status_change (bool yn)
5308 start_step_editing ();
5310 stop_step_editing ();
5315 Editor::start_step_editing ()
5317 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5321 Editor::stop_step_editing ()
5323 step_edit_connection.disconnect ();
5327 Editor::check_step_edit ()
5329 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5330 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5332 mtv->check_step_edit ();
5336 return true; // do it again, till we stop
5340 Editor::scroll_press (Direction dir)
5342 ++_scroll_callbacks;
5344 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5345 /* delay the first auto-repeat */
5351 scroll_backward (1);
5359 scroll_up_one_track ();
5363 scroll_down_one_track ();
5367 /* do hacky auto-repeat */
5368 if (!_scroll_connection.connected ()) {
5370 _scroll_connection = Glib::signal_timeout().connect (
5371 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5374 _scroll_callbacks = 0;
5381 Editor::scroll_release ()
5383 _scroll_connection.disconnect ();
5386 /** Queue a change for the Editor viewport x origin to follow the playhead */
5388 Editor::reset_x_origin_to_follow_playhead ()
5390 framepos_t const frame = playhead_cursor->current_frame ();
5392 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5394 if (_session->transport_speed() < 0) {
5396 if (frame > (current_page_samples() / 2)) {
5397 center_screen (frame-(current_page_samples()/2));
5399 center_screen (current_page_samples()/2);
5406 if (frame < leftmost_frame) {
5408 if (_session->transport_rolling()) {
5409 /* rolling; end up with the playhead at the right of the page */
5410 l = frame - current_page_samples ();
5412 /* not rolling: end up with the playhead 1/4 of the way along the page */
5413 l = frame - current_page_samples() / 4;
5417 if (_session->transport_rolling()) {
5418 /* rolling: end up with the playhead on the left of the page */
5421 /* not rolling: end up with the playhead 3/4 of the way along the page */
5422 l = frame - 3 * current_page_samples() / 4;
5430 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5436 Editor::super_rapid_screen_update ()
5438 if (!_session || !_session->engine().running()) {
5442 /* METERING / MIXER STRIPS */
5444 /* update track meters, if required */
5445 if (is_mapped() && meters_running) {
5446 RouteTimeAxisView* rtv;
5447 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5448 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5449 rtv->fast_update ();
5454 /* and any current mixer strip */
5455 if (current_mixer_strip) {
5456 current_mixer_strip->fast_update ();
5459 /* PLAYHEAD AND VIEWPORT */
5461 framepos_t const frame = _session->audible_frame();
5463 /* There are a few reasons why we might not update the playhead / viewport stuff:
5465 * 1. we don't update things when there's a pending locate request, otherwise
5466 * when the editor requests a locate there is a chance that this method
5467 * will move the playhead before the locate request is processed, causing
5469 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5470 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5473 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5475 last_update_frame = frame;
5477 if (!_dragging_playhead) {
5478 playhead_cursor->set_position (frame);
5481 if (!_stationary_playhead) {
5483 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5484 /* We only do this if we aren't already
5485 handling a visual change (ie if
5486 pending_visual_change.being_handled is
5487 false) so that these requests don't stack
5488 up there are too many of them to handle in
5491 reset_x_origin_to_follow_playhead ();
5496 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5500 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5501 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5502 if (target <= 0.0) {
5505 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5506 target = (target * 0.15) + (current * 0.85);
5512 set_horizontal_position (current);
5521 Editor::session_going_away ()
5523 _have_idled = false;
5525 _session_connections.drop_connections ();
5527 super_rapid_screen_update_connection.disconnect ();
5529 selection->clear ();
5530 cut_buffer->clear ();
5532 clicked_regionview = 0;
5533 clicked_axisview = 0;
5534 clicked_routeview = 0;
5535 entered_regionview = 0;
5537 last_update_frame = 0;
5540 playhead_cursor->hide ();
5542 /* rip everything out of the list displays */
5546 _route_groups->clear ();
5548 /* do this first so that deleting a track doesn't reset cms to null
5549 and thus cause a leak.
5552 if (current_mixer_strip) {
5553 if (current_mixer_strip->get_parent() != 0) {
5554 global_hpacker.remove (*current_mixer_strip);
5556 delete current_mixer_strip;
5557 current_mixer_strip = 0;
5560 /* delete all trackviews */
5562 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5565 track_views.clear ();
5567 nudge_clock->set_session (0);
5569 editor_list_button.set_active(false);
5570 editor_list_button.set_sensitive(false);
5572 /* clear tempo/meter rulers */
5573 remove_metric_marks ();
5575 clear_marker_display ();
5577 stop_step_editing ();
5579 /* get rid of any existing editor mixer strip */
5581 WindowTitle title(Glib::get_application_name());
5582 title += _("Editor");
5584 set_title (title.get_string());
5586 SessionHandlePtr::session_going_away ();
5591 Editor::show_editor_list (bool yn)
5594 _the_notebook.show ();
5596 _the_notebook.hide ();
5601 Editor::change_region_layering_order (bool from_context_menu)
5603 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5605 if (!clicked_routeview) {
5606 if (layering_order_editor) {
5607 layering_order_editor->hide ();
5612 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5618 boost::shared_ptr<Playlist> pl = track->playlist();
5624 if (layering_order_editor == 0) {
5625 layering_order_editor = new RegionLayeringOrderEditor (*this);
5628 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5629 layering_order_editor->maybe_present ();
5633 Editor::update_region_layering_order_editor ()
5635 if (layering_order_editor && layering_order_editor->is_visible ()) {
5636 change_region_layering_order (true);
5641 Editor::setup_fade_images ()
5643 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5644 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5645 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5646 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5647 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5649 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5650 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5651 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5652 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5653 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5655 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5656 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5657 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5658 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5659 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5661 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5662 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5663 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5664 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5665 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5669 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5671 Editor::action_menu_item (std::string const & name)
5673 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5676 return *manage (a->create_menu_item ());
5680 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5682 EventBox* b = manage (new EventBox);
5683 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5684 Label* l = manage (new Label (name));
5688 _the_notebook.append_page (widget, *b);
5692 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5694 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5695 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5698 if (ev->type == GDK_2BUTTON_PRESS) {
5700 /* double-click on a notebook tab shrinks or expands the notebook */
5702 if (_notebook_shrunk) {
5703 if (pre_notebook_shrink_pane_width) {
5704 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5706 _notebook_shrunk = false;
5708 pre_notebook_shrink_pane_width = edit_pane.get_position();
5710 /* this expands the LHS of the edit pane to cover the notebook
5711 PAGE but leaves the tabs visible.
5713 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5714 _notebook_shrunk = true;
5722 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5724 using namespace Menu_Helpers;
5726 MenuList& items = _control_point_context_menu.items ();
5729 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5730 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5731 if (!can_remove_control_point (item)) {
5732 items.back().set_sensitive (false);
5735 _control_point_context_menu.popup (event->button.button, event->button.time);
5739 Editor::zoom_vertical_modifier_released()
5741 _stepping_axis_view = 0;
5745 Editor::ui_parameter_changed (string parameter)
5747 if (parameter == "icon-set") {
5748 while (!_cursor_stack.empty()) {
5749 _cursor_stack.pop_back();
5751 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5752 _cursor_stack.push_back(_cursors->grabber);
5753 } else if (parameter == "draggable-playhead") {
5754 if (_verbose_cursor) {
5755 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());