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"
127 #include "verbose_cursor.h"
132 using namespace ARDOUR;
133 using namespace ARDOUR_UI_UTILS;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
180 static const gchar *_snap_mode_strings[] = {
187 static const gchar *_edit_point_strings[] = {
194 static const gchar *_edit_mode_strings[] = {
202 static const gchar *_zoom_focus_strings[] = {
212 #ifdef USE_RUBBERBAND
213 static const gchar *_rb_opt_strings[] = {
216 N_("Balanced multitimbral mixture"),
217 N_("Unpitched percussion with stable notes"),
218 N_("Crisp monophonic instrumental"),
219 N_("Unpitched solo percussion"),
220 N_("Resample without preserving pitch"),
225 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
228 pane_size_watcher (Paned* pane)
230 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
234 Quartz: impossible to access
236 so stop that by preventing it from ever getting too narrow. 35
237 pixels is basically a rough guess at the tab width.
242 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
244 gint pos = pane->get_position ();
246 if (pos > max_width_of_lhs) {
247 pane->set_position (max_width_of_lhs);
252 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
254 /* time display buttons */
255 , minsec_label (_("Mins:Secs"))
256 , bbt_label (_("Bars:Beats"))
257 , timecode_label (_("Timecode"))
258 , samples_label (_("Samples"))
259 , tempo_label (_("Tempo"))
260 , meter_label (_("Meter"))
261 , mark_label (_("Location Markers"))
262 , range_mark_label (_("Range Markers"))
263 , transport_mark_label (_("Loop/Punch Ranges"))
264 , cd_mark_label (_("CD Markers"))
265 , videotl_label (_("Video Timeline"))
266 , edit_packer (4, 4, true)
268 /* the values here don't matter: layout widgets
269 reset them as needed.
272 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
273 , horizontal_adjustment (0.0, 0.0, 1e16)
274 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
276 , controls_layout (unused_adjustment, vertical_adjustment)
278 /* tool bar related */
280 , toolbar_selection_clock_table (2,3)
281 , _mouse_mode_tearoff (0)
282 , automation_mode_button (_("mode"))
286 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
287 , selection_op_cmd_depth (0)
288 , selection_op_history_it (0)
292 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
293 , meters_running(false)
294 , _pending_locate_request (false)
295 , _pending_initial_locate (false)
296 , _last_cut_copy_source_track (0)
298 , _region_selection_change_updates_region_list (true)
299 , _following_mixer_selection (false)
300 , _control_point_toggled_on_press (false)
301 , _stepping_axis_view (0)
305 /* we are a singleton */
307 PublicEditor::_instance = this;
311 selection = new Selection (this);
312 cut_buffer = new Selection (this);
313 _selection_memento = new SelectionMemento ();
314 selection_op_history.clear();
317 clicked_regionview = 0;
318 clicked_axisview = 0;
319 clicked_routeview = 0;
320 clicked_control_point = 0;
321 last_update_frame = 0;
324 _drags = new DragManager (this);
327 current_mixer_strip = 0;
330 snap_type_strings = I18N (_snap_type_strings);
331 snap_mode_strings = I18N (_snap_mode_strings);
332 zoom_focus_strings = I18N (_zoom_focus_strings);
333 edit_mode_strings = I18N (_edit_mode_strings);
334 edit_point_strings = I18N (_edit_point_strings);
335 #ifdef USE_RUBBERBAND
336 rb_opt_strings = I18N (_rb_opt_strings);
340 build_edit_mode_menu();
341 build_zoom_focus_menu();
342 build_track_count_menu();
343 build_snap_mode_menu();
344 build_snap_type_menu();
345 build_edit_point_menu();
347 snap_threshold = 5.0;
348 bbt_beat_subdivision = 4;
349 _visible_canvas_width = 0;
350 _visible_canvas_height = 0;
351 autoscroll_horizontal_allowed = false;
352 autoscroll_vertical_allowed = false;
357 current_interthread_info = 0;
358 _show_measures = true;
360 show_gain_after_trim = false;
362 have_pending_keyboard_selection = false;
363 _follow_playhead = true;
364 _stationary_playhead = false;
365 editor_ruler_menu = 0;
366 no_ruler_shown_update = false;
368 range_marker_menu = 0;
369 marker_menu_item = 0;
370 tempo_or_meter_marker_menu = 0;
371 transport_marker_menu = 0;
372 new_transport_marker_menu = 0;
373 editor_mixer_strip_width = Wide;
374 show_editor_mixer_when_tracks_arrive = false;
375 region_edit_menu_split_multichannel_item = 0;
376 region_edit_menu_split_item = 0;
379 current_stepping_trackview = 0;
381 entered_regionview = 0;
383 clear_entered_track = false;
386 button_release_can_deselect = true;
387 _dragging_playhead = false;
388 _dragging_edit_point = false;
389 select_new_marker = false;
391 layering_order_editor = 0;
392 no_save_visual = false;
394 within_track_canvas = false;
396 scrubbing_direction = 0;
400 location_marker_color = ARDOUR_UI::config()->color ("location marker");
401 location_range_color = ARDOUR_UI::config()->color ("location range");
402 location_cd_marker_color = ARDOUR_UI::config()->color ("location cd marker");
403 location_loop_color = ARDOUR_UI::config()->color ("location loop");
404 location_punch_color = ARDOUR_UI::config()->color ("location punch");
406 zoom_focus = ZoomFocusLeft;
407 _edit_point = EditAtMouse;
408 _visible_track_count = -1;
410 samples_per_pixel = 2048; /* too early to use reset_zoom () */
412 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::config()->get_font_scale() / 102400.));
413 TimeAxisView::setup_sizes ();
414 Marker::setup_sizes (timebar_height);
416 _scroll_callbacks = 0;
418 bbt_label.set_name ("EditorRulerLabel");
419 bbt_label.set_size_request (-1, (int)timebar_height);
420 bbt_label.set_alignment (1.0, 0.5);
421 bbt_label.set_padding (5,0);
423 bbt_label.set_no_show_all();
424 minsec_label.set_name ("EditorRulerLabel");
425 minsec_label.set_size_request (-1, (int)timebar_height);
426 minsec_label.set_alignment (1.0, 0.5);
427 minsec_label.set_padding (5,0);
428 minsec_label.hide ();
429 minsec_label.set_no_show_all();
430 timecode_label.set_name ("EditorRulerLabel");
431 timecode_label.set_size_request (-1, (int)timebar_height);
432 timecode_label.set_alignment (1.0, 0.5);
433 timecode_label.set_padding (5,0);
434 timecode_label.hide ();
435 timecode_label.set_no_show_all();
436 samples_label.set_name ("EditorRulerLabel");
437 samples_label.set_size_request (-1, (int)timebar_height);
438 samples_label.set_alignment (1.0, 0.5);
439 samples_label.set_padding (5,0);
440 samples_label.hide ();
441 samples_label.set_no_show_all();
443 tempo_label.set_name ("EditorRulerLabel");
444 tempo_label.set_size_request (-1, (int)timebar_height);
445 tempo_label.set_alignment (1.0, 0.5);
446 tempo_label.set_padding (5,0);
448 tempo_label.set_no_show_all();
450 meter_label.set_name ("EditorRulerLabel");
451 meter_label.set_size_request (-1, (int)timebar_height);
452 meter_label.set_alignment (1.0, 0.5);
453 meter_label.set_padding (5,0);
455 meter_label.set_no_show_all();
457 if (Profile->get_trx()) {
458 mark_label.set_text (_("Markers"));
460 mark_label.set_name ("EditorRulerLabel");
461 mark_label.set_size_request (-1, (int)timebar_height);
462 mark_label.set_alignment (1.0, 0.5);
463 mark_label.set_padding (5,0);
465 mark_label.set_no_show_all();
467 cd_mark_label.set_name ("EditorRulerLabel");
468 cd_mark_label.set_size_request (-1, (int)timebar_height);
469 cd_mark_label.set_alignment (1.0, 0.5);
470 cd_mark_label.set_padding (5,0);
471 cd_mark_label.hide();
472 cd_mark_label.set_no_show_all();
474 videotl_bar_height = 4;
475 videotl_label.set_name ("EditorRulerLabel");
476 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
477 videotl_label.set_alignment (1.0, 0.5);
478 videotl_label.set_padding (5,0);
479 videotl_label.hide();
480 videotl_label.set_no_show_all();
482 range_mark_label.set_name ("EditorRulerLabel");
483 range_mark_label.set_size_request (-1, (int)timebar_height);
484 range_mark_label.set_alignment (1.0, 0.5);
485 range_mark_label.set_padding (5,0);
486 range_mark_label.hide();
487 range_mark_label.set_no_show_all();
489 transport_mark_label.set_name ("EditorRulerLabel");
490 transport_mark_label.set_size_request (-1, (int)timebar_height);
491 transport_mark_label.set_alignment (1.0, 0.5);
492 transport_mark_label.set_padding (5,0);
493 transport_mark_label.hide();
494 transport_mark_label.set_no_show_all();
496 initialize_canvas ();
498 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
500 _summary = new EditorSummary (this);
502 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
503 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
505 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
507 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
508 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
510 edit_controls_vbox.set_spacing (0);
511 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
512 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
514 HBox* h = manage (new HBox);
515 _group_tabs = new EditorGroupTabs (this);
516 if (!ARDOUR::Profile->get_trx()) {
517 h->pack_start (*_group_tabs, PACK_SHRINK);
519 h->pack_start (edit_controls_vbox);
520 controls_layout.add (*h);
522 controls_layout.set_name ("EditControlsBase");
523 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
524 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
525 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
527 _cursors = new MouseCursors;
528 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
529 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
531 /* Push default cursor to ever-present bottom of cursor stack. */
532 push_canvas_cursor(_cursors->grabber);
534 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
536 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
537 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
538 pad_line_1->set_outline_color (0xFF0000FF);
544 edit_packer.set_col_spacings (0);
545 edit_packer.set_row_spacings (0);
546 edit_packer.set_homogeneous (false);
547 edit_packer.set_border_width (0);
548 edit_packer.set_name ("EditorWindow");
550 time_bars_event_box.add (time_bars_vbox);
551 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
552 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
554 /* labels for the time bars */
555 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
557 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
559 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
561 bottom_hbox.set_border_width (2);
562 bottom_hbox.set_spacing (3);
564 _route_groups = new EditorRouteGroups (this);
565 _routes = new EditorRoutes (this);
566 _regions = new EditorRegions (this);
567 _snapshots = new EditorSnapshots (this);
568 _locations = new EditorLocations (this);
570 /* these are static location signals */
572 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
573 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
574 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
576 add_notebook_page (_("Regions"), _regions->widget ());
577 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
578 add_notebook_page (_("Snapshots"), _snapshots->widget ());
579 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
580 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
582 _the_notebook.set_show_tabs (true);
583 _the_notebook.set_scrollable (true);
584 _the_notebook.popup_disable ();
585 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
586 _the_notebook.show_all ();
588 _notebook_shrunk = false;
590 editor_summary_pane.pack1(edit_packer);
592 Button* summary_arrows_left_left = manage (new Button);
593 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
594 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
595 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
597 Button* summary_arrows_left_right = manage (new Button);
598 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
599 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
600 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
602 VBox* summary_arrows_left = manage (new VBox);
603 summary_arrows_left->pack_start (*summary_arrows_left_left);
604 summary_arrows_left->pack_start (*summary_arrows_left_right);
606 Button* summary_arrows_right_up = manage (new Button);
607 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
608 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
609 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
611 Button* summary_arrows_right_down = manage (new Button);
612 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
613 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
614 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
616 VBox* summary_arrows_right = manage (new VBox);
617 summary_arrows_right->pack_start (*summary_arrows_right_up);
618 summary_arrows_right->pack_start (*summary_arrows_right_down);
620 Frame* summary_frame = manage (new Frame);
621 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
623 summary_frame->add (*_summary);
624 summary_frame->show ();
626 _summary_hbox.pack_start (*summary_arrows_left, false, false);
627 _summary_hbox.pack_start (*summary_frame, true, true);
628 _summary_hbox.pack_start (*summary_arrows_right, false, false);
630 if (!ARDOUR::Profile->get_trx()) {
631 editor_summary_pane.pack2 (_summary_hbox);
634 edit_pane.pack1 (editor_summary_pane, true, true);
635 if (!ARDOUR::Profile->get_trx()) {
636 edit_pane.pack2 (_the_notebook, false, true);
639 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
641 /* XXX: editor_summary_pane might need similar to the edit_pane */
643 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
645 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
646 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
648 top_hbox.pack_start (toolbar_frame);
650 HBox *hbox = manage (new HBox);
651 hbox->pack_start (edit_pane, true, true);
653 global_vpacker.pack_start (top_hbox, false, false);
654 global_vpacker.pack_start (*hbox, true, true);
656 global_hpacker.pack_start (global_vpacker, true, true);
658 set_name ("EditorWindow");
659 add_accel_group (ActionManager::ui_manager->get_accel_group());
661 status_bar_hpacker.show ();
663 vpacker.pack_end (status_bar_hpacker, false, false);
664 vpacker.pack_end (global_hpacker, true, true);
666 /* register actions now so that set_state() can find them and set toggles/checks etc */
669 /* when we start using our own keybinding system for the editor, this
670 * will be uncommented
676 set_zoom_focus (zoom_focus);
677 set_visible_track_count (_visible_track_count);
678 _snap_type = SnapToBeat;
679 set_snap_to (_snap_type);
680 _snap_mode = SnapOff;
681 set_snap_mode (_snap_mode);
682 set_mouse_mode (MouseObject, true);
683 pre_internal_mouse_mode = MouseObject;
684 pre_internal_snap_type = _snap_type;
685 pre_internal_snap_mode = _snap_mode;
686 internal_snap_type = _snap_type;
687 internal_snap_mode = _snap_mode;
688 set_edit_point_preference (EditAtMouse, true);
690 _playlist_selector = new PlaylistSelector();
691 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
693 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
697 nudge_forward_button.set_name ("nudge button");
698 nudge_forward_button.set_image(::get_icon("nudge_right"));
700 nudge_backward_button.set_name ("nudge button");
701 nudge_backward_button.set_image(::get_icon("nudge_left"));
703 fade_context_menu.set_name ("ArdourContextMenu");
705 /* icons, titles, WM stuff */
707 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
708 Glib::RefPtr<Gdk::Pixbuf> icon;
710 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
711 window_icons.push_back (icon);
713 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
714 window_icons.push_back (icon);
716 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
717 window_icons.push_back (icon);
719 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
720 window_icons.push_back (icon);
722 if (!window_icons.empty()) {
723 // set_icon_list (window_icons);
724 set_default_icon_list (window_icons);
727 WindowTitle title(Glib::get_application_name());
728 title += _("Editor");
729 set_title (title.get_string());
730 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
733 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
735 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
736 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
738 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
740 /* allow external control surfaces/protocols to do various things */
742 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
743 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
744 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
745 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
746 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
747 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
748 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
749 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
750 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
751 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
752 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
753 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
754 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
755 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
757 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
758 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
759 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
760 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
761 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
763 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
765 /* problematic: has to return a value and thus cannot be x-thread */
767 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
769 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
770 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
772 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
774 _ignore_region_action = false;
775 _last_region_menu_was_main = false;
776 _popup_region_menu_item = 0;
778 _ignore_follow_edits = false;
780 _show_marker_lines = false;
782 /* Button bindings */
784 button_bindings = new Bindings;
786 XMLNode* node = button_settings();
788 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
789 button_bindings->load (**i);
795 /* grab current parameter state */
796 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
797 ARDOUR_UI::config()->map_parameters (pc);
799 setup_fade_images ();
806 delete button_bindings;
808 delete _route_groups;
809 delete _track_canvas_viewport;
815 Editor::button_settings () const
817 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
818 XMLNode* node = find_named_node (*settings, X_("Buttons"));
821 node = new XMLNode (X_("Buttons"));
828 Editor::add_toplevel_menu (Container& cont)
830 vpacker.pack_start (cont, false, false);
835 Editor::add_transport_frame (Container& cont)
837 if(ARDOUR::Profile->get_mixbus()) {
838 global_vpacker.pack_start (cont, false, false);
839 global_vpacker.reorder_child (cont, 0);
842 vpacker.pack_start (cont, false, false);
847 Editor::get_smart_mode () const
849 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
853 Editor::catch_vanishing_regionview (RegionView *rv)
855 /* note: the selection will take care of the vanishing
856 audioregionview by itself.
859 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
863 if (clicked_regionview == rv) {
864 clicked_regionview = 0;
867 if (entered_regionview == rv) {
868 set_entered_regionview (0);
871 if (!_all_region_actions_sensitized) {
872 sensitize_all_region_actions (true);
877 Editor::set_entered_regionview (RegionView* rv)
879 if (rv == entered_regionview) {
883 if (entered_regionview) {
884 entered_regionview->exited ();
887 entered_regionview = rv;
889 if (entered_regionview != 0) {
890 entered_regionview->entered ();
893 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
894 /* This RegionView entry might have changed what region actions
895 are allowed, so sensitize them all in case a key is pressed.
897 sensitize_all_region_actions (true);
902 Editor::set_entered_track (TimeAxisView* tav)
905 entered_track->exited ();
911 entered_track->entered ();
916 Editor::show_window ()
918 if (!is_visible ()) {
922 /* XXX: this is a bit unfortunate; it would probably
923 be nicer if we could just call show () above rather
924 than needing the show_all ()
927 /* re-hide stuff if necessary */
928 editor_list_button_toggled ();
929 parameter_changed ("show-summary");
930 parameter_changed ("show-group-tabs");
931 parameter_changed ("show-zoom-tools");
933 /* now reset all audio_time_axis heights, because widgets might need
939 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
940 tv = (static_cast<TimeAxisView*>(*i));
944 if (current_mixer_strip) {
945 current_mixer_strip->hide_things ();
946 current_mixer_strip->parameter_changed ("mixer-element-visibility");
954 Editor::instant_save ()
956 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
961 _session->add_instant_xml(get_state());
963 Config->add_instant_xml(get_state());
968 Editor::control_vertical_zoom_in_all ()
970 tav_zoom_smooth (false, true);
974 Editor::control_vertical_zoom_out_all ()
976 tav_zoom_smooth (true, true);
980 Editor::control_vertical_zoom_in_selected ()
982 tav_zoom_smooth (false, false);
986 Editor::control_vertical_zoom_out_selected ()
988 tav_zoom_smooth (true, false);
992 Editor::control_view (uint32_t view)
994 goto_visual_state (view);
998 Editor::control_unselect ()
1000 selection->clear_tracks ();
1004 Editor::control_select (uint32_t rid, Selection::Operation op)
1006 /* handles the (static) signal from the ControlProtocol class that
1007 * requests setting the selected track to a given RID
1014 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1020 TimeAxisView* tav = axis_view_from_route (r);
1024 case Selection::Add:
1025 selection->add (tav);
1027 case Selection::Toggle:
1028 selection->toggle (tav);
1030 case Selection::Extend:
1032 case Selection::Set:
1033 selection->set (tav);
1037 selection->clear_tracks ();
1042 Editor::control_step_tracks_up ()
1044 scroll_tracks_up_line ();
1048 Editor::control_step_tracks_down ()
1050 scroll_tracks_down_line ();
1054 Editor::control_scroll (float fraction)
1056 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1062 double step = fraction * current_page_samples();
1065 _control_scroll_target is an optional<T>
1067 it acts like a pointer to an framepos_t, with
1068 a operator conversion to boolean to check
1069 that it has a value could possibly use
1070 playhead_cursor->current_frame to store the
1071 value and a boolean in the class to know
1072 when it's out of date
1075 if (!_control_scroll_target) {
1076 _control_scroll_target = _session->transport_frame();
1077 _dragging_playhead = true;
1080 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1081 *_control_scroll_target = 0;
1082 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1083 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1085 *_control_scroll_target += (framepos_t) trunc (step);
1088 /* move visuals, we'll catch up with it later */
1090 playhead_cursor->set_position (*_control_scroll_target);
1091 UpdateAllTransportClocks (*_control_scroll_target);
1093 if (*_control_scroll_target > (current_page_samples() / 2)) {
1094 /* try to center PH in window */
1095 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1101 Now we do a timeout to actually bring the session to the right place
1102 according to the playhead. This is to avoid reading disk buffers on every
1103 call to control_scroll, which is driven by ScrollTimeline and therefore
1104 probably by a control surface wheel which can generate lots of events.
1106 /* cancel the existing timeout */
1108 control_scroll_connection.disconnect ();
1110 /* add the next timeout */
1112 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1116 Editor::deferred_control_scroll (framepos_t /*target*/)
1118 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1119 // reset for next stream
1120 _control_scroll_target = boost::none;
1121 _dragging_playhead = false;
1126 Editor::access_action (std::string action_group, std::string action_item)
1132 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1135 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1143 Editor::on_realize ()
1145 Window::on_realize ();
1148 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1149 start_lock_event_timing ();
1152 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1156 Editor::start_lock_event_timing ()
1158 /* check if we should lock the GUI every 30 seconds */
1160 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1164 Editor::generic_event_handler (GdkEvent* ev)
1167 case GDK_BUTTON_PRESS:
1168 case GDK_BUTTON_RELEASE:
1169 case GDK_MOTION_NOTIFY:
1171 case GDK_KEY_RELEASE:
1172 gettimeofday (&last_event_time, 0);
1175 case GDK_LEAVE_NOTIFY:
1176 switch (ev->crossing.detail) {
1177 case GDK_NOTIFY_UNKNOWN:
1178 case GDK_NOTIFY_INFERIOR:
1179 case GDK_NOTIFY_ANCESTOR:
1181 case GDK_NOTIFY_VIRTUAL:
1182 case GDK_NOTIFY_NONLINEAR:
1183 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1184 /* leaving window, so reset focus, thus ending any and
1185 all text entry operations.
1200 Editor::lock_timeout_callback ()
1202 struct timeval now, delta;
1204 gettimeofday (&now, 0);
1206 timersub (&now, &last_event_time, &delta);
1208 if (delta.tv_sec > (time_t) ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1210 /* don't call again. Returning false will effectively
1211 disconnect us from the timer callback.
1213 unlock() will call start_lock_event_timing() to get things
1223 Editor::map_position_change (framepos_t frame)
1225 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1227 if (_session == 0) {
1231 if (_follow_playhead) {
1232 center_screen (frame);
1235 playhead_cursor->set_position (frame);
1239 Editor::center_screen (framepos_t frame)
1241 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1243 /* if we're off the page, then scroll.
1246 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1247 center_screen_internal (frame, page);
1252 Editor::center_screen_internal (framepos_t frame, float page)
1257 frame -= (framepos_t) page;
1262 reset_x_origin (frame);
1267 Editor::update_title ()
1269 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1272 bool dirty = _session->dirty();
1274 string session_name;
1276 if (_session->snap_name() != _session->name()) {
1277 session_name = _session->snap_name();
1279 session_name = _session->name();
1283 session_name = "*" + session_name;
1286 WindowTitle title(session_name);
1287 title += Glib::get_application_name();
1288 set_title (title.get_string());
1290 /* ::session_going_away() will have taken care of it */
1295 Editor::set_session (Session *t)
1297 SessionHandlePtr::set_session (t);
1303 _playlist_selector->set_session (_session);
1304 nudge_clock->set_session (_session);
1305 _summary->set_session (_session);
1306 _group_tabs->set_session (_session);
1307 _route_groups->set_session (_session);
1308 _regions->set_session (_session);
1309 _snapshots->set_session (_session);
1310 _routes->set_session (_session);
1311 _locations->set_session (_session);
1313 if (rhythm_ferret) {
1314 rhythm_ferret->set_session (_session);
1317 if (analysis_window) {
1318 analysis_window->set_session (_session);
1322 sfbrowser->set_session (_session);
1325 compute_fixed_ruler_scale ();
1327 /* Make sure we have auto loop and auto punch ranges */
1329 Location* loc = _session->locations()->auto_loop_location();
1331 loc->set_name (_("Loop"));
1334 loc = _session->locations()->auto_punch_location();
1337 loc->set_name (_("Punch"));
1340 refresh_location_display ();
1342 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1343 the selected Marker; this needs the LocationMarker list to be available.
1345 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1346 set_state (*node, Stateful::loading_state_version);
1348 /* catch up with the playhead */
1350 _session->request_locate (playhead_cursor->current_frame ());
1351 _pending_initial_locate = true;
1355 /* These signals can all be emitted by a non-GUI thread. Therefore the
1356 handlers for them must not attempt to directly interact with the GUI,
1357 but use PBD::Signal<T>::connect() which accepts an event loop
1358 ("context") where the handler will be asked to run.
1361 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1362 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1363 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1364 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1365 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1366 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1367 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1368 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1369 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1370 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1371 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1372 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1373 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1375 playhead_cursor->show ();
1377 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1378 Config->map_parameters (pc);
1379 _session->config.map_parameters (pc);
1381 restore_ruler_visibility ();
1382 //tempo_map_changed (PropertyChange (0));
1383 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1385 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1386 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1389 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1390 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1393 switch (_snap_type) {
1394 case SnapToRegionStart:
1395 case SnapToRegionEnd:
1396 case SnapToRegionSync:
1397 case SnapToRegionBoundary:
1398 build_region_boundary_cache ();
1405 /* register for undo history */
1406 _session->register_with_memento_command_factory(id(), this);
1407 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1409 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1411 start_updating_meters ();
1415 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1417 if (a->get_name() == "RegionMenu") {
1418 /* When the main menu's region menu is opened, we setup the actions so that they look right
1419 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1420 so we resensitize all region actions when the entered regionview or the region selection
1421 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1422 happens after the region context menu is opened. So we set a flag here, too.
1426 sensitize_the_right_region_actions ();
1427 _last_region_menu_was_main = true;
1432 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1434 using namespace Menu_Helpers;
1436 void (Editor::*emf)(FadeShape);
1437 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1440 images = &_xfade_in_images;
1441 emf = &Editor::set_fade_in_shape;
1443 images = &_xfade_out_images;
1444 emf = &Editor::set_fade_out_shape;
1449 _("Linear (for highly correlated material)"),
1450 *(*images)[FadeLinear],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1455 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 _("Constant power"),
1460 *(*images)[FadeConstantPower],
1461 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSymmetric],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *(*images)[FadeSlow],
1480 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 *(*images)[FadeFast],
1489 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 /** Pop up a context menu for when the user clicks on a start crossfade */
1497 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1499 using namespace Menu_Helpers;
1500 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1505 MenuList& items (xfade_in_context_menu.items());
1508 if (arv->audio_region()->fade_in_active()) {
1509 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1511 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1514 items.push_back (SeparatorElem());
1515 fill_xfade_menu (items, true);
1517 xfade_in_context_menu.popup (button, time);
1520 /** Pop up a context menu for when the user clicks on an end crossfade */
1522 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1524 using namespace Menu_Helpers;
1525 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1530 MenuList& items (xfade_out_context_menu.items());
1533 if (arv->audio_region()->fade_out_active()) {
1534 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1536 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1539 items.push_back (SeparatorElem());
1540 fill_xfade_menu (items, false);
1542 xfade_out_context_menu.popup (button, time);
1546 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1548 using namespace Menu_Helpers;
1549 Menu* (Editor::*build_menu_function)();
1552 switch (item_type) {
1554 case RegionViewName:
1555 case RegionViewNameHighlight:
1556 case LeftFrameHandle:
1557 case RightFrameHandle:
1558 if (with_selection) {
1559 build_menu_function = &Editor::build_track_selection_context_menu;
1561 build_menu_function = &Editor::build_track_region_context_menu;
1566 if (with_selection) {
1567 build_menu_function = &Editor::build_track_selection_context_menu;
1569 build_menu_function = &Editor::build_track_context_menu;
1574 if (clicked_routeview->track()) {
1575 build_menu_function = &Editor::build_track_context_menu;
1577 build_menu_function = &Editor::build_track_bus_context_menu;
1582 /* probably shouldn't happen but if it does, we don't care */
1586 menu = (this->*build_menu_function)();
1587 menu->set_name ("ArdourContextMenu");
1589 /* now handle specific situations */
1591 switch (item_type) {
1593 case RegionViewName:
1594 case RegionViewNameHighlight:
1595 case LeftFrameHandle:
1596 case RightFrameHandle:
1597 if (!with_selection) {
1598 if (region_edit_menu_split_item) {
1599 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1600 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1602 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1605 if (region_edit_menu_split_multichannel_item) {
1606 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1607 region_edit_menu_split_multichannel_item->set_sensitive (true);
1609 region_edit_menu_split_multichannel_item->set_sensitive (false);
1622 /* probably shouldn't happen but if it does, we don't care */
1626 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1628 /* Bounce to disk */
1630 using namespace Menu_Helpers;
1631 MenuList& edit_items = menu->items();
1633 edit_items.push_back (SeparatorElem());
1635 switch (clicked_routeview->audio_track()->freeze_state()) {
1636 case AudioTrack::NoFreeze:
1637 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1640 case AudioTrack::Frozen:
1641 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1644 case AudioTrack::UnFrozen:
1645 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1651 if (item_type == StreamItem && clicked_routeview) {
1652 clicked_routeview->build_underlay_menu(menu);
1655 /* When the region menu is opened, we setup the actions so that they look right
1658 sensitize_the_right_region_actions ();
1659 _last_region_menu_was_main = false;
1661 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1662 menu->popup (button, time);
1666 Editor::build_track_context_menu ()
1668 using namespace Menu_Helpers;
1670 MenuList& edit_items = track_context_menu.items();
1673 add_dstream_context_items (edit_items);
1674 return &track_context_menu;
1678 Editor::build_track_bus_context_menu ()
1680 using namespace Menu_Helpers;
1682 MenuList& edit_items = track_context_menu.items();
1685 add_bus_context_items (edit_items);
1686 return &track_context_menu;
1690 Editor::build_track_region_context_menu ()
1692 using namespace Menu_Helpers;
1693 MenuList& edit_items = track_region_context_menu.items();
1696 /* we've just cleared the track region context menu, so the menu that these
1697 two items were on will have disappeared; stop them dangling.
1699 region_edit_menu_split_item = 0;
1700 region_edit_menu_split_multichannel_item = 0;
1702 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1705 boost::shared_ptr<Track> tr;
1706 boost::shared_ptr<Playlist> pl;
1708 if ((tr = rtv->track())) {
1709 add_region_context_items (edit_items, tr);
1713 add_dstream_context_items (edit_items);
1715 return &track_region_context_menu;
1719 Editor::analyze_region_selection ()
1721 if (analysis_window == 0) {
1722 analysis_window = new AnalysisWindow();
1725 analysis_window->set_session(_session);
1727 analysis_window->show_all();
1730 analysis_window->set_regionmode();
1731 analysis_window->analyze();
1733 analysis_window->present();
1737 Editor::analyze_range_selection()
1739 if (analysis_window == 0) {
1740 analysis_window = new AnalysisWindow();
1743 analysis_window->set_session(_session);
1745 analysis_window->show_all();
1748 analysis_window->set_rangemode();
1749 analysis_window->analyze();
1751 analysis_window->present();
1755 Editor::build_track_selection_context_menu ()
1757 using namespace Menu_Helpers;
1758 MenuList& edit_items = track_selection_context_menu.items();
1759 edit_items.clear ();
1761 add_selection_context_items (edit_items);
1762 // edit_items.push_back (SeparatorElem());
1763 // add_dstream_context_items (edit_items);
1765 return &track_selection_context_menu;
1769 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1771 using namespace Menu_Helpers;
1773 /* OK, stick the region submenu at the top of the list, and then add
1777 RegionSelection rs = get_regions_from_selection_and_entered ();
1779 string::size_type pos = 0;
1780 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1782 /* we have to hack up the region name because "_" has a special
1783 meaning for menu titles.
1786 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1787 menu_item_name.replace (pos, 1, "__");
1791 if (_popup_region_menu_item == 0) {
1792 _popup_region_menu_item = new MenuItem (menu_item_name);
1793 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1794 _popup_region_menu_item->show ();
1796 _popup_region_menu_item->set_label (menu_item_name);
1799 const framepos_t position = get_preferred_edit_position (false, true);
1801 edit_items.push_back (*_popup_region_menu_item);
1802 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1803 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1805 edit_items.push_back (SeparatorElem());
1808 /** Add context menu items relevant to selection ranges.
1809 * @param edit_items List to add the items to.
1812 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1814 using namespace Menu_Helpers;
1816 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1817 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1819 edit_items.push_back (SeparatorElem());
1820 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1822 edit_items.push_back (SeparatorElem());
1823 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1825 edit_items.push_back (SeparatorElem());
1827 edit_items.push_back (
1829 _("Move Range Start to Previous Region Boundary"),
1830 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1834 edit_items.push_back (
1836 _("Move Range Start to Next Region Boundary"),
1837 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1841 edit_items.push_back (
1843 _("Move Range End to Previous Region Boundary"),
1844 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1848 edit_items.push_back (
1850 _("Move Range End to Next Region Boundary"),
1851 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1855 edit_items.push_back (SeparatorElem());
1856 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1857 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1859 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1862 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1864 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1865 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1867 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1870 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1872 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1873 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1875 edit_items.push_back (SeparatorElem());
1876 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1877 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1878 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1879 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1880 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1881 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1882 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1888 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1890 using namespace Menu_Helpers;
1894 Menu *play_menu = manage (new Menu);
1895 MenuList& play_items = play_menu->items();
1896 play_menu->set_name ("ArdourContextMenu");
1898 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1899 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1900 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1901 play_items.push_back (SeparatorElem());
1902 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1904 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1908 Menu *select_menu = manage (new Menu);
1909 MenuList& select_items = select_menu->items();
1910 select_menu->set_name ("ArdourContextMenu");
1912 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1913 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1914 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1915 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1916 select_items.push_back (SeparatorElem());
1917 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1918 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1919 select_items.push_back (SeparatorElem());
1920 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1921 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1922 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1923 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1924 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1925 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1926 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1928 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1932 Menu *cutnpaste_menu = manage (new Menu);
1933 MenuList& cutnpaste_items = cutnpaste_menu->items();
1934 cutnpaste_menu->set_name ("ArdourContextMenu");
1936 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1937 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1938 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1940 cutnpaste_items.push_back (SeparatorElem());
1942 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1943 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1945 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1947 /* Adding new material */
1949 edit_items.push_back (SeparatorElem());
1950 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1951 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1955 Menu *nudge_menu = manage (new Menu());
1956 MenuList& nudge_items = nudge_menu->items();
1957 nudge_menu->set_name ("ArdourContextMenu");
1959 edit_items.push_back (SeparatorElem());
1960 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1961 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1962 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1963 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1965 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1969 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1971 using namespace Menu_Helpers;
1975 Menu *play_menu = manage (new Menu);
1976 MenuList& play_items = play_menu->items();
1977 play_menu->set_name ("ArdourContextMenu");
1979 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1980 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1981 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1985 Menu *select_menu = manage (new Menu);
1986 MenuList& select_items = select_menu->items();
1987 select_menu->set_name ("ArdourContextMenu");
1989 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1990 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1991 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1992 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1993 select_items.push_back (SeparatorElem());
1994 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1995 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1996 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1997 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1999 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2003 Menu *cutnpaste_menu = manage (new Menu);
2004 MenuList& cutnpaste_items = cutnpaste_menu->items();
2005 cutnpaste_menu->set_name ("ArdourContextMenu");
2007 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2008 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2009 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2011 Menu *nudge_menu = manage (new Menu());
2012 MenuList& nudge_items = nudge_menu->items();
2013 nudge_menu->set_name ("ArdourContextMenu");
2015 edit_items.push_back (SeparatorElem());
2016 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2017 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2018 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2019 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2021 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2025 Editor::snap_type() const
2031 Editor::snap_mode() const
2037 Editor::set_snap_to (SnapType st)
2039 unsigned int snap_ind = (unsigned int)st;
2043 if (snap_ind > snap_type_strings.size() - 1) {
2045 _snap_type = (SnapType)snap_ind;
2048 string str = snap_type_strings[snap_ind];
2050 if (str != snap_type_selector.get_text()) {
2051 snap_type_selector.set_text (str);
2056 switch (_snap_type) {
2057 case SnapToBeatDiv128:
2058 case SnapToBeatDiv64:
2059 case SnapToBeatDiv32:
2060 case SnapToBeatDiv28:
2061 case SnapToBeatDiv24:
2062 case SnapToBeatDiv20:
2063 case SnapToBeatDiv16:
2064 case SnapToBeatDiv14:
2065 case SnapToBeatDiv12:
2066 case SnapToBeatDiv10:
2067 case SnapToBeatDiv8:
2068 case SnapToBeatDiv7:
2069 case SnapToBeatDiv6:
2070 case SnapToBeatDiv5:
2071 case SnapToBeatDiv4:
2072 case SnapToBeatDiv3:
2073 case SnapToBeatDiv2: {
2074 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2075 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2077 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2078 current_bbt_points_begin, current_bbt_points_end);
2079 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2080 current_bbt_points_begin, current_bbt_points_end);
2081 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2085 case SnapToRegionStart:
2086 case SnapToRegionEnd:
2087 case SnapToRegionSync:
2088 case SnapToRegionBoundary:
2089 build_region_boundary_cache ();
2097 redisplay_tempo (false);
2099 SnapChanged (); /* EMIT SIGNAL */
2103 Editor::set_snap_mode (SnapMode mode)
2105 string str = snap_mode_strings[(int)mode];
2107 if (internal_editing()) {
2108 internal_snap_mode = mode;
2110 pre_internal_snap_mode = mode;
2115 if (str != snap_mode_selector.get_text ()) {
2116 snap_mode_selector.set_text (str);
2122 Editor::set_edit_point_preference (EditPoint ep, bool force)
2124 bool changed = (_edit_point != ep);
2127 if (Profile->get_mixbus())
2128 if (ep == EditAtSelectedMarker)
2129 ep = EditAtPlayhead;
2131 string str = edit_point_strings[(int)ep];
2132 if (str != edit_point_selector.get_text ()) {
2133 edit_point_selector.set_text (str);
2136 update_all_enter_cursors();
2138 if (!force && !changed) {
2142 const char* action=NULL;
2144 switch (_edit_point) {
2145 case EditAtPlayhead:
2146 action = "edit-at-playhead";
2148 case EditAtSelectedMarker:
2149 action = "edit-at-marker";
2152 action = "edit-at-mouse";
2156 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2158 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2162 bool in_track_canvas;
2164 if (!mouse_frame (foo, in_track_canvas)) {
2165 in_track_canvas = false;
2168 reset_canvas_action_sensitivity (in_track_canvas);
2174 Editor::set_state (const XMLNode& node, int /*version*/)
2176 const XMLProperty* prop;
2183 g.base_width = default_width;
2184 g.base_height = default_height;
2188 if ((geometry = find_named_node (node, "geometry")) != 0) {
2192 if ((prop = geometry->property("x_size")) == 0) {
2193 prop = geometry->property ("x-size");
2196 g.base_width = atoi(prop->value());
2198 if ((prop = geometry->property("y_size")) == 0) {
2199 prop = geometry->property ("y-size");
2202 g.base_height = atoi(prop->value());
2205 if ((prop = geometry->property ("x_pos")) == 0) {
2206 prop = geometry->property ("x-pos");
2209 x = atoi (prop->value());
2212 if ((prop = geometry->property ("y_pos")) == 0) {
2213 prop = geometry->property ("y-pos");
2216 y = atoi (prop->value());
2220 set_default_size (g.base_width, g.base_height);
2223 if (_session && (prop = node.property ("playhead"))) {
2225 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2227 playhead_cursor->set_position (pos);
2229 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2230 playhead_cursor->set_position (0);
2233 playhead_cursor->set_position (0);
2236 if ((prop = node.property ("mixer-width"))) {
2237 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2240 if ((prop = node.property ("zoom-focus"))) {
2241 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2244 if ((prop = node.property ("zoom"))) {
2245 /* older versions of ardour used floating point samples_per_pixel */
2246 double f = PBD::atof (prop->value());
2247 reset_zoom (llrintf (f));
2249 reset_zoom (samples_per_pixel);
2252 if ((prop = node.property ("visible-track-count"))) {
2253 set_visible_track_count (PBD::atoi (prop->value()));
2256 if ((prop = node.property ("snap-to"))) {
2257 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2260 if ((prop = node.property ("snap-mode"))) {
2261 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2264 if ((prop = node.property ("internal-snap-to"))) {
2265 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2268 if ((prop = node.property ("internal-snap-mode"))) {
2269 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2272 if ((prop = node.property ("pre-internal-snap-to"))) {
2273 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2276 if ((prop = node.property ("pre-internal-snap-mode"))) {
2277 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2280 if ((prop = node.property ("mouse-mode"))) {
2281 MouseMode m = str2mousemode(prop->value());
2282 set_mouse_mode (m, true);
2284 set_mouse_mode (MouseObject, true);
2287 if ((prop = node.property ("left-frame")) != 0) {
2289 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2293 reset_x_origin (pos);
2297 if ((prop = node.property ("y-origin")) != 0) {
2298 reset_y_origin (atof (prop->value ()));
2301 if ((prop = node.property ("join-object-range"))) {
2302 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2303 bool yn = string_is_affirmative (prop->value());
2305 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2306 tact->set_active (!yn);
2307 tact->set_active (yn);
2309 set_mouse_mode(mouse_mode, true);
2312 if ((prop = node.property ("edit-point"))) {
2313 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2316 if ((prop = node.property ("show-measures"))) {
2317 bool yn = string_is_affirmative (prop->value());
2318 _show_measures = yn;
2319 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2321 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322 /* do it twice to force the change */
2323 tact->set_active (!yn);
2324 tact->set_active (yn);
2328 if ((prop = node.property ("follow-playhead"))) {
2329 bool yn = string_is_affirmative (prop->value());
2330 set_follow_playhead (yn);
2331 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2333 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2334 if (tact->get_active() != yn) {
2335 tact->set_active (yn);
2340 if ((prop = node.property ("stationary-playhead"))) {
2341 bool yn = string_is_affirmative (prop->value());
2342 set_stationary_playhead (yn);
2343 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2345 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2346 if (tact->get_active() != yn) {
2347 tact->set_active (yn);
2352 if ((prop = node.property ("region-list-sort-type"))) {
2353 RegionListSortType st;
2354 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2357 if ((prop = node.property ("show-editor-mixer"))) {
2359 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2362 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2363 bool yn = string_is_affirmative (prop->value());
2365 /* do it twice to force the change */
2367 tact->set_active (!yn);
2368 tact->set_active (yn);
2371 if ((prop = node.property ("show-editor-list"))) {
2373 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2376 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2377 bool yn = string_is_affirmative (prop->value());
2379 /* do it twice to force the change */
2381 tact->set_active (!yn);
2382 tact->set_active (yn);
2385 if ((prop = node.property (X_("editor-list-page")))) {
2386 _the_notebook.set_current_page (atoi (prop->value ()));
2389 if ((prop = node.property (X_("show-marker-lines")))) {
2390 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2392 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2393 bool yn = string_is_affirmative (prop->value ());
2395 tact->set_active (!yn);
2396 tact->set_active (yn);
2399 XMLNodeList children = node.children ();
2400 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2401 selection->set_state (**i, Stateful::current_state_version);
2402 _regions->set_state (**i);
2405 if ((prop = node.property ("maximised"))) {
2406 bool yn = string_is_affirmative (prop->value());
2407 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2409 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2410 bool fs = tact && tact->get_active();
2412 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2416 if ((prop = node.property ("nudge-clock-value"))) {
2418 sscanf (prop->value().c_str(), "%" PRId64, &f);
2419 nudge_clock->set (f);
2421 nudge_clock->set_mode (AudioClock::Timecode);
2422 nudge_clock->set (_session->frame_rate() * 5, true);
2429 Editor::get_state ()
2431 XMLNode* node = new XMLNode ("Editor");
2434 id().print (buf, sizeof (buf));
2435 node->add_property ("id", buf);
2437 if (is_realized()) {
2438 Glib::RefPtr<Gdk::Window> win = get_window();
2440 int x, y, width, height;
2441 win->get_root_origin(x, y);
2442 win->get_size(width, height);
2444 XMLNode* geometry = new XMLNode ("geometry");
2446 snprintf(buf, sizeof(buf), "%d", width);
2447 geometry->add_property("x-size", string(buf));
2448 snprintf(buf, sizeof(buf), "%d", height);
2449 geometry->add_property("y-size", string(buf));
2450 snprintf(buf, sizeof(buf), "%d", x);
2451 geometry->add_property("x-pos", string(buf));
2452 snprintf(buf, sizeof(buf), "%d", y);
2453 geometry->add_property("y-pos", string(buf));
2454 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2455 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2456 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2457 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2458 geometry->add_property("edit-vertical-pane-pos", string(buf));
2460 node->add_child_nocopy (*geometry);
2463 maybe_add_mixer_strip_width (*node);
2465 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2467 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2468 node->add_property ("zoom", buf);
2469 node->add_property ("snap-to", enum_2_string (_snap_type));
2470 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2471 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2472 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2473 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2474 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2475 node->add_property ("edit-point", enum_2_string (_edit_point));
2476 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2477 node->add_property ("visible-track-count", buf);
2479 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2480 node->add_property ("playhead", buf);
2481 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2482 node->add_property ("left-frame", buf);
2483 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2484 node->add_property ("y-origin", buf);
2486 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2487 node->add_property ("maximised", _maximised ? "yes" : "no");
2488 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2489 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2490 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2491 node->add_property ("mouse-mode", enum2str(mouse_mode));
2492 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2494 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2500 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2502 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2503 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2506 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2507 node->add_property (X_("editor-list-page"), buf);
2509 if (button_bindings) {
2510 XMLNode* bb = new XMLNode (X_("Buttons"));
2511 button_bindings->save (*bb);
2512 node->add_child_nocopy (*bb);
2515 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2517 node->add_child_nocopy (selection->get_state ());
2518 node->add_child_nocopy (_regions->get_state ());
2520 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2521 node->add_property ("nudge-clock-value", buf);
2526 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2527 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2529 * @return pair: TimeAxisView that y is over, layer index.
2531 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2532 * in stacked or expanded region display mode, otherwise 0.
2534 std::pair<TimeAxisView *, double>
2535 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2537 if (!trackview_relative_offset) {
2538 y -= _trackview_group->canvas_origin().y;
2542 return std::make_pair ( (TimeAxisView *) 0, 0);
2545 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2547 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2554 return std::make_pair ( (TimeAxisView *) 0, 0);
2557 /** Snap a position to the grid, if appropriate, taking into account current
2558 * grid settings and also the state of any snap modifier keys that may be pressed.
2559 * @param start Position to snap.
2560 * @param event Event to get current key modifier information from, or 0.
2563 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2565 if (!_session || !event) {
2569 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2570 if (_snap_mode == SnapOff) {
2571 snap_to_internal (start, direction, for_mark);
2574 if (_snap_mode != SnapOff) {
2575 snap_to_internal (start, direction, for_mark);
2581 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark)
2583 if (!_session || _snap_mode == SnapOff) {
2587 snap_to_internal (start, direction, for_mark);
2591 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2593 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2594 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2596 switch (_snap_type) {
2597 case SnapToTimecodeFrame:
2598 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2599 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2600 /* start is already on a whole timecode frame, do nothing */
2601 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2602 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2604 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2608 case SnapToTimecodeSeconds:
2609 if (_session->config.get_timecode_offset_negative()) {
2610 start += _session->config.get_timecode_offset ();
2612 start -= _session->config.get_timecode_offset ();
2614 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2615 (start % one_timecode_second == 0)) {
2616 /* start is already on a whole second, do nothing */
2617 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2618 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2620 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2623 if (_session->config.get_timecode_offset_negative()) {
2624 start -= _session->config.get_timecode_offset ();
2626 start += _session->config.get_timecode_offset ();
2630 case SnapToTimecodeMinutes:
2631 if (_session->config.get_timecode_offset_negative()) {
2632 start += _session->config.get_timecode_offset ();
2634 start -= _session->config.get_timecode_offset ();
2636 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2637 (start % one_timecode_minute == 0)) {
2638 /* start is already on a whole minute, do nothing */
2639 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2640 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2642 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2644 if (_session->config.get_timecode_offset_negative()) {
2645 start -= _session->config.get_timecode_offset ();
2647 start += _session->config.get_timecode_offset ();
2651 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2652 abort(); /*NOTREACHED*/
2657 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark)
2659 const framepos_t one_second = _session->frame_rate();
2660 const framepos_t one_minute = _session->frame_rate() * 60;
2661 framepos_t presnap = start;
2665 switch (_snap_type) {
2666 case SnapToTimecodeFrame:
2667 case SnapToTimecodeSeconds:
2668 case SnapToTimecodeMinutes:
2669 return timecode_snap_to_internal (start, direction, for_mark);
2672 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2673 start % (one_second/75) == 0) {
2674 /* start is already on a whole CD frame, do nothing */
2675 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2676 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2678 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2683 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2684 start % one_second == 0) {
2685 /* start is already on a whole second, do nothing */
2686 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2687 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2689 start = (framepos_t) floor ((double) start / one_second) * one_second;
2694 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2695 start % one_minute == 0) {
2696 /* start is already on a whole minute, do nothing */
2697 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2698 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2700 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2705 start = _session->tempo_map().round_to_bar (start, direction);
2709 start = _session->tempo_map().round_to_beat (start, direction);
2712 case SnapToBeatDiv128:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2715 case SnapToBeatDiv64:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2718 case SnapToBeatDiv32:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2721 case SnapToBeatDiv28:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2724 case SnapToBeatDiv24:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2727 case SnapToBeatDiv20:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2730 case SnapToBeatDiv16:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2733 case SnapToBeatDiv14:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2736 case SnapToBeatDiv12:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2739 case SnapToBeatDiv10:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2742 case SnapToBeatDiv8:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2745 case SnapToBeatDiv7:
2746 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2748 case SnapToBeatDiv6:
2749 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2751 case SnapToBeatDiv5:
2752 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2754 case SnapToBeatDiv4:
2755 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2757 case SnapToBeatDiv3:
2758 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2760 case SnapToBeatDiv2:
2761 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2769 _session->locations()->marks_either_side (start, before, after);
2771 if (before == max_framepos && after == max_framepos) {
2772 /* No marks to snap to, so just don't snap */
2774 } else if (before == max_framepos) {
2776 } else if (after == max_framepos) {
2778 } else if (before != max_framepos && after != max_framepos) {
2779 /* have before and after */
2780 if ((start - before) < (after - start)) {
2789 case SnapToRegionStart:
2790 case SnapToRegionEnd:
2791 case SnapToRegionSync:
2792 case SnapToRegionBoundary:
2793 if (!region_boundary_cache.empty()) {
2795 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2796 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2798 if (direction > 0) {
2799 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2801 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2804 if (next != region_boundary_cache.begin ()) {
2809 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2810 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2812 if (start > (p + n) / 2) {
2821 switch (_snap_mode) {
2827 if (presnap > start) {
2828 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2832 } else if (presnap < start) {
2833 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2839 /* handled at entry */
2847 Editor::setup_toolbar ()
2849 HBox* mode_box = manage(new HBox);
2850 mode_box->set_border_width (2);
2851 mode_box->set_spacing(2);
2853 HBox* mouse_mode_box = manage (new HBox);
2854 HBox* mouse_mode_hbox = manage (new HBox);
2855 VBox* mouse_mode_vbox = manage (new VBox);
2856 Alignment* mouse_mode_align = manage (new Alignment);
2858 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2859 mouse_mode_size_group->add_widget (smart_mode_button);
2860 mouse_mode_size_group->add_widget (mouse_move_button);
2861 mouse_mode_size_group->add_widget (mouse_cut_button);
2862 mouse_mode_size_group->add_widget (mouse_select_button);
2863 mouse_mode_size_group->add_widget (mouse_timefx_button);
2864 mouse_mode_size_group->add_widget (mouse_audition_button);
2865 mouse_mode_size_group->add_widget (mouse_draw_button);
2866 mouse_mode_size_group->add_widget (mouse_content_button);
2868 mouse_mode_size_group->add_widget (zoom_in_button);
2869 mouse_mode_size_group->add_widget (zoom_out_button);
2870 mouse_mode_size_group->add_widget (zoom_preset_selector);
2871 mouse_mode_size_group->add_widget (zoom_out_full_button);
2872 mouse_mode_size_group->add_widget (zoom_focus_selector);
2874 mouse_mode_size_group->add_widget (tav_shrink_button);
2875 mouse_mode_size_group->add_widget (tav_expand_button);
2876 mouse_mode_size_group->add_widget (visible_tracks_selector);
2878 mouse_mode_size_group->add_widget (snap_type_selector);
2879 mouse_mode_size_group->add_widget (snap_mode_selector);
2881 mouse_mode_size_group->add_widget (edit_point_selector);
2882 mouse_mode_size_group->add_widget (edit_mode_selector);
2884 mouse_mode_size_group->add_widget (*nudge_clock);
2885 mouse_mode_size_group->add_widget (nudge_forward_button);
2886 mouse_mode_size_group->add_widget (nudge_backward_button);
2888 mouse_mode_hbox->set_spacing (2);
2890 if (!ARDOUR::Profile->get_trx()) {
2891 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2894 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2895 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2897 if (!ARDOUR::Profile->get_mixbus()) {
2898 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2901 if (!ARDOUR::Profile->get_trx()) {
2902 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2903 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2904 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2905 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2908 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2910 mouse_mode_align->add (*mouse_mode_vbox);
2911 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2913 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2915 edit_mode_selector.set_name ("mouse mode button");
2917 if (!ARDOUR::Profile->get_trx()) {
2918 mode_box->pack_start (edit_mode_selector, false, false);
2920 mode_box->pack_start (*mouse_mode_box, false, false);
2922 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2923 _mouse_mode_tearoff->set_name ("MouseModeBase");
2924 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2926 if (Profile->get_sae() || Profile->get_mixbus() ) {
2927 _mouse_mode_tearoff->set_can_be_torn_off (false);
2930 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2931 &_mouse_mode_tearoff->tearoff_window()));
2932 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2933 &_mouse_mode_tearoff->tearoff_window(), 1));
2934 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2935 &_mouse_mode_tearoff->tearoff_window()));
2936 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2937 &_mouse_mode_tearoff->tearoff_window(), 1));
2941 _zoom_box.set_spacing (2);
2942 _zoom_box.set_border_width (2);
2946 zoom_preset_selector.set_name ("zoom button");
2947 zoom_preset_selector.set_image(::get_icon ("time_exp"));
2948 zoom_preset_selector.set_size_request (42, -1);
2950 zoom_in_button.set_name ("zoom button");
2951 zoom_in_button.set_image(::get_icon ("zoom_in"));
2952 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2953 zoom_in_button.set_related_action (act);
2955 zoom_out_button.set_name ("zoom button");
2956 zoom_out_button.set_image(::get_icon ("zoom_out"));
2957 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2958 zoom_out_button.set_related_action (act);
2960 zoom_out_full_button.set_name ("zoom button");
2961 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2962 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2963 zoom_out_full_button.set_related_action (act);
2965 zoom_focus_selector.set_name ("zoom button");
2967 if (ARDOUR::Profile->get_mixbus()) {
2968 _zoom_box.pack_start (zoom_preset_selector, false, false);
2969 } else if (ARDOUR::Profile->get_trx()) {
2970 mode_box->pack_start (zoom_out_button, false, false);
2971 mode_box->pack_start (zoom_in_button, false, false);
2973 _zoom_box.pack_start (zoom_out_button, false, false);
2974 _zoom_box.pack_start (zoom_in_button, false, false);
2975 _zoom_box.pack_start (zoom_out_full_button, false, false);
2976 _zoom_box.pack_start (zoom_focus_selector, false, false);
2979 /* Track zoom buttons */
2980 visible_tracks_selector.set_name ("zoom button");
2981 if (Profile->get_mixbus()) {
2982 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
2983 visible_tracks_selector.set_size_request (42, -1);
2985 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
2988 tav_expand_button.set_name ("zoom button");
2989 tav_expand_button.set_image(::get_icon ("tav_exp"));
2990 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2991 tav_expand_button.set_related_action (act);
2993 tav_shrink_button.set_name ("zoom button");
2994 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2995 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2996 tav_shrink_button.set_related_action (act);
2998 if (ARDOUR::Profile->get_mixbus()) {
2999 _zoom_box.pack_start (visible_tracks_selector);
3000 } else if (ARDOUR::Profile->get_trx()) {
3001 _zoom_box.pack_start (tav_shrink_button);
3002 _zoom_box.pack_start (tav_expand_button);
3004 _zoom_box.pack_start (visible_tracks_selector);
3005 _zoom_box.pack_start (tav_shrink_button);
3006 _zoom_box.pack_start (tav_expand_button);
3009 if (!ARDOUR::Profile->get_trx()) {
3010 _zoom_tearoff = manage (new TearOff (_zoom_box));
3012 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3013 &_zoom_tearoff->tearoff_window()));
3014 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3015 &_zoom_tearoff->tearoff_window(), 0));
3016 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3017 &_zoom_tearoff->tearoff_window()));
3018 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3019 &_zoom_tearoff->tearoff_window(), 0));
3022 if (Profile->get_sae() || Profile->get_mixbus() ) {
3023 _zoom_tearoff->set_can_be_torn_off (false);
3026 snap_box.set_spacing (2);
3027 snap_box.set_border_width (2);
3029 snap_type_selector.set_name ("mouse mode button");
3031 snap_mode_selector.set_name ("mouse mode button");
3033 edit_point_selector.set_name ("mouse mode button");
3035 snap_box.pack_start (snap_mode_selector, false, false);
3036 snap_box.pack_start (snap_type_selector, false, false);
3037 snap_box.pack_start (edit_point_selector, false, false);
3041 HBox *nudge_box = manage (new HBox);
3042 nudge_box->set_spacing (2);
3043 nudge_box->set_border_width (2);
3045 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3046 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3048 nudge_box->pack_start (nudge_backward_button, false, false);
3049 nudge_box->pack_start (nudge_forward_button, false, false);
3050 nudge_box->pack_start (*nudge_clock, false, false);
3053 /* Pack everything in... */
3055 HBox* hbox = manage (new HBox);
3056 hbox->set_spacing(2);
3058 _tools_tearoff = manage (new TearOff (*hbox));
3059 _tools_tearoff->set_name ("MouseModeBase");
3060 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3062 if (Profile->get_sae() || Profile->get_mixbus()) {
3063 _tools_tearoff->set_can_be_torn_off (false);
3066 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3067 &_tools_tearoff->tearoff_window()));
3068 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3069 &_tools_tearoff->tearoff_window(), 0));
3070 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3071 &_tools_tearoff->tearoff_window()));
3072 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3073 &_tools_tearoff->tearoff_window(), 0));
3075 toolbar_hbox.set_spacing (2);
3076 toolbar_hbox.set_border_width (1);
3078 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3079 if (!ARDOUR::Profile->get_trx()) {
3080 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3081 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3084 if (!ARDOUR::Profile->get_trx()) {
3085 hbox->pack_start (snap_box, false, false);
3086 if ( !Profile->get_small_screen() || Profile->get_mixbus() ) {
3087 hbox->pack_start (*nudge_box, false, false);
3089 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3092 hbox->pack_start (panic_box, false, false);
3096 toolbar_base.set_name ("ToolBarBase");
3097 toolbar_base.add (toolbar_hbox);
3099 _toolbar_viewport.add (toolbar_base);
3100 /* stick to the required height but allow width to vary if there's not enough room */
3101 _toolbar_viewport.set_size_request (1, -1);
3103 toolbar_frame.set_shadow_type (SHADOW_OUT);
3104 toolbar_frame.set_name ("BaseFrame");
3105 toolbar_frame.add (_toolbar_viewport);
3109 Editor::build_edit_point_menu ()
3111 using namespace Menu_Helpers;
3113 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3114 if(!Profile->get_mixbus())
3115 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3116 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3118 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3122 Editor::build_edit_mode_menu ()
3124 using namespace Menu_Helpers;
3126 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3127 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3128 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3129 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3131 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3135 Editor::build_snap_mode_menu ()
3137 using namespace Menu_Helpers;
3139 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3140 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3141 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3143 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3147 Editor::build_snap_type_menu ()
3149 using namespace Menu_Helpers;
3151 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3152 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3153 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3154 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3155 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3156 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3157 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3158 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3159 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3160 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3161 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3162 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3163 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3164 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3165 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3166 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3167 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3168 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3169 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3170 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3171 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3172 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3173 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3174 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3175 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3176 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3177 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3178 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3179 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3180 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3182 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3187 Editor::setup_tooltips ()
3189 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3190 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3191 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3192 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Grab/Select Objects"));
3193 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit Gain/Notes/Automation"));
3194 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3195 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3196 ARDOUR_UI::instance()->set_tip (mouse_content_button, _("Edit Contents (notes and automation)"));
3197 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3198 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3199 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3200 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3201 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3202 ARDOUR_UI::instance()->set_tip (zoom_preset_selector, _("Zoom to Time Scale"));
3203 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3204 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3205 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3206 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3207 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3208 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3209 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3210 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3211 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3212 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3216 Editor::convert_drop_to_paths (
3217 vector<string>& paths,
3218 const RefPtr<Gdk::DragContext>& /*context*/,
3221 const SelectionData& data,
3225 if (_session == 0) {
3229 vector<string> uris = data.get_uris();
3233 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3234 are actually URI lists. So do it by hand.
3237 if (data.get_target() != "text/plain") {
3241 /* Parse the "uri-list" format that Nautilus provides,
3242 where each pathname is delimited by \r\n.
3244 THERE MAY BE NO NULL TERMINATING CHAR!!!
3247 string txt = data.get_text();
3251 p = (char *) malloc (txt.length() + 1);
3252 txt.copy (p, txt.length(), 0);
3253 p[txt.length()] = '\0';
3259 while (g_ascii_isspace (*p))
3263 while (*q && (*q != '\n') && (*q != '\r')) {
3270 while (q > p && g_ascii_isspace (*q))
3275 uris.push_back (string (p, q - p + 1));
3279 p = strchr (p, '\n');
3291 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3292 if ((*i).substr (0,7) == "file://") {
3293 paths.push_back (Glib::filename_from_uri (*i));
3301 Editor::new_tempo_section ()
3306 Editor::map_transport_state ()
3308 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3310 if (_session && _session->transport_stopped()) {
3311 have_pending_keyboard_selection = false;
3314 update_loop_range_view ();
3320 Editor::begin_selection_op_history ()
3322 selection_op_cmd_depth = 0;
3323 selection_op_history_it = 0;
3324 selection_op_history.clear();
3325 selection_undo_action->set_sensitive (false);
3326 selection_redo_action->set_sensitive (false);
3327 selection_op_history.push_front (&_selection_memento->get_state ());
3331 Editor::begin_reversible_selection_op (string name)
3334 //cerr << name << endl;
3335 /* begin/commit pairs can be nested */
3336 selection_op_cmd_depth++;
3341 Editor::commit_reversible_selection_op ()
3344 if (selection_op_cmd_depth == 1) {
3346 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3347 list<XMLNode *>::iterator it = selection_op_history.begin();
3348 advance (it, selection_op_history_it);
3349 selection_op_history.erase (selection_op_history.begin(), it);
3351 selection_op_history.push_front (&_selection_memento->get_state ());
3352 selection_op_history_it = 0;
3355 if (selection_op_cmd_depth > 0) {
3356 selection_op_cmd_depth--;
3359 selection_undo_action->set_sensitive (true);
3360 selection_redo_action->set_sensitive (false);
3365 Editor::undo_selection_op ()
3368 selection_op_history_it++;
3370 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3371 if (n == selection_op_history_it) {
3372 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3373 selection_redo_action->set_sensitive (true);
3378 /* is there an earlier entry? */
3379 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3380 selection_undo_action->set_sensitive (false);
3386 Editor::redo_selection_op ()
3389 if (selection_op_history_it > 0) {
3390 selection_op_history_it--;
3393 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3394 if (n == selection_op_history_it) {
3395 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3396 selection_undo_action->set_sensitive (true);
3402 if (selection_op_history_it == 0) {
3403 selection_redo_action->set_sensitive (false);
3409 Editor::begin_reversible_command (string name)
3412 before.push_back (&_selection_memento->get_state ());
3413 _session->begin_reversible_command (name);
3418 Editor::begin_reversible_command (GQuark q)
3421 before.push_back (&_selection_memento->get_state ());
3422 _session->begin_reversible_command (q);
3427 Editor::commit_reversible_command ()
3430 if (before.size() == 1) {
3431 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3432 undo_action->set_sensitive(true);
3433 begin_selection_op_history ();
3436 if (before.empty()) {
3437 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3442 _session->commit_reversible_command ();
3447 Editor::history_changed ()
3451 if (undo_action && _session) {
3452 if (_session->undo_depth() == 0) {
3453 label = S_("Command|Undo");
3455 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3457 undo_action->property_label() = label;
3460 if (redo_action && _session) {
3461 if (_session->redo_depth() == 0) {
3464 label = string_compose(_("Redo (%1)"), _session->next_redo());
3466 redo_action->property_label() = label;
3471 Editor::duplicate_range (bool with_dialog)
3475 RegionSelection rs = get_regions_from_selection_and_entered ();
3477 if ( selection->time.length() == 0 && rs.empty()) {
3483 ArdourDialog win (_("Duplicate"));
3484 Label label (_("Number of duplications:"));
3485 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3486 SpinButton spinner (adjustment, 0.0, 1);
3489 win.get_vbox()->set_spacing (12);
3490 win.get_vbox()->pack_start (hbox);
3491 hbox.set_border_width (6);
3492 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3494 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3495 place, visually. so do this by hand.
3498 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3499 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3500 spinner.grab_focus();
3506 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3507 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3508 win.set_default_response (RESPONSE_ACCEPT);
3510 spinner.grab_focus ();
3512 switch (win.run ()) {
3513 case RESPONSE_ACCEPT:
3519 times = adjustment.get_value();
3522 if ((current_mouse_mode() == Editing::MouseRange)) {
3523 if (selection->time.length()) {
3524 duplicate_selection (times);
3526 } else if (get_smart_mode()) {
3527 if (selection->time.length()) {
3528 duplicate_selection (times);
3530 duplicate_some_regions (rs, times);
3532 duplicate_some_regions (rs, times);
3537 Editor::set_edit_mode (EditMode m)
3539 Config->set_edit_mode (m);
3543 Editor::cycle_edit_mode ()
3545 switch (Config->get_edit_mode()) {
3547 if (Profile->get_sae()) {
3548 Config->set_edit_mode (Lock);
3550 Config->set_edit_mode (Ripple);
3555 Config->set_edit_mode (Lock);
3558 Config->set_edit_mode (Slide);
3564 Editor::edit_mode_selection_done ( EditMode m )
3566 Config->set_edit_mode ( m );
3570 Editor::snap_type_selection_done (SnapType snaptype)
3572 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3574 ract->set_active ();
3579 Editor::snap_mode_selection_done (SnapMode mode)
3581 RefPtr<RadioAction> ract = snap_mode_action (mode);
3584 ract->set_active (true);
3589 Editor::cycle_edit_point (bool with_marker)
3591 if(Profile->get_mixbus())
3592 with_marker = false;
3594 switch (_edit_point) {
3596 set_edit_point_preference (EditAtPlayhead);
3598 case EditAtPlayhead:
3600 set_edit_point_preference (EditAtSelectedMarker);
3602 set_edit_point_preference (EditAtMouse);
3605 case EditAtSelectedMarker:
3606 set_edit_point_preference (EditAtMouse);
3612 Editor::edit_point_selection_done (EditPoint ep)
3614 set_edit_point_preference ( ep );
3618 Editor::build_zoom_focus_menu ()
3620 using namespace Menu_Helpers;
3622 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3623 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3624 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3625 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3626 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3627 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3629 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3633 Editor::zoom_focus_selection_done ( ZoomFocus f )
3635 RefPtr<RadioAction> ract = zoom_focus_action (f);
3637 ract->set_active ();
3642 Editor::build_track_count_menu ()
3644 using namespace Menu_Helpers;
3646 if (!Profile->get_mixbus()) {
3647 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3648 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3649 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3650 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3651 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3652 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3653 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3654 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3655 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3656 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3657 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3658 visible_tracks_selector.AddMenuElem (MenuElem (_("Selected"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3659 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3661 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3662 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3663 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3664 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3665 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3666 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3667 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3668 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3669 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3670 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selected tracks"), sigc::mem_fun(*this, &Editor::fit_selected_tracks)));
3672 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3673 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3674 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3675 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3676 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3677 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3678 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3679 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3680 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3681 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3682 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3687 Editor::set_zoom_preset (int64_t ms)
3690 temporal_zoom_session();
3694 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3695 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3699 Editor::set_visible_track_count (int32_t n)
3701 _visible_track_count = n;
3703 /* if the canvas hasn't really been allocated any size yet, just
3704 record the desired number of visible tracks and return. when canvas
3705 allocation happens, we will get called again and then we can do the
3709 if (_visible_canvas_height <= 1) {
3715 DisplaySuspender ds;
3717 if (_visible_track_count > 0) {
3718 h = trackviews_height() / _visible_track_count;
3719 std::ostringstream s;
3720 s << _visible_track_count;
3722 } else if (_visible_track_count == 0) {
3724 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3725 if ((*i)->marked_for_display()) {
3729 h = trackviews_height() / n;
3732 /* negative value means that the visible track count has
3733 been overridden by explicit track height changes.
3735 visible_tracks_selector.set_text (X_("*"));
3739 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3740 (*i)->set_height (h);
3743 if (str != visible_tracks_selector.get_text()) {
3744 visible_tracks_selector.set_text (str);
3749 Editor::override_visible_track_count ()
3751 _visible_track_count = -1;
3752 visible_tracks_selector.set_text ( _("*") );
3756 Editor::edit_controls_button_release (GdkEventButton* ev)
3758 if (Keyboard::is_context_menu_event (ev)) {
3759 ARDOUR_UI::instance()->add_route (this);
3760 } else if (ev->button == 1) {
3761 selection->clear_tracks ();
3768 Editor::mouse_select_button_release (GdkEventButton* ev)
3770 /* this handles just right-clicks */
3772 if (ev->button != 3) {
3780 Editor::set_zoom_focus (ZoomFocus f)
3782 string str = zoom_focus_strings[(int)f];
3784 if (str != zoom_focus_selector.get_text()) {
3785 zoom_focus_selector.set_text (str);
3788 if (zoom_focus != f) {
3795 Editor::cycle_zoom_focus ()
3797 switch (zoom_focus) {
3799 set_zoom_focus (ZoomFocusRight);
3801 case ZoomFocusRight:
3802 set_zoom_focus (ZoomFocusCenter);
3804 case ZoomFocusCenter:
3805 set_zoom_focus (ZoomFocusPlayhead);
3807 case ZoomFocusPlayhead:
3808 set_zoom_focus (ZoomFocusMouse);
3810 case ZoomFocusMouse:
3811 set_zoom_focus (ZoomFocusEdit);
3814 set_zoom_focus (ZoomFocusLeft);
3820 Editor::ensure_float (Window& win)
3822 win.set_transient_for (*this);
3826 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3828 /* recover or initialize pane positions. do this here rather than earlier because
3829 we don't want the positions to change the child allocations, which they seem to do.
3835 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3844 XMLNode* geometry = find_named_node (*node, "geometry");
3846 if (which == static_cast<Paned*> (&edit_pane)) {
3848 if (done & Horizontal) {
3852 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3853 _notebook_shrunk = string_is_affirmative (prop->value ());
3856 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3857 /* initial allocation is 90% to canvas, 10% to notebook */
3858 pos = (int) floor (alloc.get_width() * 0.90f);
3859 snprintf (buf, sizeof(buf), "%d", pos);
3861 pos = atoi (prop->value());
3864 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3865 edit_pane.set_position (pos);
3868 done = (Pane) (done | Horizontal);
3870 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3872 if (done & Vertical) {
3876 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3877 /* initial allocation is 90% to canvas, 10% to summary */
3878 pos = (int) floor (alloc.get_height() * 0.90f);
3879 snprintf (buf, sizeof(buf), "%d", pos);
3882 pos = atoi (prop->value());
3885 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3886 editor_summary_pane.set_position (pos);
3889 done = (Pane) (done | Vertical);
3894 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3896 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3897 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3898 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3899 top_hbox.remove (toolbar_frame);
3904 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3906 if (toolbar_frame.get_parent() == 0) {
3907 top_hbox.pack_end (toolbar_frame);
3912 Editor::set_show_measures (bool yn)
3914 if (_show_measures != yn) {
3917 if ((_show_measures = yn) == true) {
3919 tempo_lines->show();
3922 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3923 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3925 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3926 draw_measures (begin, end);
3934 Editor::toggle_follow_playhead ()
3936 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3938 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3939 set_follow_playhead (tact->get_active());
3943 /** @param yn true to follow playhead, otherwise false.
3944 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3947 Editor::set_follow_playhead (bool yn, bool catch_up)
3949 if (_follow_playhead != yn) {
3950 if ((_follow_playhead = yn) == true && catch_up) {
3952 reset_x_origin_to_follow_playhead ();
3959 Editor::toggle_stationary_playhead ()
3961 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3963 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3964 set_stationary_playhead (tact->get_active());
3969 Editor::set_stationary_playhead (bool yn)
3971 if (_stationary_playhead != yn) {
3972 if ((_stationary_playhead = yn) == true) {
3974 // FIXME need a 3.0 equivalent of this 2.X call
3975 // update_current_screen ();
3982 Editor::playlist_selector () const
3984 return *_playlist_selector;
3988 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
3990 if (paste_count == 0) {
3991 /* don't bother calculating an offset that will be zero anyway */
3995 /* calculate basic unsnapped multi-paste offset */
3996 framecnt_t offset = paste_count * duration;
3998 /* snap offset so pos + offset is aligned to the grid */
3999 framepos_t offset_pos = pos + offset;
4000 snap_to(offset_pos, RoundUpMaybe);
4001 offset = offset_pos - pos;
4007 Editor::get_grid_beat_divisions(framepos_t position)
4009 switch (_snap_type) {
4010 case SnapToBeatDiv128: return 128;
4011 case SnapToBeatDiv64: return 64;
4012 case SnapToBeatDiv32: return 32;
4013 case SnapToBeatDiv28: return 28;
4014 case SnapToBeatDiv24: return 24;
4015 case SnapToBeatDiv20: return 20;
4016 case SnapToBeatDiv16: return 16;
4017 case SnapToBeatDiv14: return 14;
4018 case SnapToBeatDiv12: return 12;
4019 case SnapToBeatDiv10: return 10;
4020 case SnapToBeatDiv8: return 8;
4021 case SnapToBeatDiv7: return 7;
4022 case SnapToBeatDiv6: return 6;
4023 case SnapToBeatDiv5: return 5;
4024 case SnapToBeatDiv4: return 4;
4025 case SnapToBeatDiv3: return 3;
4026 case SnapToBeatDiv2: return 2;
4033 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4037 const unsigned divisions = get_grid_beat_divisions(position);
4039 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4042 switch (_snap_type) {
4044 return Evoral::Beats(1.0);
4047 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4055 return Evoral::Beats();
4059 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4063 ret = nudge_clock->current_duration (pos);
4064 next = ret + 1; /* XXXX fix me */
4070 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4072 ArdourDialog dialog (_("Playlist Deletion"));
4073 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4074 "If it is kept, its audio files will not be cleaned.\n"
4075 "If it is deleted, audio files used by it alone will be cleaned."),
4078 dialog.set_position (WIN_POS_CENTER);
4079 dialog.get_vbox()->pack_start (label);
4083 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4084 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4085 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4087 switch (dialog.run ()) {
4088 case RESPONSE_ACCEPT:
4089 /* delete the playlist */
4093 case RESPONSE_REJECT:
4094 /* keep the playlist */
4106 Editor::audio_region_selection_covers (framepos_t where)
4108 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4109 if ((*a)->region()->covers (where)) {
4118 Editor::prepare_for_cleanup ()
4120 cut_buffer->clear_regions ();
4121 cut_buffer->clear_playlists ();
4123 selection->clear_regions ();
4124 selection->clear_playlists ();
4126 _regions->suspend_redisplay ();
4130 Editor::finish_cleanup ()
4132 _regions->resume_redisplay ();
4136 Editor::transport_loop_location()
4139 return _session->locations()->auto_loop_location();
4146 Editor::transport_punch_location()
4149 return _session->locations()->auto_punch_location();
4156 Editor::control_layout_scroll (GdkEventScroll* ev)
4158 /* Just forward to the normal canvas scroll method. The coordinate
4159 systems are different but since the canvas is always larger than the
4160 track headers, and aligned with the trackview area, this will work.
4162 In the not too distant future this layout is going away anyway and
4163 headers will be on the canvas.
4165 return canvas_scroll_event (ev, false);
4169 Editor::session_state_saved (string)
4172 _snapshots->redisplay ();
4176 Editor::update_tearoff_visibility()
4178 bool visible = ARDOUR_UI::config()->get_keep_tearoffs();
4179 _mouse_mode_tearoff->set_visible (visible);
4180 _tools_tearoff->set_visible (visible);
4181 if (_zoom_tearoff) {
4182 _zoom_tearoff->set_visible (visible);
4187 Editor::reattach_all_tearoffs ()
4189 if (_mouse_mode_tearoff) _mouse_mode_tearoff->put_it_back ();
4190 if (_tools_tearoff) _tools_tearoff->put_it_back ();
4191 if (_zoom_tearoff) _zoom_tearoff->put_it_back ();
4195 Editor::maximise_editing_space ()
4207 Editor::restore_editing_space ()
4219 * Make new playlists for a given track and also any others that belong
4220 * to the same active route group with the `select' property.
4225 Editor::new_playlists (TimeAxisView* v)
4227 begin_reversible_command (_("new playlists"));
4228 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4229 _session->playlists->get (playlists);
4230 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4231 commit_reversible_command ();
4235 * Use a copy of the current playlist for a given track and also any others that belong
4236 * to the same active route group with the `select' property.
4241 Editor::copy_playlists (TimeAxisView* v)
4243 begin_reversible_command (_("copy playlists"));
4244 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4245 _session->playlists->get (playlists);
4246 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4247 commit_reversible_command ();
4250 /** Clear the current playlist for a given track and also any others that belong
4251 * to the same active route group with the `select' property.
4256 Editor::clear_playlists (TimeAxisView* v)
4258 begin_reversible_command (_("clear playlists"));
4259 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4260 _session->playlists->get (playlists);
4261 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4262 commit_reversible_command ();
4266 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4268 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4272 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4274 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4278 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4280 atv.clear_playlist ();
4284 Editor::on_key_press_event (GdkEventKey* ev)
4286 return key_press_focus_accelerator_handler (*this, ev);
4290 Editor::on_key_release_event (GdkEventKey* ev)
4292 return Gtk::Window::on_key_release_event (ev);
4293 // return key_press_focus_accelerator_handler (*this, ev);
4297 Editor::get_y_origin () const
4299 return vertical_adjustment.get_value ();
4302 /** Queue up a change to the viewport x origin.
4303 * @param frame New x origin.
4306 Editor::reset_x_origin (framepos_t frame)
4308 pending_visual_change.add (VisualChange::TimeOrigin);
4309 pending_visual_change.time_origin = frame;
4310 ensure_visual_change_idle_handler ();
4314 Editor::reset_y_origin (double y)
4316 pending_visual_change.add (VisualChange::YOrigin);
4317 pending_visual_change.y_origin = y;
4318 ensure_visual_change_idle_handler ();
4322 Editor::reset_zoom (framecnt_t spp)
4324 if (spp == samples_per_pixel) {
4328 pending_visual_change.add (VisualChange::ZoomLevel);
4329 pending_visual_change.samples_per_pixel = spp;
4330 ensure_visual_change_idle_handler ();
4334 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4336 reset_x_origin (frame);
4339 if (!no_save_visual) {
4340 undo_visual_stack.push_back (current_visual_state(false));
4344 Editor::VisualState::VisualState (bool with_tracks)
4345 : gui_state (with_tracks ? new GUIObjectState : 0)
4349 Editor::VisualState::~VisualState ()
4354 Editor::VisualState*
4355 Editor::current_visual_state (bool with_tracks)
4357 VisualState* vs = new VisualState (with_tracks);
4358 vs->y_position = vertical_adjustment.get_value();
4359 vs->samples_per_pixel = samples_per_pixel;
4360 vs->leftmost_frame = leftmost_frame;
4361 vs->zoom_focus = zoom_focus;
4364 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4371 Editor::undo_visual_state ()
4373 if (undo_visual_stack.empty()) {
4377 VisualState* vs = undo_visual_stack.back();
4378 undo_visual_stack.pop_back();
4381 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4384 use_visual_state (*vs);
4389 Editor::redo_visual_state ()
4391 if (redo_visual_stack.empty()) {
4395 VisualState* vs = redo_visual_stack.back();
4396 redo_visual_stack.pop_back();
4398 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4399 // why do we check here?
4400 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4403 use_visual_state (*vs);
4408 Editor::swap_visual_state ()
4410 if (undo_visual_stack.empty()) {
4411 redo_visual_state ();
4413 undo_visual_state ();
4418 Editor::use_visual_state (VisualState& vs)
4420 PBD::Unwinder<bool> nsv (no_save_visual, true);
4421 DisplaySuspender ds;
4423 vertical_adjustment.set_value (vs.y_position);
4425 set_zoom_focus (vs.zoom_focus);
4426 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4429 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4431 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4432 (*i)->reset_visual_state ();
4436 _routes->update_visibility ();
4439 /** This is the core function that controls the zoom level of the canvas. It is called
4440 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4441 * @param spp new number of samples per pixel
4444 Editor::set_samples_per_pixel (framecnt_t spp)
4450 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4451 const framecnt_t lots_of_pixels = 4000;
4453 /* if the zoom level is greater than what you'd get trying to display 3
4454 * days of audio on a really big screen, then it's too big.
4457 if (spp * lots_of_pixels > three_days) {
4461 samples_per_pixel = spp;
4464 tempo_lines->tempo_map_changed();
4467 bool const showing_time_selection = selection->time.length() > 0;
4469 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4470 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4471 (*i)->reshow_selection (selection->time);
4475 ZoomChanged (); /* EMIT_SIGNAL */
4477 ArdourCanvas::GtkCanvasViewport* c;
4479 c = get_track_canvas();
4481 c->canvas()->zoomed ();
4484 if (playhead_cursor) {
4485 playhead_cursor->set_position (playhead_cursor->current_frame ());
4488 refresh_location_display();
4489 _summary->set_overlays_dirty ();
4491 update_marker_labels ();
4497 Editor::queue_visual_videotimeline_update ()
4500 * pending_visual_change.add (VisualChange::VideoTimeline);
4501 * or maybe even more specific: which videotimeline-image
4502 * currently it calls update_video_timeline() to update
4503 * _all outdated_ images on the video-timeline.
4504 * see 'exposeimg()' in video_image_frame.cc
4506 ensure_visual_change_idle_handler ();
4510 Editor::ensure_visual_change_idle_handler ()
4512 if (pending_visual_change.idle_handler_id < 0) {
4513 // see comment in add_to_idle_resize above.
4514 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4515 pending_visual_change.being_handled = false;
4520 Editor::_idle_visual_changer (void* arg)
4522 return static_cast<Editor*>(arg)->idle_visual_changer ();
4526 Editor::idle_visual_changer ()
4528 /* set_horizontal_position() below (and maybe other calls) call
4529 gtk_main_iteration(), so it's possible that a signal will be handled
4530 half-way through this method. If this signal wants an
4531 idle_visual_changer we must schedule another one after this one, so
4532 mark the idle_handler_id as -1 here to allow that. Also make a note
4533 that we are doing the visual change, so that changes in response to
4534 super-rapid-screen-update can be dropped if we are still processing
4538 pending_visual_change.idle_handler_id = -1;
4539 pending_visual_change.being_handled = true;
4541 VisualChange vc = pending_visual_change;
4543 pending_visual_change.pending = (VisualChange::Type) 0;
4545 visual_changer (vc);
4547 pending_visual_change.being_handled = false;
4549 return 0; /* this is always a one-shot call */
4553 Editor::visual_changer (const VisualChange& vc)
4555 double const last_time_origin = horizontal_position ();
4557 if (vc.pending & VisualChange::ZoomLevel) {
4558 set_samples_per_pixel (vc.samples_per_pixel);
4560 compute_fixed_ruler_scale ();
4562 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4563 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4565 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4566 current_bbt_points_begin, current_bbt_points_end);
4567 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4568 current_bbt_points_begin, current_bbt_points_end);
4569 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4571 update_video_timeline();
4574 if (vc.pending & VisualChange::TimeOrigin) {
4575 set_horizontal_position (vc.time_origin / samples_per_pixel);
4578 if (vc.pending & VisualChange::YOrigin) {
4579 vertical_adjustment.set_value (vc.y_origin);
4582 if (last_time_origin == horizontal_position ()) {
4583 /* changed signal not emitted */
4584 update_fixed_rulers ();
4585 redisplay_tempo (true);
4588 if (!(vc.pending & VisualChange::ZoomLevel)) {
4589 update_video_timeline();
4592 _summary->set_overlays_dirty ();
4595 struct EditorOrderTimeAxisSorter {
4596 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4597 return a->order () < b->order ();
4602 Editor::sort_track_selection (TrackViewList& sel)
4604 EditorOrderTimeAxisSorter cmp;
4609 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4612 framepos_t where = 0;
4613 EditPoint ep = _edit_point;
4615 if(Profile->get_mixbus())
4616 if (ep == EditAtSelectedMarker)
4619 if (from_context_menu && (ep == EditAtMouse)) {
4620 return canvas_event_sample (&context_click_event, 0, 0);
4623 if (entered_marker) {
4624 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4625 return entered_marker->position();
4628 if (ignore_playhead && ep == EditAtPlayhead) {
4629 ep = EditAtSelectedMarker;
4633 case EditAtPlayhead:
4634 where = _session->audible_frame();
4635 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4638 case EditAtSelectedMarker:
4639 if (!selection->markers.empty()) {
4641 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4644 where = loc->start();
4648 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4656 if (!mouse_frame (where, ignored)) {
4657 /* XXX not right but what can we do ? */
4661 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4669 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4671 if (!_session) return;
4673 begin_reversible_command (cmd);
4677 if ((tll = transport_loop_location()) == 0) {
4678 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4679 XMLNode &before = _session->locations()->get_state();
4680 _session->locations()->add (loc, true);
4681 _session->set_auto_loop_location (loc);
4682 XMLNode &after = _session->locations()->get_state();
4683 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4685 XMLNode &before = tll->get_state();
4686 tll->set_hidden (false, this);
4687 tll->set (start, end);
4688 XMLNode &after = tll->get_state();
4689 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4692 commit_reversible_command ();
4696 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4698 if (!_session) return;
4700 begin_reversible_command (cmd);
4704 if ((tpl = transport_punch_location()) == 0) {
4705 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4706 XMLNode &before = _session->locations()->get_state();
4707 _session->locations()->add (loc, true);
4708 _session->set_auto_punch_location (loc);
4709 XMLNode &after = _session->locations()->get_state();
4710 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4712 XMLNode &before = tpl->get_state();
4713 tpl->set_hidden (false, this);
4714 tpl->set (start, end);
4715 XMLNode &after = tpl->get_state();
4716 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4719 commit_reversible_command ();
4722 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4723 * @param rs List to which found regions are added.
4724 * @param where Time to look at.
4725 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4728 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4730 const TrackViewList* tracks;
4733 tracks = &track_views;
4738 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4740 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4743 boost::shared_ptr<Track> tr;
4744 boost::shared_ptr<Playlist> pl;
4746 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4748 boost::shared_ptr<RegionList> regions = pl->regions_at (
4749 (framepos_t) floor ( (double) where * tr->speed()));
4751 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4752 RegionView* rv = rtv->view()->find_view (*i);
4763 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4765 const TrackViewList* tracks;
4768 tracks = &track_views;
4773 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4774 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4776 boost::shared_ptr<Track> tr;
4777 boost::shared_ptr<Playlist> pl;
4779 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4781 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4782 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4784 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4786 RegionView* rv = rtv->view()->find_view (*i);
4797 /** Get regions using the following method:
4799 * Make a region list using:
4800 * (a) any selected regions
4801 * (b) the intersection of any selected tracks and the edit point(*)
4802 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4804 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4806 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4810 Editor::get_regions_from_selection_and_edit_point ()
4812 RegionSelection regions;
4814 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4815 regions.add (entered_regionview);
4817 regions = selection->regions;
4820 if ( regions.empty() ) {
4821 TrackViewList tracks = selection->tracks;
4823 if (!tracks.empty()) {
4824 /* no region selected or entered, but some selected tracks:
4825 * act on all regions on the selected tracks at the edit point
4827 framepos_t const where = get_preferred_edit_position ();
4828 get_regions_at(regions, where, tracks);
4835 /** Get regions using the following method:
4837 * Make a region list using:
4838 * (a) any selected regions
4839 * (b) the intersection of any selected tracks and the edit point(*)
4840 * (c) if neither exists, then whatever region is under the mouse
4842 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4844 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4847 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4849 RegionSelection regions;
4851 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4852 regions.add (entered_regionview);
4854 regions = selection->regions;
4857 if ( regions.empty() ) {
4858 TrackViewList tracks = selection->tracks;
4860 if (!tracks.empty()) {
4861 /* no region selected or entered, but some selected tracks:
4862 * act on all regions on the selected tracks at the edit point
4864 get_regions_at(regions, pos, tracks);
4871 /** Start with regions that are selected, or the entered regionview if none are selected.
4872 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4873 * of the regions that we started with.
4877 Editor::get_regions_from_selection_and_entered ()
4879 RegionSelection regions = selection->regions;
4881 if (regions.empty() && entered_regionview) {
4882 regions.add (entered_regionview);
4889 Editor::get_regionviews_by_id (PBD::ID const & id, RegionSelection & regions) const
4891 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4892 RouteTimeAxisView* tatv;
4894 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4895 boost::shared_ptr<Playlist> pl;
4896 std::vector<boost::shared_ptr<Region> > results;
4897 boost::shared_ptr<Track> tr;
4899 if ((tr = tatv->track()) == 0) {
4904 if ((pl = (tr->playlist())) != 0) {
4905 boost::shared_ptr<Region> r = pl->region_by_id (id);
4907 RegionView* marv = tatv->view()->find_view (r);
4909 regions.push_back (marv);
4918 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4920 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4922 RouteTimeAxisView* tatv;
4924 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4926 boost::shared_ptr<Playlist> pl;
4927 vector<boost::shared_ptr<Region> > results;
4929 boost::shared_ptr<Track> tr;
4931 if ((tr = tatv->track()) == 0) {
4936 if ((pl = (tr->playlist())) != 0) {
4937 if (src_comparison) {
4938 pl->get_source_equivalent_regions (region, results);
4940 pl->get_region_list_equivalent_regions (region, results);
4944 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4945 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4946 regions.push_back (marv);
4955 Editor::show_rhythm_ferret ()
4957 if (rhythm_ferret == 0) {
4958 rhythm_ferret = new RhythmFerret(*this);
4961 rhythm_ferret->set_session (_session);
4962 rhythm_ferret->show ();
4963 rhythm_ferret->present ();
4967 Editor::first_idle ()
4969 MessageDialog* dialog = 0;
4971 if (track_views.size() > 1) {
4972 dialog = new MessageDialog (
4974 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4978 ARDOUR_UI::instance()->flush_pending ();
4981 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4985 // first idle adds route children (automation tracks), so we need to redisplay here
4986 _routes->redisplay ();
4990 if (_session->undo_depth() == 0) {
4991 undo_action->set_sensitive(false);
4993 redo_action->set_sensitive(false);
4994 begin_selection_op_history ();
5000 Editor::_idle_resize (gpointer arg)
5002 return ((Editor*)arg)->idle_resize ();
5006 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5008 if (resize_idle_id < 0) {
5009 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5010 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5011 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5013 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5014 _pending_resize_amount = 0;
5017 /* make a note of the smallest resulting height, so that we can clamp the
5018 lower limit at TimeAxisView::hSmall */
5020 int32_t min_resulting = INT32_MAX;
5022 _pending_resize_amount += h;
5023 _pending_resize_view = view;
5025 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5027 if (selection->tracks.contains (_pending_resize_view)) {
5028 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5029 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5033 if (min_resulting < 0) {
5038 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5039 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5043 /** Handle pending resizing of tracks */
5045 Editor::idle_resize ()
5047 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5049 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5050 selection->tracks.contains (_pending_resize_view)) {
5052 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5053 if (*i != _pending_resize_view) {
5054 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5059 _pending_resize_amount = 0;
5060 _group_tabs->set_dirty ();
5061 resize_idle_id = -1;
5069 ENSURE_GUI_THREAD (*this, &Editor::located);
5072 playhead_cursor->set_position (_session->audible_frame ());
5073 if (_follow_playhead && !_pending_initial_locate) {
5074 reset_x_origin_to_follow_playhead ();
5078 _pending_locate_request = false;
5079 _pending_initial_locate = false;
5083 Editor::region_view_added (RegionView * rv)
5085 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5086 if (rv->region ()->id () == (*pr)) {
5087 selection->add (rv);
5088 selection->regions.pending.erase (pr);
5092 _summary->set_background_dirty ();
5096 Editor::region_view_removed ()
5098 _summary->set_background_dirty ();
5102 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5104 TrackViewList::const_iterator j = track_views.begin ();
5105 while (j != track_views.end()) {
5106 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5107 if (rtv && rtv->route() == r) {
5118 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5122 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5123 TimeAxisView* tv = axis_view_from_route (*i);
5133 Editor::suspend_route_redisplay ()
5136 _routes->suspend_redisplay();
5141 Editor::resume_route_redisplay ()
5144 _routes->resume_redisplay();
5149 Editor::add_routes (RouteList& routes)
5151 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5153 RouteTimeAxisView *rtv;
5154 list<RouteTimeAxisView*> new_views;
5156 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5157 boost::shared_ptr<Route> route = (*x);
5159 if (route->is_auditioner() || route->is_monitor()) {
5163 DataType dt = route->input()->default_type();
5165 if (dt == ARDOUR::DataType::AUDIO) {
5166 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5167 rtv->set_route (route);
5168 } else if (dt == ARDOUR::DataType::MIDI) {
5169 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5170 rtv->set_route (route);
5172 throw unknown_type();
5175 new_views.push_back (rtv);
5176 track_views.push_back (rtv);
5178 rtv->effective_gain_display ();
5180 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5181 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5184 if (new_views.size() > 0) {
5185 _routes->routes_added (new_views);
5186 _summary->routes_added (new_views);
5189 if (show_editor_mixer_when_tracks_arrive) {
5190 show_editor_mixer (true);
5193 editor_list_button.set_sensitive (true);
5197 Editor::timeaxisview_deleted (TimeAxisView *tv)
5199 if (tv == entered_track) {
5203 if (_session && _session->deletion_in_progress()) {
5204 /* the situation is under control */
5208 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5210 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5212 _routes->route_removed (tv);
5214 TimeAxisView::Children c = tv->get_child_list ();
5215 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5216 if (entered_track == i->get()) {
5221 /* remove it from the list of track views */
5223 TrackViewList::iterator i;
5225 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5226 i = track_views.erase (i);
5229 /* update whatever the current mixer strip is displaying, if revelant */
5231 boost::shared_ptr<Route> route;
5234 route = rtav->route ();
5237 if (current_mixer_strip && current_mixer_strip->route() == route) {
5239 TimeAxisView* next_tv;
5241 if (track_views.empty()) {
5243 } else if (i == track_views.end()) {
5244 next_tv = track_views.front();
5251 set_selected_mixer_strip (*next_tv);
5253 /* make the editor mixer strip go away setting the
5254 * button to inactive (which also unticks the menu option)
5257 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5263 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5265 if (apply_to_selection) {
5266 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5268 TrackSelection::iterator j = i;
5271 hide_track_in_display (*i, false);
5276 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5278 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5279 // this will hide the mixer strip
5280 set_selected_mixer_strip (*tv);
5283 _routes->hide_track_in_display (*tv);
5288 Editor::sync_track_view_list_and_routes ()
5290 track_views = TrackViewList (_routes->views ());
5292 _summary->set_dirty ();
5293 _group_tabs->set_dirty ();
5295 return false; // do not call again (until needed)
5299 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5301 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5306 /** Find a RouteTimeAxisView by the ID of its route */
5308 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5310 RouteTimeAxisView* v;
5312 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5313 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5314 if(v->route()->id() == id) {
5324 Editor::fit_route_group (RouteGroup *g)
5326 TrackViewList ts = axis_views_from_routes (g->route_list ());
5331 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5333 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5336 _session->cancel_audition ();
5340 if (_session->is_auditioning()) {
5341 _session->cancel_audition ();
5342 if (r == last_audition_region) {
5347 _session->audition_region (r);
5348 last_audition_region = r;
5353 Editor::hide_a_region (boost::shared_ptr<Region> r)
5355 r->set_hidden (true);
5359 Editor::show_a_region (boost::shared_ptr<Region> r)
5361 r->set_hidden (false);
5365 Editor::audition_region_from_region_list ()
5367 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5371 Editor::hide_region_from_region_list ()
5373 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5377 Editor::show_region_in_region_list ()
5379 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5383 Editor::step_edit_status_change (bool yn)
5386 start_step_editing ();
5388 stop_step_editing ();
5393 Editor::start_step_editing ()
5395 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5399 Editor::stop_step_editing ()
5401 step_edit_connection.disconnect ();
5405 Editor::check_step_edit ()
5407 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5408 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5410 mtv->check_step_edit ();
5414 return true; // do it again, till we stop
5418 Editor::scroll_press (Direction dir)
5420 ++_scroll_callbacks;
5422 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5423 /* delay the first auto-repeat */
5429 scroll_backward (1);
5437 scroll_up_one_track ();
5441 scroll_down_one_track ();
5445 /* do hacky auto-repeat */
5446 if (!_scroll_connection.connected ()) {
5448 _scroll_connection = Glib::signal_timeout().connect (
5449 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5452 _scroll_callbacks = 0;
5459 Editor::scroll_release ()
5461 _scroll_connection.disconnect ();
5464 /** Queue a change for the Editor viewport x origin to follow the playhead */
5466 Editor::reset_x_origin_to_follow_playhead ()
5468 framepos_t const frame = playhead_cursor->current_frame ();
5470 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5472 if (_session->transport_speed() < 0) {
5474 if (frame > (current_page_samples() / 2)) {
5475 center_screen (frame-(current_page_samples()/2));
5477 center_screen (current_page_samples()/2);
5484 if (frame < leftmost_frame) {
5486 if (_session->transport_rolling()) {
5487 /* rolling; end up with the playhead at the right of the page */
5488 l = frame - current_page_samples ();
5490 /* not rolling: end up with the playhead 1/4 of the way along the page */
5491 l = frame - current_page_samples() / 4;
5495 if (_session->transport_rolling()) {
5496 /* rolling: end up with the playhead on the left of the page */
5499 /* not rolling: end up with the playhead 3/4 of the way along the page */
5500 l = frame - 3 * current_page_samples() / 4;
5508 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5514 Editor::super_rapid_screen_update ()
5516 if (!_session || !_session->engine().running()) {
5520 /* METERING / MIXER STRIPS */
5522 /* update track meters, if required */
5523 if (is_mapped() && meters_running) {
5524 RouteTimeAxisView* rtv;
5525 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5526 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5527 rtv->fast_update ();
5532 /* and any current mixer strip */
5533 if (current_mixer_strip) {
5534 current_mixer_strip->fast_update ();
5537 /* PLAYHEAD AND VIEWPORT */
5539 framepos_t const frame = _session->audible_frame();
5541 /* There are a few reasons why we might not update the playhead / viewport stuff:
5543 * 1. we don't update things when there's a pending locate request, otherwise
5544 * when the editor requests a locate there is a chance that this method
5545 * will move the playhead before the locate request is processed, causing
5547 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5548 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5551 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5553 last_update_frame = frame;
5555 if (!_dragging_playhead) {
5556 playhead_cursor->set_position (frame);
5559 if (!_stationary_playhead) {
5561 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5562 /* We only do this if we aren't already
5563 handling a visual change (ie if
5564 pending_visual_change.being_handled is
5565 false) so that these requests don't stack
5566 up there are too many of them to handle in
5569 reset_x_origin_to_follow_playhead ();
5574 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5578 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5579 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5580 if (target <= 0.0) {
5583 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5584 target = (target * 0.15) + (current * 0.85);
5590 set_horizontal_position (current);
5599 Editor::session_going_away ()
5601 _have_idled = false;
5603 _session_connections.drop_connections ();
5605 super_rapid_screen_update_connection.disconnect ();
5607 selection->clear ();
5608 cut_buffer->clear ();
5610 clicked_regionview = 0;
5611 clicked_axisview = 0;
5612 clicked_routeview = 0;
5613 entered_regionview = 0;
5615 last_update_frame = 0;
5618 playhead_cursor->hide ();
5620 /* rip everything out of the list displays */
5624 _route_groups->clear ();
5626 /* do this first so that deleting a track doesn't reset cms to null
5627 and thus cause a leak.
5630 if (current_mixer_strip) {
5631 if (current_mixer_strip->get_parent() != 0) {
5632 global_hpacker.remove (*current_mixer_strip);
5634 delete current_mixer_strip;
5635 current_mixer_strip = 0;
5638 /* delete all trackviews */
5640 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5643 track_views.clear ();
5645 nudge_clock->set_session (0);
5647 editor_list_button.set_active(false);
5648 editor_list_button.set_sensitive(false);
5650 /* clear tempo/meter rulers */
5651 remove_metric_marks ();
5653 clear_marker_display ();
5655 stop_step_editing ();
5657 /* get rid of any existing editor mixer strip */
5659 WindowTitle title(Glib::get_application_name());
5660 title += _("Editor");
5662 set_title (title.get_string());
5664 SessionHandlePtr::session_going_away ();
5669 Editor::show_editor_list (bool yn)
5672 _the_notebook.show ();
5674 _the_notebook.hide ();
5679 Editor::change_region_layering_order (bool from_context_menu)
5681 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5683 if (!clicked_routeview) {
5684 if (layering_order_editor) {
5685 layering_order_editor->hide ();
5690 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5696 boost::shared_ptr<Playlist> pl = track->playlist();
5702 if (layering_order_editor == 0) {
5703 layering_order_editor = new RegionLayeringOrderEditor (*this);
5706 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5707 layering_order_editor->maybe_present ();
5711 Editor::update_region_layering_order_editor ()
5713 if (layering_order_editor && layering_order_editor->is_visible ()) {
5714 change_region_layering_order (true);
5719 Editor::setup_fade_images ()
5721 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5722 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5723 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5724 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5725 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5727 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5728 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5729 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5730 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5731 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5733 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5734 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5735 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5736 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5737 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5739 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5740 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5741 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5742 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5743 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5747 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5749 Editor::action_menu_item (std::string const & name)
5751 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5754 return *manage (a->create_menu_item ());
5758 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5760 EventBox* b = manage (new EventBox);
5761 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5762 Label* l = manage (new Label (name));
5766 _the_notebook.append_page (widget, *b);
5770 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5772 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5773 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5776 if (ev->type == GDK_2BUTTON_PRESS) {
5778 /* double-click on a notebook tab shrinks or expands the notebook */
5780 if (_notebook_shrunk) {
5781 if (pre_notebook_shrink_pane_width) {
5782 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5784 _notebook_shrunk = false;
5786 pre_notebook_shrink_pane_width = edit_pane.get_position();
5788 /* this expands the LHS of the edit pane to cover the notebook
5789 PAGE but leaves the tabs visible.
5791 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5792 _notebook_shrunk = true;
5800 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5802 using namespace Menu_Helpers;
5804 MenuList& items = _control_point_context_menu.items ();
5807 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5808 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5809 if (!can_remove_control_point (item)) {
5810 items.back().set_sensitive (false);
5813 _control_point_context_menu.popup (event->button.button, event->button.time);
5817 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5819 using namespace Menu_Helpers;
5821 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5826 /* We need to get the selection here and pass it to the operations, since
5827 popping up the menu will cause a region leave event which clears
5828 entered_regionview. */
5830 MidiRegionView& mrv = note->region_view();
5831 const RegionSelection rs = get_regions_from_selection_and_entered ();
5833 MenuList& items = _note_context_menu.items();
5836 items.push_back(MenuElem(_("Delete"),
5837 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5838 items.push_back(MenuElem(_("Edit..."),
5839 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5840 items.push_back(MenuElem(_("Legatize"),
5841 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5842 items.push_back(MenuElem(_("Quantize..."),
5843 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5844 items.push_back(MenuElem(_("Remove Overlap"),
5845 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5846 items.push_back(MenuElem(_("Transform..."),
5847 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5849 _note_context_menu.popup (event->button.button, event->button.time);
5853 Editor::zoom_vertical_modifier_released()
5855 _stepping_axis_view = 0;
5859 Editor::ui_parameter_changed (string parameter)
5861 if (parameter == "icon-set") {
5862 while (!_cursor_stack.empty()) {
5863 _cursor_stack.pop_back();
5865 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5866 _cursor_stack.push_back(_cursors->grabber);
5867 } else if (parameter == "draggable-playhead") {
5868 if (_verbose_cursor) {
5869 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());