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_region_view.h"
111 #include "midi_time_axis.h"
112 #include "mixer_strip.h"
113 #include "mixer_ui.h"
114 #include "mouse_cursors.h"
115 #include "note_base.h"
116 #include "playlist_selector.h"
117 #include "public_editor.h"
118 #include "region_layering_order_editor.h"
119 #include "rgb_macros.h"
120 #include "rhythm_ferret.h"
121 #include "selection.h"
123 #include "tempo_lines.h"
124 #include "time_axis_view.h"
126 #include "verbose_cursor.h"
131 using namespace ARDOUR;
132 using namespace ARDOUR_UI_UTILS;
135 using namespace Glib;
136 using namespace Gtkmm2ext;
137 using namespace Editing;
139 using PBD::internationalize;
141 using Gtkmm2ext::Keyboard;
143 const double Editor::timebar_height = 15.0;
145 static const gchar *_snap_type_strings[] = {
179 static const gchar *_snap_mode_strings[] = {
186 static const gchar *_edit_point_strings[] = {
193 static const gchar *_edit_mode_strings[] = {
201 static const gchar *_zoom_focus_strings[] = {
211 #ifdef USE_RUBBERBAND
212 static const gchar *_rb_opt_strings[] = {
215 N_("Balanced multitimbral mixture"),
216 N_("Unpitched percussion with stable notes"),
217 N_("Crisp monophonic instrumental"),
218 N_("Unpitched solo percussion"),
219 N_("Resample without preserving pitch"),
224 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
227 pane_size_watcher (Paned* pane)
229 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
233 Quartz: impossible to access
235 so stop that by preventing it from ever getting too narrow. 35
236 pixels is basically a rough guess at the tab width.
241 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
243 gint pos = pane->get_position ();
245 if (pos > max_width_of_lhs) {
246 pane->set_position (max_width_of_lhs);
251 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
253 /* time display buttons */
254 , minsec_label (_("Mins:Secs"))
255 , bbt_label (_("Bars:Beats"))
256 , timecode_label (_("Timecode"))
257 , samples_label (_("Samples"))
258 , tempo_label (_("Tempo"))
259 , meter_label (_("Meter"))
260 , mark_label (_("Location Markers"))
261 , range_mark_label (_("Range Markers"))
262 , transport_mark_label (_("Loop/Punch Ranges"))
263 , cd_mark_label (_("CD Markers"))
264 , videotl_label (_("Video Timeline"))
265 , edit_packer (4, 4, true)
267 /* the values here don't matter: layout widgets
268 reset them as needed.
271 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
272 , horizontal_adjustment (0.0, 0.0, 1e16)
273 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
275 , controls_layout (unused_adjustment, vertical_adjustment)
277 /* tool bar related */
279 , toolbar_selection_clock_table (2,3)
280 , _mouse_mode_tearoff (0)
281 , automation_mode_button (_("mode"))
285 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
289 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
290 , meters_running(false)
291 , _pending_locate_request (false)
292 , _pending_initial_locate (false)
293 , _last_cut_copy_source_track (0)
295 , _region_selection_change_updates_region_list (true)
296 , _following_mixer_selection (false)
297 , _control_point_toggled_on_press (false)
298 , _stepping_axis_view (0)
302 /* we are a singleton */
304 PublicEditor::_instance = this;
308 selection = new Selection (this);
309 cut_buffer = new Selection (this);
310 _selection_memento = new SelectionMemento ();
313 clicked_regionview = 0;
314 clicked_axisview = 0;
315 clicked_routeview = 0;
316 clicked_control_point = 0;
317 last_update_frame = 0;
320 _drags = new DragManager (this);
323 current_mixer_strip = 0;
326 snap_type_strings = I18N (_snap_type_strings);
327 snap_mode_strings = I18N (_snap_mode_strings);
328 zoom_focus_strings = I18N (_zoom_focus_strings);
329 edit_mode_strings = I18N (_edit_mode_strings);
330 edit_point_strings = I18N (_edit_point_strings);
331 #ifdef USE_RUBBERBAND
332 rb_opt_strings = I18N (_rb_opt_strings);
336 build_edit_mode_menu();
337 build_zoom_focus_menu();
338 build_track_count_menu();
339 build_snap_mode_menu();
340 build_snap_type_menu();
341 build_edit_point_menu();
343 snap_threshold = 5.0;
344 bbt_beat_subdivision = 4;
345 _visible_canvas_width = 0;
346 _visible_canvas_height = 0;
347 autoscroll_horizontal_allowed = false;
348 autoscroll_vertical_allowed = false;
353 current_interthread_info = 0;
354 _show_measures = true;
356 show_gain_after_trim = false;
358 have_pending_keyboard_selection = false;
359 _follow_playhead = true;
360 _stationary_playhead = false;
361 editor_ruler_menu = 0;
362 no_ruler_shown_update = false;
364 range_marker_menu = 0;
365 marker_menu_item = 0;
366 tempo_or_meter_marker_menu = 0;
367 transport_marker_menu = 0;
368 new_transport_marker_menu = 0;
369 editor_mixer_strip_width = Wide;
370 show_editor_mixer_when_tracks_arrive = false;
371 region_edit_menu_split_multichannel_item = 0;
372 region_edit_menu_split_item = 0;
375 current_stepping_trackview = 0;
377 entered_regionview = 0;
379 clear_entered_track = false;
382 button_release_can_deselect = true;
383 _dragging_playhead = false;
384 _dragging_edit_point = false;
385 select_new_marker = false;
387 layering_order_editor = 0;
388 no_save_visual = false;
390 within_track_canvas = false;
392 scrubbing_direction = 0;
396 location_marker_color = ARDOUR_UI::config()->color ("location marker");
397 location_range_color = ARDOUR_UI::config()->color ("location range");
398 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
399 location_loop_color = ARDOUR_UI::config()->color ("location loop");
400 location_punch_color = ARDOUR_UI::config()->color ("location punch");
402 zoom_focus = ZoomFocusLeft;
403 _edit_point = EditAtMouse;
404 _visible_track_count = -1;
406 samples_per_pixel = 2048; /* too early to use reset_zoom () */
408 _scroll_callbacks = 0;
410 bbt_label.set_name ("EditorRulerLabel");
411 bbt_label.set_size_request (-1, (int)timebar_height);
412 bbt_label.set_alignment (1.0, 0.5);
413 bbt_label.set_padding (5,0);
415 bbt_label.set_no_show_all();
416 minsec_label.set_name ("EditorRulerLabel");
417 minsec_label.set_size_request (-1, (int)timebar_height);
418 minsec_label.set_alignment (1.0, 0.5);
419 minsec_label.set_padding (5,0);
420 minsec_label.hide ();
421 minsec_label.set_no_show_all();
422 timecode_label.set_name ("EditorRulerLabel");
423 timecode_label.set_size_request (-1, (int)timebar_height);
424 timecode_label.set_alignment (1.0, 0.5);
425 timecode_label.set_padding (5,0);
426 timecode_label.hide ();
427 timecode_label.set_no_show_all();
428 samples_label.set_name ("EditorRulerLabel");
429 samples_label.set_size_request (-1, (int)timebar_height);
430 samples_label.set_alignment (1.0, 0.5);
431 samples_label.set_padding (5,0);
432 samples_label.hide ();
433 samples_label.set_no_show_all();
435 tempo_label.set_name ("EditorRulerLabel");
436 tempo_label.set_size_request (-1, (int)timebar_height);
437 tempo_label.set_alignment (1.0, 0.5);
438 tempo_label.set_padding (5,0);
440 tempo_label.set_no_show_all();
442 meter_label.set_name ("EditorRulerLabel");
443 meter_label.set_size_request (-1, (int)timebar_height);
444 meter_label.set_alignment (1.0, 0.5);
445 meter_label.set_padding (5,0);
447 meter_label.set_no_show_all();
449 if (Profile->get_trx()) {
450 mark_label.set_text (_("Markers"));
452 mark_label.set_name ("EditorRulerLabel");
453 mark_label.set_size_request (-1, (int)timebar_height);
454 mark_label.set_alignment (1.0, 0.5);
455 mark_label.set_padding (5,0);
457 mark_label.set_no_show_all();
459 cd_mark_label.set_name ("EditorRulerLabel");
460 cd_mark_label.set_size_request (-1, (int)timebar_height);
461 cd_mark_label.set_alignment (1.0, 0.5);
462 cd_mark_label.set_padding (5,0);
463 cd_mark_label.hide();
464 cd_mark_label.set_no_show_all();
466 videotl_bar_height = 4;
467 videotl_label.set_name ("EditorRulerLabel");
468 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
469 videotl_label.set_alignment (1.0, 0.5);
470 videotl_label.set_padding (5,0);
471 videotl_label.hide();
472 videotl_label.set_no_show_all();
474 range_mark_label.set_name ("EditorRulerLabel");
475 range_mark_label.set_size_request (-1, (int)timebar_height);
476 range_mark_label.set_alignment (1.0, 0.5);
477 range_mark_label.set_padding (5,0);
478 range_mark_label.hide();
479 range_mark_label.set_no_show_all();
481 transport_mark_label.set_name ("EditorRulerLabel");
482 transport_mark_label.set_size_request (-1, (int)timebar_height);
483 transport_mark_label.set_alignment (1.0, 0.5);
484 transport_mark_label.set_padding (5,0);
485 transport_mark_label.hide();
486 transport_mark_label.set_no_show_all();
488 initialize_canvas ();
490 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
492 _summary = new EditorSummary (this);
494 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
495 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
497 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
499 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
500 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
502 edit_controls_vbox.set_spacing (0);
503 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
504 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
506 HBox* h = manage (new HBox);
507 _group_tabs = new EditorGroupTabs (this);
508 if (!ARDOUR::Profile->get_trx()) {
509 h->pack_start (*_group_tabs, PACK_SHRINK);
511 h->pack_start (edit_controls_vbox);
512 controls_layout.add (*h);
514 controls_layout.set_name ("EditControlsBase");
515 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
516 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
517 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
519 _cursors = new MouseCursors;
520 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
521 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
523 /* Push default cursor to ever-present bottom of cursor stack. */
524 push_canvas_cursor(_cursors->grabber);
526 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
528 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
529 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
530 pad_line_1->set_outline_color (0xFF0000FF);
536 edit_packer.set_col_spacings (0);
537 edit_packer.set_row_spacings (0);
538 edit_packer.set_homogeneous (false);
539 edit_packer.set_border_width (0);
540 edit_packer.set_name ("EditorWindow");
542 time_bars_event_box.add (time_bars_vbox);
543 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
544 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
546 /* labels for the time bars */
547 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
549 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
551 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
553 bottom_hbox.set_border_width (2);
554 bottom_hbox.set_spacing (3);
556 _route_groups = new EditorRouteGroups (this);
557 _routes = new EditorRoutes (this);
558 _regions = new EditorRegions (this);
559 _snapshots = new EditorSnapshots (this);
560 _locations = new EditorLocations (this);
562 /* these are static location signals */
564 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
565 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
566 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
568 add_notebook_page (_("Regions"), _regions->widget ());
569 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
570 add_notebook_page (_("Snapshots"), _snapshots->widget ());
571 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
572 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
574 _the_notebook.set_show_tabs (true);
575 _the_notebook.set_scrollable (true);
576 _the_notebook.popup_disable ();
577 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
578 _the_notebook.show_all ();
580 _notebook_shrunk = false;
582 editor_summary_pane.pack1(edit_packer);
584 Button* summary_arrows_left_left = manage (new Button);
585 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
586 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
587 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
589 Button* summary_arrows_left_right = manage (new Button);
590 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
591 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
592 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
594 VBox* summary_arrows_left = manage (new VBox);
595 summary_arrows_left->pack_start (*summary_arrows_left_left);
596 summary_arrows_left->pack_start (*summary_arrows_left_right);
598 Button* summary_arrows_right_up = manage (new Button);
599 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
600 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
601 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
603 Button* summary_arrows_right_down = manage (new Button);
604 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
605 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
606 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
608 VBox* summary_arrows_right = manage (new VBox);
609 summary_arrows_right->pack_start (*summary_arrows_right_up);
610 summary_arrows_right->pack_start (*summary_arrows_right_down);
612 Frame* summary_frame = manage (new Frame);
613 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
615 summary_frame->add (*_summary);
616 summary_frame->show ();
618 _summary_hbox.pack_start (*summary_arrows_left, false, false);
619 _summary_hbox.pack_start (*summary_frame, true, true);
620 _summary_hbox.pack_start (*summary_arrows_right, false, false);
622 if (!ARDOUR::Profile->get_trx()) {
623 editor_summary_pane.pack2 (_summary_hbox);
626 edit_pane.pack1 (editor_summary_pane, true, true);
627 if (!ARDOUR::Profile->get_trx()) {
628 edit_pane.pack2 (_the_notebook, false, true);
631 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
633 /* XXX: editor_summary_pane might need similar to the edit_pane */
635 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
637 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
638 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
640 top_hbox.pack_start (toolbar_frame);
642 HBox *hbox = manage (new HBox);
643 hbox->pack_start (edit_pane, true, true);
645 global_vpacker.pack_start (top_hbox, false, false);
646 global_vpacker.pack_start (*hbox, true, true);
648 global_hpacker.pack_start (global_vpacker, true, true);
650 set_name ("EditorWindow");
651 add_accel_group (ActionManager::ui_manager->get_accel_group());
653 status_bar_hpacker.show ();
655 vpacker.pack_end (status_bar_hpacker, false, false);
656 vpacker.pack_end (global_hpacker, true, true);
658 /* register actions now so that set_state() can find them and set toggles/checks etc */
661 /* when we start using our own keybinding system for the editor, this
662 * will be uncommented
668 set_zoom_focus (zoom_focus);
669 set_visible_track_count (_visible_track_count);
670 _snap_type = SnapToBeat;
671 set_snap_to (_snap_type);
672 _snap_mode = SnapOff;
673 set_snap_mode (_snap_mode);
674 set_mouse_mode (MouseObject, true);
675 pre_internal_mouse_mode = MouseObject;
676 pre_internal_snap_type = _snap_type;
677 pre_internal_snap_mode = _snap_mode;
678 internal_snap_type = _snap_type;
679 internal_snap_mode = _snap_mode;
680 set_edit_point_preference (EditAtMouse, true);
682 _playlist_selector = new PlaylistSelector();
683 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
685 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
689 nudge_forward_button.set_name ("nudge button");
690 nudge_forward_button.set_image(::get_icon("nudge_right"));
692 nudge_backward_button.set_name ("nudge button");
693 nudge_backward_button.set_image(::get_icon("nudge_left"));
695 fade_context_menu.set_name ("ArdourContextMenu");
697 /* icons, titles, WM stuff */
699 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
700 Glib::RefPtr<Gdk::Pixbuf> icon;
702 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
703 window_icons.push_back (icon);
705 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
706 window_icons.push_back (icon);
708 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
709 window_icons.push_back (icon);
711 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
712 window_icons.push_back (icon);
714 if (!window_icons.empty()) {
715 // set_icon_list (window_icons);
716 set_default_icon_list (window_icons);
719 WindowTitle title(Glib::get_application_name());
720 title += _("Editor");
721 set_title (title.get_string());
722 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
725 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
727 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
728 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
730 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
732 /* allow external control surfaces/protocols to do various things */
734 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
735 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
736 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
737 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
738 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
739 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
740 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
741 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
742 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
743 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
744 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
745 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
746 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
747 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
749 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
750 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
751 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
752 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
753 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
755 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
757 /* problematic: has to return a value and thus cannot be x-thread */
759 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
761 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
762 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
764 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
766 _ignore_region_action = false;
767 _last_region_menu_was_main = false;
768 _popup_region_menu_item = 0;
770 _ignore_follow_edits = false;
772 _show_marker_lines = false;
774 /* Button bindings */
776 button_bindings = new Bindings;
778 XMLNode* node = button_settings();
780 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
781 button_bindings->load (**i);
787 /* grab current parameter state */
788 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
789 ARDOUR_UI::config()->map_parameters (pc);
791 setup_fade_images ();
798 delete button_bindings;
800 delete _route_groups;
801 delete _track_canvas_viewport;
807 Editor::button_settings () const
809 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
810 XMLNode* node = find_named_node (*settings, X_("Buttons"));
813 node = new XMLNode (X_("Buttons"));
820 Editor::add_toplevel_menu (Container& cont)
822 vpacker.pack_start (cont, false, false);
827 Editor::add_transport_frame (Container& cont)
829 if(ARDOUR::Profile->get_mixbus()) {
830 global_vpacker.pack_start (cont, false, false);
831 global_vpacker.reorder_child (cont, 0);
834 vpacker.pack_start (cont, false, false);
839 Editor::get_smart_mode () const
841 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
845 Editor::catch_vanishing_regionview (RegionView *rv)
847 /* note: the selection will take care of the vanishing
848 audioregionview by itself.
851 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
855 if (clicked_regionview == rv) {
856 clicked_regionview = 0;
859 if (entered_regionview == rv) {
860 set_entered_regionview (0);
863 if (!_all_region_actions_sensitized) {
864 sensitize_all_region_actions (true);
869 Editor::set_entered_regionview (RegionView* rv)
871 if (rv == entered_regionview) {
875 if (entered_regionview) {
876 entered_regionview->exited ();
879 entered_regionview = rv;
881 if (entered_regionview != 0) {
882 entered_regionview->entered ();
885 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
886 /* This RegionView entry might have changed what region actions
887 are allowed, so sensitize them all in case a key is pressed.
889 sensitize_all_region_actions (true);
894 Editor::set_entered_track (TimeAxisView* tav)
897 entered_track->exited ();
903 entered_track->entered ();
908 Editor::show_window ()
910 if (!is_visible ()) {
914 /* XXX: this is a bit unfortunate; it would probably
915 be nicer if we could just call show () above rather
916 than needing the show_all ()
919 /* re-hide stuff if necessary */
920 editor_list_button_toggled ();
921 parameter_changed ("show-summary");
922 parameter_changed ("show-group-tabs");
923 parameter_changed ("show-zoom-tools");
925 /* now reset all audio_time_axis heights, because widgets might need
931 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
932 tv = (static_cast<TimeAxisView*>(*i));
936 if (current_mixer_strip) {
937 current_mixer_strip->hide_things ();
938 current_mixer_strip->parameter_changed ("mixer-element-visibility");
946 Editor::instant_save ()
948 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
953 _session->add_instant_xml(get_state());
955 Config->add_instant_xml(get_state());
960 Editor::control_vertical_zoom_in_all ()
962 tav_zoom_smooth (false, true);
966 Editor::control_vertical_zoom_out_all ()
968 tav_zoom_smooth (true, true);
972 Editor::control_vertical_zoom_in_selected ()
974 tav_zoom_smooth (false, false);
978 Editor::control_vertical_zoom_out_selected ()
980 tav_zoom_smooth (true, false);
984 Editor::control_view (uint32_t view)
986 goto_visual_state (view);
990 Editor::control_unselect ()
992 selection->clear_tracks ();
996 Editor::control_select (uint32_t rid, Selection::Operation op)
998 /* handles the (static) signal from the ControlProtocol class that
999 * requests setting the selected track to a given RID
1006 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1012 TimeAxisView* tav = axis_view_from_route (r);
1016 case Selection::Add:
1017 selection->add (tav);
1019 case Selection::Toggle:
1020 selection->toggle (tav);
1022 case Selection::Extend:
1024 case Selection::Set:
1025 selection->set (tav);
1029 selection->clear_tracks ();
1034 Editor::control_step_tracks_up ()
1036 scroll_tracks_up_line ();
1040 Editor::control_step_tracks_down ()
1042 scroll_tracks_down_line ();
1046 Editor::control_scroll (float fraction)
1048 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1054 double step = fraction * current_page_samples();
1057 _control_scroll_target is an optional<T>
1059 it acts like a pointer to an framepos_t, with
1060 a operator conversion to boolean to check
1061 that it has a value could possibly use
1062 playhead_cursor->current_frame to store the
1063 value and a boolean in the class to know
1064 when it's out of date
1067 if (!_control_scroll_target) {
1068 _control_scroll_target = _session->transport_frame();
1069 _dragging_playhead = true;
1072 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1073 *_control_scroll_target = 0;
1074 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1075 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1077 *_control_scroll_target += (framepos_t) trunc (step);
1080 /* move visuals, we'll catch up with it later */
1082 playhead_cursor->set_position (*_control_scroll_target);
1083 UpdateAllTransportClocks (*_control_scroll_target);
1085 if (*_control_scroll_target > (current_page_samples() / 2)) {
1086 /* try to center PH in window */
1087 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1093 Now we do a timeout to actually bring the session to the right place
1094 according to the playhead. This is to avoid reading disk buffers on every
1095 call to control_scroll, which is driven by ScrollTimeline and therefore
1096 probably by a control surface wheel which can generate lots of events.
1098 /* cancel the existing timeout */
1100 control_scroll_connection.disconnect ();
1102 /* add the next timeout */
1104 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1108 Editor::deferred_control_scroll (framepos_t /*target*/)
1110 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1111 // reset for next stream
1112 _control_scroll_target = boost::none;
1113 _dragging_playhead = false;
1118 Editor::access_action (std::string action_group, std::string action_item)
1124 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1127 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1135 Editor::on_realize ()
1137 Window::on_realize ();
1140 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1141 start_lock_event_timing ();
1144 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1148 Editor::start_lock_event_timing ()
1150 /* check if we should lock the GUI every 30 seconds */
1152 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1156 Editor::generic_event_handler (GdkEvent* ev)
1159 case GDK_BUTTON_PRESS:
1160 case GDK_BUTTON_RELEASE:
1161 case GDK_MOTION_NOTIFY:
1163 case GDK_KEY_RELEASE:
1164 gettimeofday (&last_event_time, 0);
1167 case GDK_LEAVE_NOTIFY:
1168 switch (ev->crossing.detail) {
1169 case GDK_NOTIFY_UNKNOWN:
1170 case GDK_NOTIFY_INFERIOR:
1171 case GDK_NOTIFY_ANCESTOR:
1173 case GDK_NOTIFY_VIRTUAL:
1174 case GDK_NOTIFY_NONLINEAR:
1175 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1176 /* leaving window, so reset focus, thus ending any and
1177 all text entry operations.
1192 Editor::lock_timeout_callback ()
1194 struct timeval now, delta;
1196 gettimeofday (&now, 0);
1198 timersub (&now, &last_event_time, &delta);
1200 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1202 /* don't call again. Returning false will effectively
1203 disconnect us from the timer callback.
1205 unlock() will call start_lock_event_timing() to get things
1215 Editor::map_position_change (framepos_t frame)
1217 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1219 if (_session == 0) {
1223 if (_follow_playhead) {
1224 center_screen (frame);
1227 playhead_cursor->set_position (frame);
1231 Editor::center_screen (framepos_t frame)
1233 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1235 /* if we're off the page, then scroll.
1238 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1239 center_screen_internal (frame, page);
1244 Editor::center_screen_internal (framepos_t frame, float page)
1249 frame -= (framepos_t) page;
1254 reset_x_origin (frame);
1259 Editor::update_title ()
1261 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1264 bool dirty = _session->dirty();
1266 string session_name;
1268 if (_session->snap_name() != _session->name()) {
1269 session_name = _session->snap_name();
1271 session_name = _session->name();
1275 session_name = "*" + session_name;
1278 WindowTitle title(session_name);
1279 title += Glib::get_application_name();
1280 set_title (title.get_string());
1282 /* ::session_going_away() will have taken care of it */
1287 Editor::set_session (Session *t)
1289 SessionHandlePtr::set_session (t);
1295 _playlist_selector->set_session (_session);
1296 nudge_clock->set_session (_session);
1297 _summary->set_session (_session);
1298 _group_tabs->set_session (_session);
1299 _route_groups->set_session (_session);
1300 _regions->set_session (_session);
1301 _snapshots->set_session (_session);
1302 _routes->set_session (_session);
1303 _locations->set_session (_session);
1305 if (rhythm_ferret) {
1306 rhythm_ferret->set_session (_session);
1309 if (analysis_window) {
1310 analysis_window->set_session (_session);
1314 sfbrowser->set_session (_session);
1317 compute_fixed_ruler_scale ();
1319 /* Make sure we have auto loop and auto punch ranges */
1321 Location* loc = _session->locations()->auto_loop_location();
1323 loc->set_name (_("Loop"));
1326 loc = _session->locations()->auto_punch_location();
1329 loc->set_name (_("Punch"));
1332 refresh_location_display ();
1334 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1335 the selected Marker; this needs the LocationMarker list to be available.
1337 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1338 set_state (*node, Stateful::loading_state_version);
1340 /* catch up with the playhead */
1342 _session->request_locate (playhead_cursor->current_frame ());
1343 _pending_initial_locate = true;
1347 /* These signals can all be emitted by a non-GUI thread. Therefore the
1348 handlers for them must not attempt to directly interact with the GUI,
1349 but use PBD::Signal<T>::connect() which accepts an event loop
1350 ("context") where the handler will be asked to run.
1353 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1354 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1355 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1356 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1357 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1358 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1359 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1360 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1361 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1362 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1363 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1364 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1365 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1367 playhead_cursor->show ();
1369 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1370 Config->map_parameters (pc);
1371 _session->config.map_parameters (pc);
1373 restore_ruler_visibility ();
1374 //tempo_map_changed (PropertyChange (0));
1375 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1377 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1378 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1381 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1382 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1385 switch (_snap_type) {
1386 case SnapToRegionStart:
1387 case SnapToRegionEnd:
1388 case SnapToRegionSync:
1389 case SnapToRegionBoundary:
1390 build_region_boundary_cache ();
1397 /* register for undo history */
1398 _session->register_with_memento_command_factory(id(), this);
1399 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1401 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1403 start_updating_meters ();
1407 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1409 if (a->get_name() == "RegionMenu") {
1410 /* When the main menu's region menu is opened, we setup the actions so that they look right
1411 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1412 so we resensitize all region actions when the entered regionview or the region selection
1413 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1414 happens after the region context menu is opened. So we set a flag here, too.
1418 sensitize_the_right_region_actions ();
1419 _last_region_menu_was_main = true;
1424 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1426 using namespace Menu_Helpers;
1428 void (Editor::*emf)(FadeShape);
1429 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1432 images = &_xfade_in_images;
1433 emf = &Editor::set_fade_in_shape;
1435 images = &_xfade_out_images;
1436 emf = &Editor::set_fade_out_shape;
1441 _("Linear (for highly correlated material)"),
1442 *(*images)[FadeLinear],
1443 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1447 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1451 _("Constant power"),
1452 *(*images)[FadeConstantPower],
1453 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1456 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1461 *(*images)[FadeSymmetric],
1462 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1466 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1471 *(*images)[FadeSlow],
1472 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1475 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1480 *(*images)[FadeFast],
1481 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1484 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 /** Pop up a context menu for when the user clicks on a start crossfade */
1489 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1491 using namespace Menu_Helpers;
1492 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1497 MenuList& items (xfade_in_context_menu.items());
1500 if (arv->audio_region()->fade_in_active()) {
1501 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1503 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1506 items.push_back (SeparatorElem());
1507 fill_xfade_menu (items, true);
1509 xfade_in_context_menu.popup (button, time);
1512 /** Pop up a context menu for when the user clicks on an end crossfade */
1514 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1516 using namespace Menu_Helpers;
1517 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1522 MenuList& items (xfade_out_context_menu.items());
1525 if (arv->audio_region()->fade_out_active()) {
1526 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1528 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1531 items.push_back (SeparatorElem());
1532 fill_xfade_menu (items, false);
1534 xfade_out_context_menu.popup (button, time);
1538 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1540 using namespace Menu_Helpers;
1541 Menu* (Editor::*build_menu_function)();
1544 switch (item_type) {
1546 case RegionViewName:
1547 case RegionViewNameHighlight:
1548 case LeftFrameHandle:
1549 case RightFrameHandle:
1550 if (with_selection) {
1551 build_menu_function = &Editor::build_track_selection_context_menu;
1553 build_menu_function = &Editor::build_track_region_context_menu;
1558 if (with_selection) {
1559 build_menu_function = &Editor::build_track_selection_context_menu;
1561 build_menu_function = &Editor::build_track_context_menu;
1566 if (clicked_routeview->track()) {
1567 build_menu_function = &Editor::build_track_context_menu;
1569 build_menu_function = &Editor::build_track_bus_context_menu;
1574 /* probably shouldn't happen but if it does, we don't care */
1578 menu = (this->*build_menu_function)();
1579 menu->set_name ("ArdourContextMenu");
1581 /* now handle specific situations */
1583 switch (item_type) {
1585 case RegionViewName:
1586 case RegionViewNameHighlight:
1587 case LeftFrameHandle:
1588 case RightFrameHandle:
1589 if (!with_selection) {
1590 if (region_edit_menu_split_item) {
1591 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1592 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1594 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1597 if (region_edit_menu_split_multichannel_item) {
1598 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1599 region_edit_menu_split_multichannel_item->set_sensitive (true);
1601 region_edit_menu_split_multichannel_item->set_sensitive (false);
1614 /* probably shouldn't happen but if it does, we don't care */
1618 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1620 /* Bounce to disk */
1622 using namespace Menu_Helpers;
1623 MenuList& edit_items = menu->items();
1625 edit_items.push_back (SeparatorElem());
1627 switch (clicked_routeview->audio_track()->freeze_state()) {
1628 case AudioTrack::NoFreeze:
1629 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1632 case AudioTrack::Frozen:
1633 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1636 case AudioTrack::UnFrozen:
1637 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1643 if (item_type == StreamItem && clicked_routeview) {
1644 clicked_routeview->build_underlay_menu(menu);
1647 /* When the region menu is opened, we setup the actions so that they look right
1650 sensitize_the_right_region_actions ();
1651 _last_region_menu_was_main = false;
1653 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1654 menu->popup (button, time);
1658 Editor::build_track_context_menu ()
1660 using namespace Menu_Helpers;
1662 MenuList& edit_items = track_context_menu.items();
1665 add_dstream_context_items (edit_items);
1666 return &track_context_menu;
1670 Editor::build_track_bus_context_menu ()
1672 using namespace Menu_Helpers;
1674 MenuList& edit_items = track_context_menu.items();
1677 add_bus_context_items (edit_items);
1678 return &track_context_menu;
1682 Editor::build_track_region_context_menu ()
1684 using namespace Menu_Helpers;
1685 MenuList& edit_items = track_region_context_menu.items();
1688 /* we've just cleared the track region context menu, so the menu that these
1689 two items were on will have disappeared; stop them dangling.
1691 region_edit_menu_split_item = 0;
1692 region_edit_menu_split_multichannel_item = 0;
1694 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1697 boost::shared_ptr<Track> tr;
1698 boost::shared_ptr<Playlist> pl;
1700 if ((tr = rtv->track())) {
1701 add_region_context_items (edit_items, tr);
1705 add_dstream_context_items (edit_items);
1707 return &track_region_context_menu;
1711 Editor::analyze_region_selection ()
1713 if (analysis_window == 0) {
1714 analysis_window = new AnalysisWindow();
1717 analysis_window->set_session(_session);
1719 analysis_window->show_all();
1722 analysis_window->set_regionmode();
1723 analysis_window->analyze();
1725 analysis_window->present();
1729 Editor::analyze_range_selection()
1731 if (analysis_window == 0) {
1732 analysis_window = new AnalysisWindow();
1735 analysis_window->set_session(_session);
1737 analysis_window->show_all();
1740 analysis_window->set_rangemode();
1741 analysis_window->analyze();
1743 analysis_window->present();
1747 Editor::build_track_selection_context_menu ()
1749 using namespace Menu_Helpers;
1750 MenuList& edit_items = track_selection_context_menu.items();
1751 edit_items.clear ();
1753 add_selection_context_items (edit_items);
1754 // edit_items.push_back (SeparatorElem());
1755 // add_dstream_context_items (edit_items);
1757 return &track_selection_context_menu;
1761 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1763 using namespace Menu_Helpers;
1765 /* OK, stick the region submenu at the top of the list, and then add
1769 RegionSelection rs = get_regions_from_selection_and_entered ();
1771 string::size_type pos = 0;
1772 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1774 /* we have to hack up the region name because "_" has a special
1775 meaning for menu titles.
1778 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1779 menu_item_name.replace (pos, 1, "__");
1783 if (_popup_region_menu_item == 0) {
1784 _popup_region_menu_item = new MenuItem (menu_item_name);
1785 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1786 _popup_region_menu_item->show ();
1788 _popup_region_menu_item->set_label (menu_item_name);
1791 const framepos_t position = get_preferred_edit_position (false, true);
1793 edit_items.push_back (*_popup_region_menu_item);
1794 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1795 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1797 edit_items.push_back (SeparatorElem());
1800 /** Add context menu items relevant to selection ranges.
1801 * @param edit_items List to add the items to.
1804 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1806 using namespace Menu_Helpers;
1808 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1809 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1811 edit_items.push_back (SeparatorElem());
1812 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1814 edit_items.push_back (SeparatorElem());
1815 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1817 edit_items.push_back (SeparatorElem());
1819 edit_items.push_back (
1821 _("Move Range Start to Previous Region Boundary"),
1822 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1826 edit_items.push_back (
1828 _("Move Range Start to Next Region Boundary"),
1829 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1833 edit_items.push_back (
1835 _("Move Range End to Previous Region Boundary"),
1836 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1840 edit_items.push_back (
1842 _("Move Range End to Next Region Boundary"),
1843 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1847 edit_items.push_back (SeparatorElem());
1848 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1849 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1851 edit_items.push_back (SeparatorElem());
1852 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1854 edit_items.push_back (SeparatorElem());
1855 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1856 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1857 edit_items.push_back (MenuElem (_("Set Session Start/End from Range"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1859 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1862 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1864 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1865 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1867 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1869 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1870 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1871 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1872 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1873 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1874 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1880 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1882 using namespace Menu_Helpers;
1886 Menu *play_menu = manage (new Menu);
1887 MenuList& play_items = play_menu->items();
1888 play_menu->set_name ("ArdourContextMenu");
1890 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1891 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1892 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1893 play_items.push_back (SeparatorElem());
1894 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1896 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1900 Menu *select_menu = manage (new Menu);
1901 MenuList& select_items = select_menu->items();
1902 select_menu->set_name ("ArdourContextMenu");
1904 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1905 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1906 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1907 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1908 select_items.push_back (SeparatorElem());
1909 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1910 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1911 select_items.push_back (SeparatorElem());
1912 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1913 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1914 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1915 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1916 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1917 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1918 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1920 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1924 Menu *cutnpaste_menu = manage (new Menu);
1925 MenuList& cutnpaste_items = cutnpaste_menu->items();
1926 cutnpaste_menu->set_name ("ArdourContextMenu");
1928 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1929 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1930 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1932 cutnpaste_items.push_back (SeparatorElem());
1934 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1935 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1937 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1939 /* Adding new material */
1941 edit_items.push_back (SeparatorElem());
1942 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1943 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1947 Menu *nudge_menu = manage (new Menu());
1948 MenuList& nudge_items = nudge_menu->items();
1949 nudge_menu->set_name ("ArdourContextMenu");
1951 edit_items.push_back (SeparatorElem());
1952 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1953 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1954 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1955 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1957 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1961 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1963 using namespace Menu_Helpers;
1967 Menu *play_menu = manage (new Menu);
1968 MenuList& play_items = play_menu->items();
1969 play_menu->set_name ("ArdourContextMenu");
1971 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1972 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1973 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1977 Menu *select_menu = manage (new Menu);
1978 MenuList& select_items = select_menu->items();
1979 select_menu->set_name ("ArdourContextMenu");
1981 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1982 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1983 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1984 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1985 select_items.push_back (SeparatorElem());
1986 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1987 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1988 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1989 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1991 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1995 Menu *cutnpaste_menu = manage (new Menu);
1996 MenuList& cutnpaste_items = cutnpaste_menu->items();
1997 cutnpaste_menu->set_name ("ArdourContextMenu");
1999 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2000 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2001 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2003 Menu *nudge_menu = manage (new Menu());
2004 MenuList& nudge_items = nudge_menu->items();
2005 nudge_menu->set_name ("ArdourContextMenu");
2007 edit_items.push_back (SeparatorElem());
2008 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2009 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2010 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2011 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2013 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2017 Editor::snap_type() const
2023 Editor::snap_mode() const
2029 Editor::set_snap_to (SnapType st)
2031 unsigned int snap_ind = (unsigned int)st;
2035 if (snap_ind > snap_type_strings.size() - 1) {
2037 _snap_type = (SnapType)snap_ind;
2040 string str = snap_type_strings[snap_ind];
2042 if (str != snap_type_selector.get_text()) {
2043 snap_type_selector.set_text (str);
2048 switch (_snap_type) {
2049 case SnapToBeatDiv128:
2050 case SnapToBeatDiv64:
2051 case SnapToBeatDiv32:
2052 case SnapToBeatDiv28:
2053 case SnapToBeatDiv24:
2054 case SnapToBeatDiv20:
2055 case SnapToBeatDiv16:
2056 case SnapToBeatDiv14:
2057 case SnapToBeatDiv12:
2058 case SnapToBeatDiv10:
2059 case SnapToBeatDiv8:
2060 case SnapToBeatDiv7:
2061 case SnapToBeatDiv6:
2062 case SnapToBeatDiv5:
2063 case SnapToBeatDiv4:
2064 case SnapToBeatDiv3:
2065 case SnapToBeatDiv2: {
2066 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2067 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2069 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2070 current_bbt_points_begin, current_bbt_points_end);
2071 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2072 current_bbt_points_begin, current_bbt_points_end);
2073 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2077 case SnapToRegionStart:
2078 case SnapToRegionEnd:
2079 case SnapToRegionSync:
2080 case SnapToRegionBoundary:
2081 build_region_boundary_cache ();
2089 SnapChanged (); /* EMIT SIGNAL */
2093 Editor::set_snap_mode (SnapMode mode)
2095 string str = snap_mode_strings[(int)mode];
2097 if (internal_editing()) {
2098 internal_snap_mode = mode;
2100 pre_internal_snap_mode = mode;
2105 if (str != snap_mode_selector.get_text ()) {
2106 snap_mode_selector.set_text (str);
2112 Editor::set_edit_point_preference (EditPoint ep, bool force)
2114 bool changed = (_edit_point != ep);
2117 if (Profile->get_mixbus())
2118 if (ep == EditAtSelectedMarker)
2119 ep = EditAtPlayhead;
2121 string str = edit_point_strings[(int)ep];
2122 if (str != edit_point_selector.get_text ()) {
2123 edit_point_selector.set_text (str);
2126 update_all_enter_cursors();
2128 if (!force && !changed) {
2132 const char* action=NULL;
2134 switch (_edit_point) {
2135 case EditAtPlayhead:
2136 action = "edit-at-playhead";
2138 case EditAtSelectedMarker:
2139 action = "edit-at-marker";
2142 action = "edit-at-mouse";
2146 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2148 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2152 bool in_track_canvas;
2154 if (!mouse_frame (foo, in_track_canvas)) {
2155 in_track_canvas = false;
2158 reset_canvas_action_sensitivity (in_track_canvas);
2164 Editor::set_state (const XMLNode& node, int /*version*/)
2166 const XMLProperty* prop;
2173 g.base_width = default_width;
2174 g.base_height = default_height;
2178 if ((geometry = find_named_node (node, "geometry")) != 0) {
2182 if ((prop = geometry->property("x_size")) == 0) {
2183 prop = geometry->property ("x-size");
2186 g.base_width = atoi(prop->value());
2188 if ((prop = geometry->property("y_size")) == 0) {
2189 prop = geometry->property ("y-size");
2192 g.base_height = atoi(prop->value());
2195 if ((prop = geometry->property ("x_pos")) == 0) {
2196 prop = geometry->property ("x-pos");
2199 x = atoi (prop->value());
2202 if ((prop = geometry->property ("y_pos")) == 0) {
2203 prop = geometry->property ("y-pos");
2206 y = atoi (prop->value());
2210 set_default_size (g.base_width, g.base_height);
2213 if (_session && (prop = node.property ("playhead"))) {
2215 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2217 playhead_cursor->set_position (pos);
2219 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2220 playhead_cursor->set_position (0);
2223 playhead_cursor->set_position (0);
2226 if ((prop = node.property ("mixer-width"))) {
2227 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2230 if ((prop = node.property ("zoom-focus"))) {
2231 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2234 if ((prop = node.property ("zoom"))) {
2235 /* older versions of ardour used floating point samples_per_pixel */
2236 double f = PBD::atof (prop->value());
2237 reset_zoom (llrintf (f));
2239 reset_zoom (samples_per_pixel);
2242 if ((prop = node.property ("visible-track-count"))) {
2243 set_visible_track_count (PBD::atoi (prop->value()));
2246 if ((prop = node.property ("snap-to"))) {
2247 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2250 if ((prop = node.property ("snap-mode"))) {
2251 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2254 if ((prop = node.property ("internal-snap-to"))) {
2255 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2258 if ((prop = node.property ("internal-snap-mode"))) {
2259 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2262 if ((prop = node.property ("pre-internal-snap-to"))) {
2263 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2266 if ((prop = node.property ("pre-internal-snap-mode"))) {
2267 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2270 if ((prop = node.property ("mouse-mode"))) {
2271 MouseMode m = str2mousemode(prop->value());
2272 set_mouse_mode (m, true);
2274 set_mouse_mode (MouseObject, true);
2277 if ((prop = node.property ("left-frame")) != 0) {
2279 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2283 reset_x_origin (pos);
2287 if ((prop = node.property ("y-origin")) != 0) {
2288 reset_y_origin (atof (prop->value ()));
2291 if ((prop = node.property ("join-object-range"))) {
2292 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2293 bool yn = string_is_affirmative (prop->value());
2295 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2296 tact->set_active (!yn);
2297 tact->set_active (yn);
2299 set_mouse_mode(mouse_mode, true);
2302 if ((prop = node.property ("edit-point"))) {
2303 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2306 if ((prop = node.property ("show-measures"))) {
2307 bool yn = string_is_affirmative (prop->value());
2308 _show_measures = yn;
2309 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2311 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2312 /* do it twice to force the change */
2313 tact->set_active (!yn);
2314 tact->set_active (yn);
2318 if ((prop = node.property ("follow-playhead"))) {
2319 bool yn = string_is_affirmative (prop->value());
2320 set_follow_playhead (yn);
2321 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2323 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2324 if (tact->get_active() != yn) {
2325 tact->set_active (yn);
2330 if ((prop = node.property ("stationary-playhead"))) {
2331 bool yn = string_is_affirmative (prop->value());
2332 set_stationary_playhead (yn);
2333 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2335 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2336 if (tact->get_active() != yn) {
2337 tact->set_active (yn);
2342 if ((prop = node.property ("region-list-sort-type"))) {
2343 RegionListSortType st;
2344 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2347 if ((prop = node.property ("show-editor-mixer"))) {
2349 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2352 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2353 bool yn = string_is_affirmative (prop->value());
2355 /* do it twice to force the change */
2357 tact->set_active (!yn);
2358 tact->set_active (yn);
2361 if ((prop = node.property ("show-editor-list"))) {
2363 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2366 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2367 bool yn = string_is_affirmative (prop->value());
2369 /* do it twice to force the change */
2371 tact->set_active (!yn);
2372 tact->set_active (yn);
2375 if ((prop = node.property (X_("editor-list-page")))) {
2376 _the_notebook.set_current_page (atoi (prop->value ()));
2379 if ((prop = node.property (X_("show-marker-lines")))) {
2380 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2382 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2383 bool yn = string_is_affirmative (prop->value ());
2385 tact->set_active (!yn);
2386 tact->set_active (yn);
2389 XMLNodeList children = node.children ();
2390 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2391 selection->set_state (**i, Stateful::current_state_version);
2392 _regions->set_state (**i);
2395 if ((prop = node.property ("maximised"))) {
2396 bool yn = string_is_affirmative (prop->value());
2397 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2399 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2400 bool fs = tact && tact->get_active();
2402 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2406 if ((prop = node.property ("nudge-clock-value"))) {
2408 sscanf (prop->value().c_str(), "%" PRId64, &f);
2409 nudge_clock->set (f);
2411 nudge_clock->set_mode (AudioClock::Timecode);
2412 nudge_clock->set (_session->frame_rate() * 5, true);
2419 Editor::get_state ()
2421 XMLNode* node = new XMLNode ("Editor");
2424 id().print (buf, sizeof (buf));
2425 node->add_property ("id", buf);
2427 if (is_realized()) {
2428 Glib::RefPtr<Gdk::Window> win = get_window();
2430 int x, y, width, height;
2431 win->get_root_origin(x, y);
2432 win->get_size(width, height);
2434 XMLNode* geometry = new XMLNode ("geometry");
2436 snprintf(buf, sizeof(buf), "%d", width);
2437 geometry->add_property("x-size", string(buf));
2438 snprintf(buf, sizeof(buf), "%d", height);
2439 geometry->add_property("y-size", string(buf));
2440 snprintf(buf, sizeof(buf), "%d", x);
2441 geometry->add_property("x-pos", string(buf));
2442 snprintf(buf, sizeof(buf), "%d", y);
2443 geometry->add_property("y-pos", string(buf));
2444 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2445 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2446 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2447 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2448 geometry->add_property("edit-vertical-pane-pos", string(buf));
2450 node->add_child_nocopy (*geometry);
2453 maybe_add_mixer_strip_width (*node);
2455 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2457 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2458 node->add_property ("zoom", buf);
2459 node->add_property ("snap-to", enum_2_string (_snap_type));
2460 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2461 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2462 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2463 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2464 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2465 node->add_property ("edit-point", enum_2_string (_edit_point));
2466 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2467 node->add_property ("visible-track-count", buf);
2469 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2470 node->add_property ("playhead", buf);
2471 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2472 node->add_property ("left-frame", buf);
2473 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2474 node->add_property ("y-origin", buf);
2476 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2477 node->add_property ("maximised", _maximised ? "yes" : "no");
2478 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2479 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2480 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2481 node->add_property ("mouse-mode", enum2str(mouse_mode));
2482 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2484 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2486 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2487 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2490 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2492 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2493 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2496 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2497 node->add_property (X_("editor-list-page"), buf);
2499 if (button_bindings) {
2500 XMLNode* bb = new XMLNode (X_("Buttons"));
2501 button_bindings->save (*bb);
2502 node->add_child_nocopy (*bb);
2505 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2507 node->add_child_nocopy (selection->get_state ());
2508 node->add_child_nocopy (_regions->get_state ());
2510 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2511 node->add_property ("nudge-clock-value", buf);
2516 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2517 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2519 * @return pair: TimeAxisView that y is over, layer index.
2521 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2522 * in stacked or expanded region display mode, otherwise 0.
2524 std::pair<TimeAxisView *, double>
2525 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2527 if (!trackview_relative_offset) {
2528 y -= _trackview_group->canvas_origin().y;
2532 return std::make_pair ( (TimeAxisView *) 0, 0);
2535 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2537 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2544 return std::make_pair ( (TimeAxisView *) 0, 0);
2547 /** Snap a position to the grid, if appropriate, taking into account current
2548 * grid settings and also the state of any snap modifier keys that may be pressed.
2549 * @param start Position to snap.
2550 * @param event Event to get current key modifier information from, or 0.
2553 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2555 if (!_session || !event) {
2559 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2560 if (_snap_mode == SnapOff) {
2561 snap_to_internal (start, direction, for_mark);
2564 if (_snap_mode != SnapOff) {
2565 snap_to_internal (start, direction, for_mark);
2571 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2573 if (!_session || _snap_mode == SnapOff) {
2577 snap_to_internal (start, direction, for_mark);
2581 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2583 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2584 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2586 switch (_snap_type) {
2587 case SnapToTimecodeFrame:
2588 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2589 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2590 /* start is already on a whole timecode frame, do nothing */
2591 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2592 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2594 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2598 case SnapToTimecodeSeconds:
2599 if (_session->config.get_timecode_offset_negative()) {
2600 start += _session->config.get_timecode_offset ();
2602 start -= _session->config.get_timecode_offset ();
2604 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2605 (start % one_timecode_second == 0)) {
2606 /* start is already on a whole second, do nothing */
2607 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2608 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2610 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2613 if (_session->config.get_timecode_offset_negative()) {
2614 start -= _session->config.get_timecode_offset ();
2616 start += _session->config.get_timecode_offset ();
2620 case SnapToTimecodeMinutes:
2621 if (_session->config.get_timecode_offset_negative()) {
2622 start += _session->config.get_timecode_offset ();
2624 start -= _session->config.get_timecode_offset ();
2626 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2627 (start % one_timecode_minute == 0)) {
2628 /* start is already on a whole minute, do nothing */
2629 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2630 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2632 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2634 if (_session->config.get_timecode_offset_negative()) {
2635 start -= _session->config.get_timecode_offset ();
2637 start += _session->config.get_timecode_offset ();
2641 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2642 abort(); /*NOTREACHED*/
2647 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2649 const framepos_t one_second = _session->frame_rate();
2650 const framepos_t one_minute = _session->frame_rate() * 60;
2651 framepos_t presnap = start;
2655 switch (_snap_type) {
2656 case SnapToTimecodeFrame:
2657 case SnapToTimecodeSeconds:
2658 case SnapToTimecodeMinutes:
2659 return timecode_snap_to_internal (start, direction, for_mark);
2662 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2663 start % (one_second/75) == 0) {
2664 /* start is already on a whole CD frame, do nothing */
2665 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2666 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2668 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2673 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2674 start % one_second == 0) {
2675 /* start is already on a whole second, do nothing */
2676 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2677 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2679 start = (framepos_t) floor ((double) start / one_second) * one_second;
2684 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2685 start % one_minute == 0) {
2686 /* start is already on a whole minute, do nothing */
2687 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2688 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2690 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2695 start = _session->tempo_map().round_to_bar (start, direction);
2699 start = _session->tempo_map().round_to_beat (start, direction);
2702 case SnapToBeatDiv128:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2705 case SnapToBeatDiv64:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2708 case SnapToBeatDiv32:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2711 case SnapToBeatDiv28:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2714 case SnapToBeatDiv24:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2717 case SnapToBeatDiv20:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2720 case SnapToBeatDiv16:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2723 case SnapToBeatDiv14:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2726 case SnapToBeatDiv12:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2729 case SnapToBeatDiv10:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2732 case SnapToBeatDiv8:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2735 case SnapToBeatDiv7:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2738 case SnapToBeatDiv6:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2741 case SnapToBeatDiv5:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2744 case SnapToBeatDiv4:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2747 case SnapToBeatDiv3:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2750 case SnapToBeatDiv2:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2759 _session->locations()->marks_either_side (start, before, after);
2761 if (before == max_framepos && after == max_framepos) {
2762 /* No marks to snap to, so just don't snap */
2764 } else if (before == max_framepos) {
2766 } else if (after == max_framepos) {
2768 } else if (before != max_framepos && after != max_framepos) {
2769 /* have before and after */
2770 if ((start - before) < (after - start)) {
2779 case SnapToRegionStart:
2780 case SnapToRegionEnd:
2781 case SnapToRegionSync:
2782 case SnapToRegionBoundary:
2783 if (!region_boundary_cache.empty()) {
2785 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2786 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2788 if (direction > 0) {
2789 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2791 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2794 if (next != region_boundary_cache.begin ()) {
2799 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2800 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2802 if (start > (p + n) / 2) {
2811 switch (_snap_mode) {
2817 if (presnap > start) {
2818 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2822 } else if (presnap < start) {
2823 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2829 /* handled at entry */
2837 Editor::setup_toolbar ()
2839 HBox* mode_box = manage(new HBox);
2840 mode_box->set_border_width (2);
2841 mode_box->set_spacing(2);
2843 HBox* mouse_mode_box = manage (new HBox);
2844 HBox* mouse_mode_hbox = manage (new HBox);
2845 VBox* mouse_mode_vbox = manage (new VBox);
2846 Alignment* mouse_mode_align = manage (new Alignment);
2848 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2849 mouse_mode_size_group->add_widget (smart_mode_button);
2850 mouse_mode_size_group->add_widget (mouse_move_button);
2851 mouse_mode_size_group->add_widget (mouse_cut_button);
2852 mouse_mode_size_group->add_widget (mouse_select_button);
2853 mouse_mode_size_group->add_widget (mouse_timefx_button);
2854 mouse_mode_size_group->add_widget (mouse_audition_button);
2855 mouse_mode_size_group->add_widget (mouse_draw_button);
2856 mouse_mode_size_group->add_widget (mouse_content_button);
2858 mouse_mode_size_group->add_widget (zoom_in_button);
2859 mouse_mode_size_group->add_widget (zoom_out_button);
2860 mouse_mode_size_group->add_widget (zoom_preset_selector);
2861 mouse_mode_size_group->add_widget (zoom_out_full_button);
2862 mouse_mode_size_group->add_widget (zoom_focus_selector);
2864 mouse_mode_size_group->add_widget (tav_shrink_button);
2865 mouse_mode_size_group->add_widget (tav_expand_button);
2866 mouse_mode_size_group->add_widget (visible_tracks_selector);
2868 mouse_mode_size_group->add_widget (snap_type_selector);
2869 mouse_mode_size_group->add_widget (snap_mode_selector);
2871 mouse_mode_size_group->add_widget (edit_point_selector);
2872 mouse_mode_size_group->add_widget (edit_mode_selector);
2874 mouse_mode_size_group->add_widget (*nudge_clock);
2875 mouse_mode_size_group->add_widget (nudge_forward_button);
2876 mouse_mode_size_group->add_widget (nudge_backward_button);
2878 mouse_mode_hbox->set_spacing (2);
2880 if (!ARDOUR::Profile->get_trx()) {
2881 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2884 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2885 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2887 if (!ARDOUR::Profile->get_mixbus()) {
2888 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2891 if (!ARDOUR::Profile->get_trx()) {
2892 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2895 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2898 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2900 mouse_mode_align->add (*mouse_mode_vbox);
2901 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2903 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2905 edit_mode_selector.set_name ("mouse mode button");
2907 if (!ARDOUR::Profile->get_trx()) {
2908 mode_box->pack_start (edit_mode_selector, false, false);
2910 mode_box->pack_start (*mouse_mode_box, false, false);
2912 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2913 _mouse_mode_tearoff->set_name ("MouseModeBase");
2914 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2916 if (Profile->get_sae() || Profile->get_mixbus() ) {
2917 _mouse_mode_tearoff->set_can_be_torn_off (false);
2920 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2921 &_mouse_mode_tearoff->tearoff_window()));
2922 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2923 &_mouse_mode_tearoff->tearoff_window(), 1));
2924 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_mouse_mode_tearoff->tearoff_window()));
2926 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_mouse_mode_tearoff->tearoff_window(), 1));
2931 _zoom_box.set_spacing (2);
2932 _zoom_box.set_border_width (2);
2936 zoom_preset_selector.set_name ("zoom button");
2937 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2938 zoom_preset_selector.set_size_request (42, -1);
2940 zoom_in_button.set_name ("zoom button");
2941 zoom_in_button.set_image(::get_icon ("zoom_in"));
2942 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2943 zoom_in_button.set_related_action (act);
2945 zoom_out_button.set_name ("zoom button");
2946 zoom_out_button.set_image(::get_icon ("zoom_out"));
2947 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2948 zoom_out_button.set_related_action (act);
2950 zoom_out_full_button.set_name ("zoom button");
2951 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2952 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2953 zoom_out_full_button.set_related_action (act);
2955 zoom_focus_selector.set_name ("zoom button");
2957 if (ARDOUR::Profile->get_mixbus()) {
2958 _zoom_box.pack_start (zoom_preset_selector, false, false);
2959 } else if (ARDOUR::Profile->get_trx()) {
2960 mode_box->pack_start (zoom_out_button, false, false);
2961 mode_box->pack_start (zoom_in_button, false, false);
2963 _zoom_box.pack_start (zoom_out_button, false, false);
2964 _zoom_box.pack_start (zoom_in_button, false, false);
2965 _zoom_box.pack_start (zoom_out_full_button, false, false);
2966 _zoom_box.pack_start (zoom_focus_selector, false, false);
2969 /* Track zoom buttons */
2970 visible_tracks_selector.set_name ("zoom button");
2971 if (Profile->get_mixbus()) {
2972 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2973 visible_tracks_selector.set_size_request (42, -1);
2975 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2978 tav_expand_button.set_name ("zoom button");
2979 tav_expand_button.set_image(::get_icon ("tav_exp"));
2980 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2981 tav_expand_button.set_related_action (act);
2983 tav_shrink_button.set_name ("zoom button");
2984 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2985 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2986 tav_shrink_button.set_related_action (act);
2988 if (ARDOUR::Profile->get_mixbus()) {
2989 _zoom_box.pack_start (visible_tracks_selector);
2990 } else if (ARDOUR::Profile->get_trx()) {
2991 _zoom_box.pack_start (tav_shrink_button);
2992 _zoom_box.pack_start (tav_expand_button);
2994 _zoom_box.pack_start (visible_tracks_selector);
2995 _zoom_box.pack_start (tav_shrink_button);
2996 _zoom_box.pack_start (tav_expand_button);
2999 if (!ARDOUR::Profile->get_trx()) {
3000 _zoom_tearoff = manage (new TearOff (_zoom_box));
3002 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3003 &_zoom_tearoff->tearoff_window()));
3004 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3005 &_zoom_tearoff->tearoff_window(), 0));
3006 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3007 &_zoom_tearoff->tearoff_window()));
3008 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3009 &_zoom_tearoff->tearoff_window(), 0));
3012 if (Profile->get_sae() || Profile->get_mixbus() ) {
3013 _zoom_tearoff->set_can_be_torn_off (false);
3016 snap_box.set_spacing (2);
3017 snap_box.set_border_width (2);
3019 snap_type_selector.set_name ("mouse mode button");
3021 snap_mode_selector.set_name ("mouse mode button");
3023 edit_point_selector.set_name ("mouse mode button");
3025 snap_box.pack_start (snap_mode_selector, false, false);
3026 snap_box.pack_start (snap_type_selector, false, false);
3027 snap_box.pack_start (edit_point_selector, false, false);
3031 HBox *nudge_box = manage (new HBox);
3032 nudge_box->set_spacing (2);
3033 nudge_box->set_border_width (2);
3035 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3036 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3038 nudge_box->pack_start (nudge_backward_button, false, false);
3039 nudge_box->pack_start (nudge_forward_button, false, false);
3040 nudge_box->pack_start (*nudge_clock, false, false);
3043 /* Pack everything in... */
3045 HBox* hbox = manage (new HBox);
3046 hbox->set_spacing(2);
3048 _tools_tearoff = manage (new TearOff (*hbox));
3049 _tools_tearoff->set_name ("MouseModeBase");
3050 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3052 if (Profile->get_sae() || Profile->get_mixbus()) {
3053 _tools_tearoff->set_can_be_torn_off (false);
3056 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3057 &_tools_tearoff->tearoff_window()));
3058 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3059 &_tools_tearoff->tearoff_window(), 0));
3060 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3061 &_tools_tearoff->tearoff_window()));
3062 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3063 &_tools_tearoff->tearoff_window(), 0));
3065 toolbar_hbox.set_spacing (2);
3066 toolbar_hbox.set_border_width (1);
3068 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3069 if (!ARDOUR::Profile->get_trx()) {
3070 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3071 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3074 if (!ARDOUR::Profile->get_trx()) {
3075 hbox->pack_start (snap_box, false, false);
3076 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3077 hbox->pack_start (*nudge_box, false, false);
3079 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3082 hbox->pack_start (panic_box, false, false);
3086 toolbar_base.set_name ("ToolBarBase");
3087 toolbar_base.add (toolbar_hbox);
3089 _toolbar_viewport.add (toolbar_base);
3090 /* stick to the required height but allow width to vary if there's not enough room */
3091 _toolbar_viewport.set_size_request (1, -1);
3093 toolbar_frame.set_shadow_type (SHADOW_OUT);
3094 toolbar_frame.set_name ("BaseFrame");
3095 toolbar_frame.add (_toolbar_viewport);
3099 Editor::build_edit_point_menu ()
3101 using namespace Menu_Helpers;
3103 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3104 if(!Profile->get_mixbus())
3105 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3106 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3108 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3112 Editor::build_edit_mode_menu ()
3114 using namespace Menu_Helpers;
3116 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3117 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3118 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3119 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3121 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3125 Editor::build_snap_mode_menu ()
3127 using namespace Menu_Helpers;
3129 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3130 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3131 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3133 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3137 Editor::build_snap_type_menu ()
3139 using namespace Menu_Helpers;
3141 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3142 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3143 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3144 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3145 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3146 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3147 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3148 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3149 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3150 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3172 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3177 Editor::setup_tooltips ()
3179 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3180 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3181 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3182 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Grab/Select Objects"));
3183 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3184 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3185 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3186 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Edit Contents (notes and automation)"));
3187 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3188 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3189 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3190 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3191 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3192 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3193 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3194 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3195 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3196 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3197 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3198 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3199 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3200 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3201 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3202 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3206 Editor::convert_drop_to_paths (
3207 vector<string>& paths,
3208 const RefPtr<Gdk::DragContext>& /*context*/,
3211 const SelectionData& data,
3215 if (_session == 0) {
3219 vector<string> uris = data.get_uris();
3223 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3224 are actually URI lists. So do it by hand.
3227 if (data.get_target() != "text/plain") {
3231 /* Parse the "uri-list" format that Nautilus provides,
3232 where each pathname is delimited by \r\n.
3234 THERE MAY BE NO NULL TERMINATING CHAR!!!
3237 string txt = data.get_text();
3241 p = (char *) malloc (txt.length() + 1);
3242 txt.copy (p, txt.length(), 0);
3243 p[txt.length()] = '\0';
3249 while (g_ascii_isspace (*p))
3253 while (*q && (*q != '\n') && (*q != '\r')) {
3260 while (q > p && g_ascii_isspace (*q))
3265 uris.push_back (string (p, q - p + 1));
3269 p = strchr (p, '\n');
3281 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3282 if ((*i).substr (0,7) == "file://") {
3283 paths.push_back (Glib::filename_from_uri (*i));
3291 Editor::new_tempo_section ()
3296 Editor::map_transport_state ()
3298 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3300 if (_session && _session->transport_stopped()) {
3301 have_pending_keyboard_selection = false;
3304 update_loop_range_view ();
3310 Editor::begin_reversible_command (string name)
3313 before.push_back (&_selection_memento->get_state ());
3314 _session->begin_reversible_command (name);
3319 Editor::begin_reversible_command (GQuark q)
3322 before.push_back (&_selection_memento->get_state ());
3323 _session->begin_reversible_command (q);
3328 Editor::commit_reversible_command ()
3331 if (before.size() == 1) {
3332 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3335 if (!before.empty()) {
3339 _session->commit_reversible_command ();
3344 Editor::history_changed ()
3348 if (undo_action && _session) {
3349 if (_session->undo_depth() == 0) {
3350 label = S_("Command|Undo");
3352 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3354 undo_action->property_label() = label;
3357 if (redo_action && _session) {
3358 if (_session->redo_depth() == 0) {
3361 label = string_compose(_("Redo (%1)"), _session->next_redo());
3363 redo_action->property_label() = label;
3368 Editor::duplicate_range (bool with_dialog)
3372 RegionSelection rs = get_regions_from_selection_and_entered ();
3374 if ( selection->time.length() == 0 && rs.empty()) {
3380 ArdourDialog win (_("Duplicate"));
3381 Label label (_("Number of duplications:"));
3382 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3383 SpinButton spinner (adjustment, 0.0, 1);
3386 win.get_vbox()->set_spacing (12);
3387 win.get_vbox()->pack_start (hbox);
3388 hbox.set_border_width (6);
3389 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3391 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3392 place, visually. so do this by hand.
3395 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3396 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3397 spinner.grab_focus();
3403 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3404 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3405 win.set_default_response (RESPONSE_ACCEPT);
3407 spinner.grab_focus ();
3409 switch (win.run ()) {
3410 case RESPONSE_ACCEPT:
3416 times = adjustment.get_value();
3419 if ((current_mouse_mode() == Editing::MouseRange)) {
3420 if (selection->time.length()) {
3421 duplicate_selection (times);
3423 } else if (get_smart_mode()) {
3424 if (selection->time.length()) {
3425 duplicate_selection (times);
3427 duplicate_some_regions (rs, times);
3429 duplicate_some_regions (rs, times);
3434 Editor::set_edit_mode (EditMode m)
3436 Config->set_edit_mode (m);
3440 Editor::cycle_edit_mode ()
3442 switch (Config->get_edit_mode()) {
3444 if (Profile->get_sae()) {
3445 Config->set_edit_mode (Lock);
3447 Config->set_edit_mode (Ripple);
3452 Config->set_edit_mode (Lock);
3455 Config->set_edit_mode (Slide);
3461 Editor::edit_mode_selection_done ( EditMode m )
3463 Config->set_edit_mode ( m );
3467 Editor::snap_type_selection_done (SnapType snaptype)
3469 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3471 ract->set_active ();
3476 Editor::snap_mode_selection_done (SnapMode mode)
3478 RefPtr<RadioAction> ract = snap_mode_action (mode);
3481 ract->set_active (true);
3486 Editor::cycle_edit_point (bool with_marker)
3488 if(Profile->get_mixbus())
3489 with_marker = false;
3491 switch (_edit_point) {
3493 set_edit_point_preference (EditAtPlayhead);
3495 case EditAtPlayhead:
3497 set_edit_point_preference (EditAtSelectedMarker);
3499 set_edit_point_preference (EditAtMouse);
3502 case EditAtSelectedMarker:
3503 set_edit_point_preference (EditAtMouse);
3509 Editor::edit_point_selection_done (EditPoint ep)
3511 set_edit_point_preference ( ep );
3515 Editor::build_zoom_focus_menu ()
3517 using namespace Menu_Helpers;
3519 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3520 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3521 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3522 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3523 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3524 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3526 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3530 Editor::zoom_focus_selection_done ( ZoomFocus f )
3532 RefPtr<RadioAction> ract = zoom_focus_action (f);
3534 ract->set_active ();
3539 Editor::build_track_count_menu ()
3541 using namespace Menu_Helpers;
3543 if (!Profile->get_mixbus()) {
3544 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3545 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3546 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3547 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3548 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3549 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3550 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3551 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3552 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3553 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3554 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3555 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3556 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3558 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3559 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3560 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3561 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3562 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3563 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3564 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3565 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3566 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3567 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3569 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3570 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3571 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3572 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3573 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3574 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3575 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3576 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3577 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3578 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3579 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3584 Editor::set_zoom_preset (int64_t ms)
3587 temporal_zoom_session();
3591 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3592 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3596 Editor::set_visible_track_count (int32_t n)
3598 _visible_track_count = n;
3600 /* if the canvas hasn't really been allocated any size yet, just
3601 record the desired number of visible tracks and return. when canvas
3602 allocation happens, we will get called again and then we can do the
3606 if (_visible_canvas_height <= 1) {
3612 DisplaySuspender ds;
3614 if (_visible_track_count > 0) {
3615 h = trackviews_height() / _visible_track_count;
3616 std::ostringstream s;
3617 s << _visible_track_count;
3619 } else if (_visible_track_count == 0) {
3621 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3622 if ((*i)->marked_for_display()) {
3626 h = trackviews_height() / n;
3629 /* negative value means that the visible track count has
3630 been overridden by explicit track height changes.
3632 visible_tracks_selector.set_text (X_("*"));
3636 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3637 (*i)->set_height (h);
3640 if (str != visible_tracks_selector.get_text()) {
3641 visible_tracks_selector.set_text (str);
3646 Editor::override_visible_track_count ()
3648 _visible_track_count = -1;
3649 visible_tracks_selector.set_text ( _("*") );
3653 Editor::edit_controls_button_release (GdkEventButton* ev)
3655 if (Keyboard::is_context_menu_event (ev)) {
3656 ARDOUR_UI::instance()->add_route (this);
3657 } else if (ev->button == 1) {
3658 selection->clear_tracks ();
3665 Editor::mouse_select_button_release (GdkEventButton* ev)
3667 /* this handles just right-clicks */
3669 if (ev->button != 3) {
3677 Editor::set_zoom_focus (ZoomFocus f)
3679 string str = zoom_focus_strings[(int)f];
3681 if (str != zoom_focus_selector.get_text()) {
3682 zoom_focus_selector.set_text (str);
3685 if (zoom_focus != f) {
3692 Editor::cycle_zoom_focus ()
3694 switch (zoom_focus) {
3696 set_zoom_focus (ZoomFocusRight);
3698 case ZoomFocusRight:
3699 set_zoom_focus (ZoomFocusCenter);
3701 case ZoomFocusCenter:
3702 set_zoom_focus (ZoomFocusPlayhead);
3704 case ZoomFocusPlayhead:
3705 set_zoom_focus (ZoomFocusMouse);
3707 case ZoomFocusMouse:
3708 set_zoom_focus (ZoomFocusEdit);
3711 set_zoom_focus (ZoomFocusLeft);
3717 Editor::ensure_float (Window& win)
3719 win.set_transient_for (*this);
3723 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3725 /* recover or initialize pane positions. do this here rather than earlier because
3726 we don't want the positions to change the child allocations, which they seem to do.
3732 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3741 XMLNode* geometry = find_named_node (*node, "geometry");
3743 if (which == static_cast<Paned*> (&edit_pane)) {
3745 if (done & Horizontal) {
3749 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3750 _notebook_shrunk = string_is_affirmative (prop->value ());
3753 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3754 /* initial allocation is 90% to canvas, 10% to notebook */
3755 pos = (int) floor (alloc.get_width() * 0.90f);
3756 snprintf (buf, sizeof(buf), "%d", pos);
3758 pos = atoi (prop->value());
3761 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3762 edit_pane.set_position (pos);
3765 done = (Pane) (done | Horizontal);
3767 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3769 if (done & Vertical) {
3773 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3774 /* initial allocation is 90% to canvas, 10% to summary */
3775 pos = (int) floor (alloc.get_height() * 0.90f);
3776 snprintf (buf, sizeof(buf), "%d", pos);
3779 pos = atoi (prop->value());
3782 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3783 editor_summary_pane.set_position (pos);
3786 done = (Pane) (done | Vertical);
3791 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3793 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3794 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3795 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3796 top_hbox.remove (toolbar_frame);
3801 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3803 if (toolbar_frame.get_parent() == 0) {
3804 top_hbox.pack_end (toolbar_frame);
3809 Editor::set_show_measures (bool yn)
3811 if (_show_measures != yn) {
3814 if ((_show_measures = yn) == true) {
3816 tempo_lines->show();
3819 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3820 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3822 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3823 draw_measures (begin, end);
3831 Editor::toggle_follow_playhead ()
3833 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3835 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3836 set_follow_playhead (tact->get_active());
3840 /** @param yn true to follow playhead, otherwise false.
3841 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3844 Editor::set_follow_playhead (bool yn, bool catch_up)
3846 if (_follow_playhead != yn) {
3847 if ((_follow_playhead = yn) == true && catch_up) {
3849 reset_x_origin_to_follow_playhead ();
3856 Editor::toggle_stationary_playhead ()
3858 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3860 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3861 set_stationary_playhead (tact->get_active());
3866 Editor::set_stationary_playhead (bool yn)
3868 if (_stationary_playhead != yn) {
3869 if ((_stationary_playhead = yn) == true) {
3871 // FIXME need a 3.0 equivalent of this 2.X call
3872 // update_current_screen ();
3879 Editor::playlist_selector () const
3881 return *_playlist_selector;
3885 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3887 if (paste_count == 0) {
3888 /* don't bother calculating an offset that will be zero anyway */
3892 /* calculate basic unsnapped multi-paste offset */
3893 framecnt_t offset = paste_count * duration;
3895 /* snap offset so pos + offset is aligned to the grid */
3896 framepos_t offset_pos = pos + offset;
3897 snap_to(offset_pos, RoundUpMaybe);
3898 offset = offset_pos - pos;
3904 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3908 switch (_snap_type) {
3910 return Evoral::MusicalTime(1.0);
3913 case SnapToBeatDiv128:
3914 return Evoral::MusicalTime(1.0/128.0);
3916 case SnapToBeatDiv64:
3917 return Evoral::MusicalTime(1.0/64.0);
3919 case SnapToBeatDiv32:
3920 return Evoral::MusicalTime(1.0/32.0);
3922 case SnapToBeatDiv28:
3923 return Evoral::MusicalTime(1.0/28.0);
3925 case SnapToBeatDiv24:
3926 return Evoral::MusicalTime(1.0/24.0);
3928 case SnapToBeatDiv20:
3929 return Evoral::MusicalTime(1.0/20.0);
3931 case SnapToBeatDiv16:
3932 return Evoral::MusicalTime(1.0/16.0);
3934 case SnapToBeatDiv14:
3935 return Evoral::MusicalTime(1.0/14.0);
3937 case SnapToBeatDiv12:
3938 return Evoral::MusicalTime(1.0/12.0);
3940 case SnapToBeatDiv10:
3941 return Evoral::MusicalTime(1.0/10.0);
3943 case SnapToBeatDiv8:
3944 return Evoral::MusicalTime(1.0/8.0);
3946 case SnapToBeatDiv7:
3947 return Evoral::MusicalTime(1.0/7.0);
3949 case SnapToBeatDiv6:
3950 return Evoral::MusicalTime(1.0/6.0);
3952 case SnapToBeatDiv5:
3953 return Evoral::MusicalTime(1.0/5.0);
3955 case SnapToBeatDiv4:
3956 return Evoral::MusicalTime(1.0/4.0);
3958 case SnapToBeatDiv3:
3959 return Evoral::MusicalTime(1.0/3.0);
3961 case SnapToBeatDiv2:
3962 return Evoral::MusicalTime(1.0/2.0);
3967 return Evoral::MusicalTime(_session->tempo_map().meter_at (position).divisions_per_bar());
3972 case SnapToTimecodeFrame:
3973 case SnapToTimecodeSeconds:
3974 case SnapToTimecodeMinutes:
3977 case SnapToRegionStart:
3978 case SnapToRegionEnd:
3979 case SnapToRegionSync:
3980 case SnapToRegionBoundary:
3986 return Evoral::MusicalTime();
3990 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3994 ret = nudge_clock->current_duration (pos);
3995 next = ret + 1; /* XXXX fix me */
4001 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4003 ArdourDialog dialog (_("Playlist Deletion"));
4004 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4005 "If it is kept, its audio files will not be cleaned.\n"
4006 "If it is deleted, audio files used by it alone will be cleaned."),
4009 dialog.set_position (WIN_POS_CENTER);
4010 dialog.get_vbox()->pack_start (label);
4014 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4015 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4016 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4018 switch (dialog.run ()) {
4019 case RESPONSE_ACCEPT:
4020 /* delete the playlist */
4024 case RESPONSE_REJECT:
4025 /* keep the playlist */
4037 Editor::audio_region_selection_covers (framepos_t where)
4039 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4040 if ((*a)->region()->covers (where)) {
4049 Editor::prepare_for_cleanup ()
4051 cut_buffer->clear_regions ();
4052 cut_buffer->clear_playlists ();
4054 selection->clear_regions ();
4055 selection->clear_playlists ();
4057 _regions->suspend_redisplay ();
4061 Editor::finish_cleanup ()
4063 _regions->resume_redisplay ();
4067 Editor::transport_loop_location()
4070 return _session->locations()->auto_loop_location();
4077 Editor::transport_punch_location()
4080 return _session->locations()->auto_punch_location();
4087 Editor::control_layout_scroll (GdkEventScroll* ev)
4089 /* Just forward to the normal canvas scroll method. The coordinate
4090 systems are different but since the canvas is always larger than the
4091 track headers, and aligned with the trackview area, this will work.
4093 In the not too distant future this layout is going away anyway and
4094 headers will be on the canvas.
4096 return canvas_scroll_event (ev, false);
4100 Editor::session_state_saved (string)
4103 _snapshots->redisplay ();
4107 Editor::update_tearoff_visibility()
4109 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4110 _mouse_mode_tearoff->set_visible (visible);
4111 _tools_tearoff->set_visible (visible);
4112 if (_zoom_tearoff) {
4113 _zoom_tearoff->set_visible (visible);
4118 Editor::reattach_all_tearoffs ()
4120 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4121 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4122 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4126 Editor::maximise_editing_space ()
4138 Editor::restore_editing_space ()
4150 * Make new playlists for a given track and also any others that belong
4151 * to the same active route group with the `select' property.
4156 Editor::new_playlists (TimeAxisView* v)
4158 begin_reversible_command (_("new playlists"));
4159 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4160 _session->playlists->get (playlists);
4161 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4162 commit_reversible_command ();
4166 * Use a copy of the current playlist for a given track and also any others that belong
4167 * to the same active route group with the `select' property.
4172 Editor::copy_playlists (TimeAxisView* v)
4174 begin_reversible_command (_("copy playlists"));
4175 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4176 _session->playlists->get (playlists);
4177 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4178 commit_reversible_command ();
4181 /** Clear the current playlist for a given track and also any others that belong
4182 * to the same active route group with the `select' property.
4187 Editor::clear_playlists (TimeAxisView* v)
4189 begin_reversible_command (_("clear playlists"));
4190 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4191 _session->playlists->get (playlists);
4192 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4193 commit_reversible_command ();
4197 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4199 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4203 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4205 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4209 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4211 atv.clear_playlist ();
4215 Editor::on_key_press_event (GdkEventKey* ev)
4217 return key_press_focus_accelerator_handler (*this, ev);
4221 Editor::on_key_release_event (GdkEventKey* ev)
4223 return Gtk::Window::on_key_release_event (ev);
4224 // return key_press_focus_accelerator_handler (*this, ev);
4228 Editor::get_y_origin () const
4230 return vertical_adjustment.get_value ();
4233 /** Queue up a change to the viewport x origin.
4234 * @param frame New x origin.
4237 Editor::reset_x_origin (framepos_t frame)
4239 pending_visual_change.add (VisualChange::TimeOrigin);
4240 pending_visual_change.time_origin = frame;
4241 ensure_visual_change_idle_handler ();
4245 Editor::reset_y_origin (double y)
4247 pending_visual_change.add (VisualChange::YOrigin);
4248 pending_visual_change.y_origin = y;
4249 ensure_visual_change_idle_handler ();
4253 Editor::reset_zoom (framecnt_t spp)
4255 if (spp == samples_per_pixel) {
4259 pending_visual_change.add (VisualChange::ZoomLevel);
4260 pending_visual_change.samples_per_pixel = spp;
4261 ensure_visual_change_idle_handler ();
4265 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4267 reset_x_origin (frame);
4270 if (!no_save_visual) {
4271 undo_visual_stack.push_back (current_visual_state(false));
4275 Editor::VisualState::VisualState (bool with_tracks)
4276 : gui_state (with_tracks ? new GUIObjectState : 0)
4280 Editor::VisualState::~VisualState ()
4285 Editor::VisualState*
4286 Editor::current_visual_state (bool with_tracks)
4288 VisualState* vs = new VisualState (with_tracks);
4289 vs->y_position = vertical_adjustment.get_value();
4290 vs->samples_per_pixel = samples_per_pixel;
4291 vs->leftmost_frame = leftmost_frame;
4292 vs->zoom_focus = zoom_focus;
4295 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4302 Editor::undo_visual_state ()
4304 if (undo_visual_stack.empty()) {
4308 VisualState* vs = undo_visual_stack.back();
4309 undo_visual_stack.pop_back();
4312 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4315 use_visual_state (*vs);
4320 Editor::redo_visual_state ()
4322 if (redo_visual_stack.empty()) {
4326 VisualState* vs = redo_visual_stack.back();
4327 redo_visual_stack.pop_back();
4329 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4330 // why do we check here?
4331 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4334 use_visual_state (*vs);
4339 Editor::swap_visual_state ()
4341 if (undo_visual_stack.empty()) {
4342 redo_visual_state ();
4344 undo_visual_state ();
4349 Editor::use_visual_state (VisualState& vs)
4351 PBD::Unwinder<bool> nsv (no_save_visual, true);
4352 DisplaySuspender ds;
4354 vertical_adjustment.set_value (vs.y_position);
4356 set_zoom_focus (vs.zoom_focus);
4357 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4360 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4362 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4363 (*i)->reset_visual_state ();
4367 _routes->update_visibility ();
4370 /** This is the core function that controls the zoom level of the canvas. It is called
4371 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4372 * @param spp new number of samples per pixel
4375 Editor::set_samples_per_pixel (framecnt_t spp)
4381 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4382 const framecnt_t lots_of_pixels = 4000;
4384 /* if the zoom level is greater than what you'd get trying to display 3
4385 * days of audio on a really big screen, then it's too big.
4388 if (spp * lots_of_pixels > three_days) {
4392 samples_per_pixel = spp;
4395 tempo_lines->tempo_map_changed();
4398 bool const showing_time_selection = selection->time.length() > 0;
4400 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4401 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4402 (*i)->reshow_selection (selection->time);
4406 ZoomChanged (); /* EMIT_SIGNAL */
4408 ArdourCanvas::GtkCanvasViewport* c;
4410 c = get_track_canvas();
4412 c->canvas()->zoomed ();
4415 if (playhead_cursor) {
4416 playhead_cursor->set_position (playhead_cursor->current_frame ());
4419 refresh_location_display();
4420 _summary->set_overlays_dirty ();
4422 update_marker_labels ();
4428 Editor::queue_visual_videotimeline_update ()
4431 * pending_visual_change.add (VisualChange::VideoTimeline);
4432 * or maybe even more specific: which videotimeline-image
4433 * currently it calls update_video_timeline() to update
4434 * _all outdated_ images on the video-timeline.
4435 * see 'exposeimg()' in video_image_frame.cc
4437 ensure_visual_change_idle_handler ();
4441 Editor::ensure_visual_change_idle_handler ()
4443 if (pending_visual_change.idle_handler_id < 0) {
4444 // see comment in add_to_idle_resize above.
4445 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4446 pending_visual_change.being_handled = false;
4451 Editor::_idle_visual_changer (void* arg)
4453 return static_cast<Editor*>(arg)->idle_visual_changer ();
4457 Editor::idle_visual_changer ()
4459 /* set_horizontal_position() below (and maybe other calls) call
4460 gtk_main_iteration(), so it's possible that a signal will be handled
4461 half-way through this method. If this signal wants an
4462 idle_visual_changer we must schedule another one after this one, so
4463 mark the idle_handler_id as -1 here to allow that. Also make a note
4464 that we are doing the visual change, so that changes in response to
4465 super-rapid-screen-update can be dropped if we are still processing
4469 pending_visual_change.idle_handler_id = -1;
4470 pending_visual_change.being_handled = true;
4472 VisualChange vc = pending_visual_change;
4474 pending_visual_change.pending = (VisualChange::Type) 0;
4476 visual_changer (vc);
4478 pending_visual_change.being_handled = false;
4480 return 0; /* this is always a one-shot call */
4484 Editor::visual_changer (const VisualChange& vc)
4486 double const last_time_origin = horizontal_position ();
4488 if (vc.pending & VisualChange::ZoomLevel) {
4489 set_samples_per_pixel (vc.samples_per_pixel);
4491 compute_fixed_ruler_scale ();
4493 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4494 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4496 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4497 current_bbt_points_begin, current_bbt_points_end);
4498 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4499 current_bbt_points_begin, current_bbt_points_end);
4500 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4502 update_video_timeline();
4505 if (vc.pending & VisualChange::TimeOrigin) {
4506 set_horizontal_position (vc.time_origin / samples_per_pixel);
4509 if (vc.pending & VisualChange::YOrigin) {
4510 vertical_adjustment.set_value (vc.y_origin);
4513 if (last_time_origin == horizontal_position ()) {
4514 /* changed signal not emitted */
4515 update_fixed_rulers ();
4516 redisplay_tempo (true);
4519 if (!(vc.pending & VisualChange::ZoomLevel)) {
4520 update_video_timeline();
4523 _summary->set_overlays_dirty ();
4526 struct EditorOrderTimeAxisSorter {
4527 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4528 return a->order () < b->order ();
4533 Editor::sort_track_selection (TrackViewList& sel)
4535 EditorOrderTimeAxisSorter cmp;
4540 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4543 framepos_t where = 0;
4544 EditPoint ep = _edit_point;
4546 if(Profile->get_mixbus())
4547 if (ep == EditAtSelectedMarker)
4550 if (from_context_menu && (ep == EditAtMouse)) {
4551 return canvas_event_sample (&context_click_event, 0, 0);
4554 if (entered_marker) {
4555 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4556 return entered_marker->position();
4559 if (ignore_playhead && ep == EditAtPlayhead) {
4560 ep = EditAtSelectedMarker;
4564 case EditAtPlayhead:
4565 where = _session->audible_frame();
4566 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4569 case EditAtSelectedMarker:
4570 if (!selection->markers.empty()) {
4572 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4575 where = loc->start();
4579 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4587 if (!mouse_frame (where, ignored)) {
4588 /* XXX not right but what can we do ? */
4592 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4600 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4602 if (!_session) return;
4604 begin_reversible_command (cmd);
4608 if ((tll = transport_loop_location()) == 0) {
4609 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4610 XMLNode &before = _session->locations()->get_state();
4611 _session->locations()->add (loc, true);
4612 _session->set_auto_loop_location (loc);
4613 XMLNode &after = _session->locations()->get_state();
4614 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4616 XMLNode &before = tll->get_state();
4617 tll->set_hidden (false, this);
4618 tll->set (start, end);
4619 XMLNode &after = tll->get_state();
4620 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4623 commit_reversible_command ();
4627 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4629 if (!_session) return;
4631 begin_reversible_command (cmd);
4635 if ((tpl = transport_punch_location()) == 0) {
4636 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4637 XMLNode &before = _session->locations()->get_state();
4638 _session->locations()->add (loc, true);
4639 _session->set_auto_punch_location (loc);
4640 XMLNode &after = _session->locations()->get_state();
4641 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4643 XMLNode &before = tpl->get_state();
4644 tpl->set_hidden (false, this);
4645 tpl->set (start, end);
4646 XMLNode &after = tpl->get_state();
4647 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4650 commit_reversible_command ();
4653 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4654 * @param rs List to which found regions are added.
4655 * @param where Time to look at.
4656 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4659 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4661 const TrackViewList* tracks;
4664 tracks = &track_views;
4669 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4671 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4674 boost::shared_ptr<Track> tr;
4675 boost::shared_ptr<Playlist> pl;
4677 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4679 boost::shared_ptr<RegionList> regions = pl->regions_at (
4680 (framepos_t) floor ( (double) where * tr->speed()));
4682 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4683 RegionView* rv = rtv->view()->find_view (*i);
4694 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4696 const TrackViewList* tracks;
4699 tracks = &track_views;
4704 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4705 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4707 boost::shared_ptr<Track> tr;
4708 boost::shared_ptr<Playlist> pl;
4710 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4712 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4713 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4715 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4717 RegionView* rv = rtv->view()->find_view (*i);
4728 /** Get regions using the following method:
4730 * Make a region list using:
4731 * (a) any selected regions
4732 * (b) the intersection of any selected tracks and the edit point(*)
4733 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4735 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4737 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4741 Editor::get_regions_from_selection_and_edit_point ()
4743 RegionSelection regions;
4745 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4746 regions.add (entered_regionview);
4748 regions = selection->regions;
4751 if ( regions.empty() ) {
4752 TrackViewList tracks = selection->tracks;
4754 if (!tracks.empty()) {
4755 /* no region selected or entered, but some selected tracks:
4756 * act on all regions on the selected tracks at the edit point
4758 framepos_t const where = get_preferred_edit_position ();
4759 get_regions_at(regions, where, tracks);
4766 /** Get regions using the following method:
4768 * Make a region list using:
4769 * (a) any selected regions
4770 * (b) the intersection of any selected tracks and the edit point(*)
4771 * (c) if neither exists, then whatever region is under the mouse
4773 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4775 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4778 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4780 RegionSelection regions;
4782 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4783 regions.add (entered_regionview);
4785 regions = selection->regions;
4788 if ( regions.empty() ) {
4789 TrackViewList tracks = selection->tracks;
4791 if (!tracks.empty()) {
4792 /* no region selected or entered, but some selected tracks:
4793 * act on all regions on the selected tracks at the edit point
4795 get_regions_at(regions, pos, tracks);
4802 /** Start with regions that are selected, or the entered regionview if none are selected.
4803 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4804 * of the regions that we started with.
4808 Editor::get_regions_from_selection_and_entered ()
4810 RegionSelection regions = selection->regions;
4812 if (regions.empty() && entered_regionview) {
4813 regions.add (entered_regionview);
4820 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4822 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4823 RouteTimeAxisView* tatv;
4825 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4826 boost::shared_ptr<Playlist> pl;
4827 std::vector<boost::shared_ptr<Region> > results;
4828 boost::shared_ptr<Track> tr;
4830 if ((tr = tatv->track()) == 0) {
4835 if ((pl = (tr->playlist())) != 0) {
4836 boost::shared_ptr<Region> r = pl->region_by_id (id);
4838 RegionView* marv = tatv->view()->find_view (r);
4840 regions.push_back (marv);
4849 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4851 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4853 RouteTimeAxisView* tatv;
4855 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4857 boost::shared_ptr<Playlist> pl;
4858 vector<boost::shared_ptr<Region> > results;
4860 boost::shared_ptr<Track> tr;
4862 if ((tr = tatv->track()) == 0) {
4867 if ((pl = (tr->playlist())) != 0) {
4868 if (src_comparison) {
4869 pl->get_source_equivalent_regions (region, results);
4871 pl->get_region_list_equivalent_regions (region, results);
4875 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4876 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4877 regions.push_back (marv);
4886 Editor::show_rhythm_ferret ()
4888 if (rhythm_ferret == 0) {
4889 rhythm_ferret = new RhythmFerret(*this);
4892 rhythm_ferret->set_session (_session);
4893 rhythm_ferret->show ();
4894 rhythm_ferret->present ();
4898 Editor::first_idle ()
4900 MessageDialog* dialog = 0;
4902 if (track_views.size() > 1) {
4903 dialog = new MessageDialog (
4905 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4909 ARDOUR_UI::instance()->flush_pending ();
4912 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4916 // first idle adds route children (automation tracks), so we need to redisplay here
4917 _routes->redisplay ();
4924 Editor::_idle_resize (gpointer arg)
4926 return ((Editor*)arg)->idle_resize ();
4930 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4932 if (resize_idle_id < 0) {
4933 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
4934 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
4935 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
4937 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
4938 _pending_resize_amount = 0;
4941 /* make a note of the smallest resulting height, so that we can clamp the
4942 lower limit at TimeAxisView::hSmall */
4944 int32_t min_resulting = INT32_MAX;
4946 _pending_resize_amount += h;
4947 _pending_resize_view = view;
4949 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4951 if (selection->tracks.contains (_pending_resize_view)) {
4952 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4953 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4957 if (min_resulting < 0) {
4962 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4963 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4967 /** Handle pending resizing of tracks */
4969 Editor::idle_resize ()
4971 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4973 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4974 selection->tracks.contains (_pending_resize_view)) {
4976 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4977 if (*i != _pending_resize_view) {
4978 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4983 _pending_resize_amount = 0;
4984 _group_tabs->set_dirty ();
4985 resize_idle_id = -1;
4993 ENSURE_GUI_THREAD (*this, &Editor::located);
4996 playhead_cursor->set_position (_session->audible_frame ());
4997 if (_follow_playhead && !_pending_initial_locate) {
4998 reset_x_origin_to_follow_playhead ();
5002 _pending_locate_request = false;
5003 _pending_initial_locate = false;
5007 Editor::region_view_added (RegionView * rv)
5009 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5010 if (rv->region ()->id () == (*pr)) {
5011 selection->add (rv);
5012 selection->regions.pending.erase (pr);
5016 _summary->set_background_dirty ();
5020 Editor::region_view_removed ()
5022 _summary->set_background_dirty ();
5026 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5028 TrackViewList::const_iterator j = track_views.begin ();
5029 while (j != track_views.end()) {
5030 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5031 if (rtv && rtv->route() == r) {
5042 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5046 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5047 TimeAxisView* tv = axis_view_from_route (*i);
5057 Editor::suspend_route_redisplay ()
5060 _routes->suspend_redisplay();
5065 Editor::resume_route_redisplay ()
5068 _routes->resume_redisplay();
5073 Editor::add_routes (RouteList& routes)
5075 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5077 RouteTimeAxisView *rtv;
5078 list<RouteTimeAxisView*> new_views;
5080 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5081 boost::shared_ptr<Route> route = (*x);
5083 if (route->is_auditioner() || route->is_monitor()) {
5087 DataType dt = route->input()->default_type();
5089 if (dt == ARDOUR::DataType::AUDIO) {
5090 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5091 rtv->set_route (route);
5092 } else if (dt == ARDOUR::DataType::MIDI) {
5093 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5094 rtv->set_route (route);
5096 throw unknown_type();
5099 new_views.push_back (rtv);
5100 track_views.push_back (rtv);
5102 rtv->effective_gain_display ();
5104 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5105 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5108 if (new_views.size() > 0) {
5109 _routes->routes_added (new_views);
5110 _summary->routes_added (new_views);
5113 if (show_editor_mixer_when_tracks_arrive) {
5114 show_editor_mixer (true);
5117 editor_list_button.set_sensitive (true);
5121 Editor::timeaxisview_deleted (TimeAxisView *tv)
5123 if (tv == entered_track) {
5127 if (_session && _session->deletion_in_progress()) {
5128 /* the situation is under control */
5132 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5134 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5136 _routes->route_removed (tv);
5138 TimeAxisView::Children c = tv->get_child_list ();
5139 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5140 if (entered_track == i->get()) {
5145 /* remove it from the list of track views */
5147 TrackViewList::iterator i;
5149 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5150 i = track_views.erase (i);
5153 /* update whatever the current mixer strip is displaying, if revelant */
5155 boost::shared_ptr<Route> route;
5158 route = rtav->route ();
5161 if (current_mixer_strip && current_mixer_strip->route() == route) {
5163 TimeAxisView* next_tv;
5165 if (track_views.empty()) {
5167 } else if (i == track_views.end()) {
5168 next_tv = track_views.front();
5175 set_selected_mixer_strip (*next_tv);
5177 /* make the editor mixer strip go away setting the
5178 * button to inactive (which also unticks the menu option)
5181 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5187 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5189 if (apply_to_selection) {
5190 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5192 TrackSelection::iterator j = i;
5195 hide_track_in_display (*i, false);
5200 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5202 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5203 // this will hide the mixer strip
5204 set_selected_mixer_strip (*tv);
5207 _routes->hide_track_in_display (*tv);
5212 Editor::sync_track_view_list_and_routes ()
5214 track_views = TrackViewList (_routes->views ());
5216 _summary->set_dirty ();
5217 _group_tabs->set_dirty ();
5219 return false; // do not call again (until needed)
5223 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5225 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5230 /** Find a RouteTimeAxisView by the ID of its route */
5232 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5234 RouteTimeAxisView* v;
5236 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5237 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5238 if(v->route()->id() == id) {
5248 Editor::fit_route_group (RouteGroup *g)
5250 TrackViewList ts = axis_views_from_routes (g->route_list ());
5255 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5257 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5260 _session->cancel_audition ();
5264 if (_session->is_auditioning()) {
5265 _session->cancel_audition ();
5266 if (r == last_audition_region) {
5271 _session->audition_region (r);
5272 last_audition_region = r;
5277 Editor::hide_a_region (boost::shared_ptr<Region> r)
5279 r->set_hidden (true);
5283 Editor::show_a_region (boost::shared_ptr<Region> r)
5285 r->set_hidden (false);
5289 Editor::audition_region_from_region_list ()
5291 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5295 Editor::hide_region_from_region_list ()
5297 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5301 Editor::show_region_in_region_list ()
5303 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5307 Editor::step_edit_status_change (bool yn)
5310 start_step_editing ();
5312 stop_step_editing ();
5317 Editor::start_step_editing ()
5319 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5323 Editor::stop_step_editing ()
5325 step_edit_connection.disconnect ();
5329 Editor::check_step_edit ()
5331 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5332 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5334 mtv->check_step_edit ();
5338 return true; // do it again, till we stop
5342 Editor::scroll_press (Direction dir)
5344 ++_scroll_callbacks;
5346 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5347 /* delay the first auto-repeat */
5353 scroll_backward (1);
5361 scroll_up_one_track ();
5365 scroll_down_one_track ();
5369 /* do hacky auto-repeat */
5370 if (!_scroll_connection.connected ()) {
5372 _scroll_connection = Glib::signal_timeout().connect (
5373 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5376 _scroll_callbacks = 0;
5383 Editor::scroll_release ()
5385 _scroll_connection.disconnect ();
5388 /** Queue a change for the Editor viewport x origin to follow the playhead */
5390 Editor::reset_x_origin_to_follow_playhead ()
5392 framepos_t const frame = playhead_cursor->current_frame ();
5394 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5396 if (_session->transport_speed() < 0) {
5398 if (frame > (current_page_samples() / 2)) {
5399 center_screen (frame-(current_page_samples()/2));
5401 center_screen (current_page_samples()/2);
5408 if (frame < leftmost_frame) {
5410 if (_session->transport_rolling()) {
5411 /* rolling; end up with the playhead at the right of the page */
5412 l = frame - current_page_samples ();
5414 /* not rolling: end up with the playhead 1/4 of the way along the page */
5415 l = frame - current_page_samples() / 4;
5419 if (_session->transport_rolling()) {
5420 /* rolling: end up with the playhead on the left of the page */
5423 /* not rolling: end up with the playhead 3/4 of the way along the page */
5424 l = frame - 3 * current_page_samples() / 4;
5432 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5438 Editor::super_rapid_screen_update ()
5440 if (!_session || !_session->engine().running()) {
5444 /* METERING / MIXER STRIPS */
5446 /* update track meters, if required */
5447 if (is_mapped() && meters_running) {
5448 RouteTimeAxisView* rtv;
5449 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5450 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5451 rtv->fast_update ();
5456 /* and any current mixer strip */
5457 if (current_mixer_strip) {
5458 current_mixer_strip->fast_update ();
5461 /* PLAYHEAD AND VIEWPORT */
5463 framepos_t const frame = _session->audible_frame();
5465 /* There are a few reasons why we might not update the playhead / viewport stuff:
5467 * 1. we don't update things when there's a pending locate request, otherwise
5468 * when the editor requests a locate there is a chance that this method
5469 * will move the playhead before the locate request is processed, causing
5471 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5472 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5475 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5477 last_update_frame = frame;
5479 if (!_dragging_playhead) {
5480 playhead_cursor->set_position (frame);
5483 if (!_stationary_playhead) {
5485 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5486 /* We only do this if we aren't already
5487 handling a visual change (ie if
5488 pending_visual_change.being_handled is
5489 false) so that these requests don't stack
5490 up there are too many of them to handle in
5493 reset_x_origin_to_follow_playhead ();
5498 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5502 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5503 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5504 if (target <= 0.0) {
5507 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5508 target = (target * 0.15) + (current * 0.85);
5514 set_horizontal_position (current);
5523 Editor::session_going_away ()
5525 _have_idled = false;
5527 _session_connections.drop_connections ();
5529 super_rapid_screen_update_connection.disconnect ();
5531 selection->clear ();
5532 cut_buffer->clear ();
5534 clicked_regionview = 0;
5535 clicked_axisview = 0;
5536 clicked_routeview = 0;
5537 entered_regionview = 0;
5539 last_update_frame = 0;
5542 playhead_cursor->hide ();
5544 /* rip everything out of the list displays */
5548 _route_groups->clear ();
5550 /* do this first so that deleting a track doesn't reset cms to null
5551 and thus cause a leak.
5554 if (current_mixer_strip) {
5555 if (current_mixer_strip->get_parent() != 0) {
5556 global_hpacker.remove (*current_mixer_strip);
5558 delete current_mixer_strip;
5559 current_mixer_strip = 0;
5562 /* delete all trackviews */
5564 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5567 track_views.clear ();
5569 nudge_clock->set_session (0);
5571 editor_list_button.set_active(false);
5572 editor_list_button.set_sensitive(false);
5574 /* clear tempo/meter rulers */
5575 remove_metric_marks ();
5577 clear_marker_display ();
5579 stop_step_editing ();
5581 /* get rid of any existing editor mixer strip */
5583 WindowTitle title(Glib::get_application_name());
5584 title += _("Editor");
5586 set_title (title.get_string());
5588 SessionHandlePtr::session_going_away ();
5593 Editor::show_editor_list (bool yn)
5596 _the_notebook.show ();
5598 _the_notebook.hide ();
5603 Editor::change_region_layering_order (bool from_context_menu)
5605 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5607 if (!clicked_routeview) {
5608 if (layering_order_editor) {
5609 layering_order_editor->hide ();
5614 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5620 boost::shared_ptr<Playlist> pl = track->playlist();
5626 if (layering_order_editor == 0) {
5627 layering_order_editor = new RegionLayeringOrderEditor (*this);
5630 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5631 layering_order_editor->maybe_present ();
5635 Editor::update_region_layering_order_editor ()
5637 if (layering_order_editor && layering_order_editor->is_visible ()) {
5638 change_region_layering_order (true);
5643 Editor::setup_fade_images ()
5645 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5646 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5647 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5648 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5649 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5651 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5652 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5653 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5654 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5655 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5657 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5658 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5659 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5660 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5661 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5663 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5664 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5665 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5666 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5667 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5671 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5673 Editor::action_menu_item (std::string const & name)
5675 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5678 return *manage (a->create_menu_item ());
5682 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5684 EventBox* b = manage (new EventBox);
5685 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5686 Label* l = manage (new Label (name));
5690 _the_notebook.append_page (widget, *b);
5694 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5696 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5697 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5700 if (ev->type == GDK_2BUTTON_PRESS) {
5702 /* double-click on a notebook tab shrinks or expands the notebook */
5704 if (_notebook_shrunk) {
5705 if (pre_notebook_shrink_pane_width) {
5706 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5708 _notebook_shrunk = false;
5710 pre_notebook_shrink_pane_width = edit_pane.get_position();
5712 /* this expands the LHS of the edit pane to cover the notebook
5713 PAGE but leaves the tabs visible.
5715 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5716 _notebook_shrunk = true;
5724 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5726 using namespace Menu_Helpers;
5728 MenuList& items = _control_point_context_menu.items ();
5731 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5732 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5733 if (!can_remove_control_point (item)) {
5734 items.back().set_sensitive (false);
5737 _control_point_context_menu.popup (event->button.button, event->button.time);
5741 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5743 using namespace Menu_Helpers;
5745 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5750 /* We need to get the selection here and pass it to the operations, since
5751 popping up the menu will cause a region leave event which clears
5752 entered_regionview. */
5754 MidiRegionView& mrv = note->region_view();
5755 const RegionSelection rs = get_regions_from_selection_and_entered ();
5757 MenuList& items = _note_context_menu.items();
5760 items.push_back(MenuElem(_("Delete"),
5761 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5762 items.push_back(MenuElem(_("Edit..."),
5763 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5764 items.push_back(MenuElem(_("Legatize"),
5765 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5766 items.push_back(MenuElem(_("Quantize..."),
5767 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5768 items.push_back(MenuElem(_("Remove Overlap"),
5769 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5771 _note_context_menu.popup (event->button.button, event->button.time);
5775 Editor::zoom_vertical_modifier_released()
5777 _stepping_axis_view = 0;
5781 Editor::ui_parameter_changed (string parameter)
5783 if (parameter == "icon-set") {
5784 while (!_cursor_stack.empty()) {
5785 _cursor_stack.pop_back();
5787 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5788 _cursor_stack.push_back(_cursors->grabber);
5789 } else if (parameter == "draggable-playhead") {
5790 if (_verbose_cursor) {
5791 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());