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/keyboard.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/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route.h"
76 #include "ardour/route_group.h"
77 #include "ardour/session_playlists.h"
78 #include "ardour/tempo.h"
79 #include "ardour/utils.h"
80 #include "ardour/vca_manager.h"
81 #include "ardour/vca.h"
83 #include "canvas/debug.h"
84 #include "canvas/text.h"
86 #include "control_protocol/control_protocol.h"
89 #include "analysis_window.h"
90 #include "audio_clock.h"
91 #include "audio_region_view.h"
92 #include "audio_streamview.h"
93 #include "audio_time_axis.h"
94 #include "automation_time_axis.h"
95 #include "bundle_manager.h"
96 #include "crossfade_edit.h"
100 #include "editor_cursors.h"
101 #include "editor_drag.h"
102 #include "editor_group_tabs.h"
103 #include "editor_locations.h"
104 #include "editor_regions.h"
105 #include "editor_route_groups.h"
106 #include "editor_routes.h"
107 #include "editor_snapshots.h"
108 #include "editor_summary.h"
109 #include "export_report.h"
110 #include "global_port_matrix.h"
111 #include "gui_object.h"
112 #include "gui_thread.h"
113 #include "keyboard.h"
114 #include "keyeditor.h"
115 #include "luainstance.h"
117 #include "midi_region_view.h"
118 #include "midi_time_axis.h"
119 #include "mixer_strip.h"
120 #include "mixer_ui.h"
121 #include "mouse_cursors.h"
122 #include "note_base.h"
123 #include "playlist_selector.h"
124 #include "public_editor.h"
125 #include "quantize_dialog.h"
126 #include "region_layering_order_editor.h"
127 #include "rgb_macros.h"
128 #include "rhythm_ferret.h"
129 #include "route_sorter.h"
130 #include "selection.h"
131 #include "simple_progress_dialog.h"
133 #include "tempo_lines.h"
134 #include "time_axis_view.h"
136 #include "tooltips.h"
137 #include "ui_config.h"
139 #include "vca_time_axis.h"
140 #include "verbose_cursor.h"
145 using namespace ARDOUR;
146 using namespace ARDOUR_UI_UTILS;
149 using namespace Glib;
150 using namespace Gtkmm2ext;
151 using namespace Editing;
153 using PBD::internationalize;
155 using Gtkmm2ext::Keyboard;
157 double Editor::timebar_height = 15.0;
159 static const gchar *_snap_type_strings[] = {
193 static const gchar *_snap_mode_strings[] = {
200 static const gchar *_edit_point_strings[] = {
207 static const gchar *_edit_mode_strings[] = {
215 static const gchar *_zoom_focus_strings[] = {
225 #ifdef USE_RUBBERBAND
226 static const gchar *_rb_opt_strings[] = {
229 N_("Balanced multitimbral mixture"),
230 N_("Unpitched percussion with stable notes"),
231 N_("Crisp monophonic instrumental"),
232 N_("Unpitched solo percussion"),
233 N_("Resample without preserving pitch"),
238 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
241 : PublicEditor (global_hpacker)
242 , editor_mixer_strip_width (Wide)
243 , constructed (false)
244 , _playlist_selector (0)
245 , no_save_visual (false)
247 , samples_per_pixel (2048)
248 , zoom_focus (ZoomFocusPlayhead)
249 , mouse_mode (MouseObject)
250 , pre_internal_snap_type (SnapToBeat)
251 , pre_internal_snap_mode (SnapOff)
252 , internal_snap_type (SnapToBeat)
253 , internal_snap_mode (SnapOff)
254 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
255 , _notebook_shrunk (false)
256 , location_marker_color (0)
257 , location_range_color (0)
258 , location_loop_color (0)
259 , location_punch_color (0)
260 , location_cd_marker_color (0)
262 , _show_marker_lines (false)
263 , clicked_axisview (0)
264 , clicked_routeview (0)
265 , clicked_regionview (0)
266 , clicked_selection (0)
267 , clicked_control_point (0)
268 , button_release_can_deselect (true)
269 , _mouse_changed_selection (false)
270 , region_edit_menu_split_item (0)
271 , region_edit_menu_split_multichannel_item (0)
272 , track_region_edit_playlist_menu (0)
273 , track_edit_playlist_submenu (0)
274 , track_selection_edit_playlist_submenu (0)
275 , _popup_region_menu_item (0)
277 , _track_canvas_viewport (0)
278 , within_track_canvas (false)
279 , _verbose_cursor (0)
283 , range_marker_group (0)
284 , transport_marker_group (0)
285 , cd_marker_group (0)
286 , _time_markers_group (0)
287 , hv_scroll_group (0)
289 , cursor_scroll_group (0)
290 , no_scroll_group (0)
291 , _trackview_group (0)
292 , _drag_motion_group (0)
293 , _canvas_drop_zone (0)
294 , no_ruler_shown_update (false)
295 , ruler_grabbed_widget (0)
297 , minsec_mark_interval (0)
298 , minsec_mark_modulo (0)
300 , timecode_mark_modulo (0)
301 , timecode_nmarks (0)
302 , _samples_ruler_interval (0)
305 , bbt_bar_helper_on (0)
306 , bbt_accent_modulo (0)
311 , visible_timebars (0)
312 , editor_ruler_menu (0)
316 , range_marker_bar (0)
317 , transport_marker_bar (0)
319 , minsec_label (_("Mins:Secs"))
320 , bbt_label (_("Bars:Beats"))
321 , timecode_label (_("Timecode"))
322 , samples_label (_("Samples"))
323 , tempo_label (_("Tempo"))
324 , meter_label (_("Meter"))
325 , mark_label (_("Location Markers"))
326 , range_mark_label (_("Range Markers"))
327 , transport_mark_label (_("Loop/Punch Ranges"))
328 , cd_mark_label (_("CD Markers"))
329 , videotl_label (_("Video Timeline"))
331 , playhead_cursor (0)
332 , edit_packer (4, 4, true)
333 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
334 , horizontal_adjustment (0.0, 0.0, 1e16)
335 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
336 , controls_layout (unused_adjustment, vertical_adjustment)
337 , _scroll_callbacks (0)
338 , _visible_canvas_width (0)
339 , _visible_canvas_height (0)
340 , _full_canvas_height (0)
341 , edit_controls_left_menu (0)
342 , edit_controls_right_menu (0)
343 , last_update_frame (0)
344 , cut_buffer_start (0)
345 , cut_buffer_length (0)
346 , button_bindings (0)
350 , current_interthread_info (0)
351 , analysis_window (0)
352 , select_new_marker (false)
354 , scrubbing_direction (0)
355 , scrub_reversals (0)
356 , scrub_reverse_distance (0)
357 , have_pending_keyboard_selection (false)
358 , pending_keyboard_selection_start (0)
359 , _snap_type (SnapToBeat)
360 , _snap_mode (SnapOff)
361 , snap_threshold (5.0)
362 , ignore_gui_changes (false)
363 , _drags (new DragManager (this))
365 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
366 , _dragging_playhead (false)
367 , _dragging_edit_point (false)
368 , _show_measures (true)
369 , _follow_playhead (true)
370 , _stationary_playhead (false)
373 , global_rect_group (0)
374 , time_line_group (0)
375 , tempo_marker_menu (0)
376 , meter_marker_menu (0)
378 , range_marker_menu (0)
379 , transport_marker_menu (0)
380 , new_transport_marker_menu (0)
382 , marker_menu_item (0)
383 , bbt_beat_subdivision (4)
384 , _visible_track_count (-1)
385 , toolbar_selection_clock_table (2,3)
386 , automation_mode_button (_("mode"))
387 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
388 , selection (new Selection (this))
389 , cut_buffer (new Selection (this))
390 , _selection_memento (new SelectionMemento())
391 , _all_region_actions_sensitized (false)
392 , _ignore_region_action (false)
393 , _last_region_menu_was_main (false)
394 , _ignore_follow_edits (false)
395 , cd_marker_bar_drag_rect (0)
396 , range_bar_drag_rect (0)
397 , transport_bar_drag_rect (0)
398 , transport_bar_range_rect (0)
399 , transport_bar_preroll_rect (0)
400 , transport_bar_postroll_rect (0)
401 , transport_loop_range_rect (0)
402 , transport_punch_range_rect (0)
403 , transport_punchin_line (0)
404 , transport_punchout_line (0)
405 , transport_preroll_rect (0)
406 , transport_postroll_rect (0)
408 , rubberband_rect (0)
414 , autoscroll_horizontal_allowed (false)
415 , autoscroll_vertical_allowed (false)
417 , autoscroll_widget (0)
418 , show_gain_after_trim (false)
419 , selection_op_cmd_depth (0)
420 , selection_op_history_it (0)
421 , no_save_instant (false)
423 , current_mixer_strip (0)
424 , show_editor_mixer_when_tracks_arrive (false)
425 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
426 , current_stepping_trackview (0)
427 , last_track_height_step_timestamp (0)
429 , entered_regionview (0)
430 , clear_entered_track (false)
431 , _edit_point (EditAtMouse)
432 , meters_running (false)
434 , _have_idled (false)
435 , resize_idle_id (-1)
436 , _pending_resize_amount (0)
437 , _pending_resize_view (0)
438 , _pending_locate_request (false)
439 , _pending_initial_locate (false)
443 , layering_order_editor (0)
444 , _last_cut_copy_source_track (0)
445 , _region_selection_change_updates_region_list (true)
447 , _following_mixer_selection (false)
448 , _control_point_toggled_on_press (false)
449 , _stepping_axis_view (0)
450 , quantize_dialog (0)
451 , _main_menu_disabler (0)
452 , myactions (X_("editor"))
454 /* we are a singleton */
456 PublicEditor::_instance = this;
460 last_event_time.tv_sec = 0;
461 last_event_time.tv_usec = 0;
463 selection_op_history.clear();
466 snap_type_strings = I18N (_snap_type_strings);
467 snap_mode_strings = I18N (_snap_mode_strings);
468 zoom_focus_strings = I18N (_zoom_focus_strings);
469 edit_mode_strings = I18N (_edit_mode_strings);
470 edit_point_strings = I18N (_edit_point_strings);
471 #ifdef USE_RUBBERBAND
472 rb_opt_strings = I18N (_rb_opt_strings);
476 build_edit_mode_menu();
477 build_zoom_focus_menu();
478 build_track_count_menu();
479 build_snap_mode_menu();
480 build_snap_type_menu();
481 build_edit_point_menu();
483 location_marker_color = UIConfiguration::instance().color ("location marker");
484 location_range_color = UIConfiguration::instance().color ("location range");
485 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
486 location_loop_color = UIConfiguration::instance().color ("location loop");
487 location_punch_color = UIConfiguration::instance().color ("location punch");
489 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
491 TimeAxisView::setup_sizes ();
492 ArdourMarker::setup_sizes (timebar_height);
493 TempoCurve::setup_sizes (timebar_height);
495 bbt_label.set_name ("EditorRulerLabel");
496 bbt_label.set_size_request (-1, (int)timebar_height);
497 bbt_label.set_alignment (1.0, 0.5);
498 bbt_label.set_padding (5,0);
500 bbt_label.set_no_show_all();
501 minsec_label.set_name ("EditorRulerLabel");
502 minsec_label.set_size_request (-1, (int)timebar_height);
503 minsec_label.set_alignment (1.0, 0.5);
504 minsec_label.set_padding (5,0);
505 minsec_label.hide ();
506 minsec_label.set_no_show_all();
507 timecode_label.set_name ("EditorRulerLabel");
508 timecode_label.set_size_request (-1, (int)timebar_height);
509 timecode_label.set_alignment (1.0, 0.5);
510 timecode_label.set_padding (5,0);
511 timecode_label.hide ();
512 timecode_label.set_no_show_all();
513 samples_label.set_name ("EditorRulerLabel");
514 samples_label.set_size_request (-1, (int)timebar_height);
515 samples_label.set_alignment (1.0, 0.5);
516 samples_label.set_padding (5,0);
517 samples_label.hide ();
518 samples_label.set_no_show_all();
520 tempo_label.set_name ("EditorRulerLabel");
521 tempo_label.set_size_request (-1, (int)timebar_height);
522 tempo_label.set_alignment (1.0, 0.5);
523 tempo_label.set_padding (5,0);
525 tempo_label.set_no_show_all();
527 meter_label.set_name ("EditorRulerLabel");
528 meter_label.set_size_request (-1, (int)timebar_height);
529 meter_label.set_alignment (1.0, 0.5);
530 meter_label.set_padding (5,0);
532 meter_label.set_no_show_all();
534 if (Profile->get_trx()) {
535 mark_label.set_text (_("Markers"));
537 mark_label.set_name ("EditorRulerLabel");
538 mark_label.set_size_request (-1, (int)timebar_height);
539 mark_label.set_alignment (1.0, 0.5);
540 mark_label.set_padding (5,0);
542 mark_label.set_no_show_all();
544 cd_mark_label.set_name ("EditorRulerLabel");
545 cd_mark_label.set_size_request (-1, (int)timebar_height);
546 cd_mark_label.set_alignment (1.0, 0.5);
547 cd_mark_label.set_padding (5,0);
548 cd_mark_label.hide();
549 cd_mark_label.set_no_show_all();
551 videotl_bar_height = 4;
552 videotl_label.set_name ("EditorRulerLabel");
553 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
554 videotl_label.set_alignment (1.0, 0.5);
555 videotl_label.set_padding (5,0);
556 videotl_label.hide();
557 videotl_label.set_no_show_all();
559 range_mark_label.set_name ("EditorRulerLabel");
560 range_mark_label.set_size_request (-1, (int)timebar_height);
561 range_mark_label.set_alignment (1.0, 0.5);
562 range_mark_label.set_padding (5,0);
563 range_mark_label.hide();
564 range_mark_label.set_no_show_all();
566 transport_mark_label.set_name ("EditorRulerLabel");
567 transport_mark_label.set_size_request (-1, (int)timebar_height);
568 transport_mark_label.set_alignment (1.0, 0.5);
569 transport_mark_label.set_padding (5,0);
570 transport_mark_label.hide();
571 transport_mark_label.set_no_show_all();
573 initialize_canvas ();
575 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
577 _summary = new EditorSummary (this);
579 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
580 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
582 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
584 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
585 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
587 edit_controls_vbox.set_spacing (0);
588 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
589 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
591 HBox* h = manage (new HBox);
592 _group_tabs = new EditorGroupTabs (this);
593 if (!ARDOUR::Profile->get_trx()) {
594 h->pack_start (*_group_tabs, PACK_SHRINK);
596 h->pack_start (edit_controls_vbox);
597 controls_layout.add (*h);
599 controls_layout.set_name ("EditControlsBase");
600 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
601 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
602 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
604 _cursors = new MouseCursors;
605 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
606 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
608 /* Push default cursor to ever-present bottom of cursor stack. */
609 push_canvas_cursor(_cursors->grabber);
611 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
613 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
614 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
615 pad_line_1->set_outline_color (0xFF0000FF);
621 edit_packer.set_col_spacings (0);
622 edit_packer.set_row_spacings (0);
623 edit_packer.set_homogeneous (false);
624 edit_packer.set_border_width (0);
625 edit_packer.set_name ("EditorWindow");
627 time_bars_event_box.add (time_bars_vbox);
628 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
629 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
631 /* labels for the time bars */
632 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
634 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
636 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
638 bottom_hbox.set_border_width (2);
639 bottom_hbox.set_spacing (3);
641 _route_groups = new EditorRouteGroups (this);
642 _routes = new EditorRoutes (this);
643 _regions = new EditorRegions (this);
644 _snapshots = new EditorSnapshots (this);
645 _locations = new EditorLocations (this);
647 /* these are static location signals */
649 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
650 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
651 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
653 add_notebook_page (_("Regions"), _regions->widget ());
654 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
655 add_notebook_page (_("Snapshots"), _snapshots->widget ());
656 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
657 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
659 _the_notebook.set_show_tabs (true);
660 _the_notebook.set_scrollable (true);
661 _the_notebook.popup_disable ();
662 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
663 _the_notebook.show_all ();
665 _notebook_shrunk = false;
668 /* Pick up some settings we need to cache, early */
670 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
673 if (settings && (prop = settings->property ("notebook-shrunk"))) {
674 _notebook_shrunk = string_is_affirmative (prop->value ());
677 editor_summary_pane.set_check_divider_position (true);
678 editor_summary_pane.add (edit_packer);
680 Button* summary_arrows_left_left = manage (new Button);
681 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
682 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
683 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
685 Button* summary_arrows_left_right = manage (new Button);
686 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
687 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
688 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 VBox* summary_arrows_left = manage (new VBox);
691 summary_arrows_left->pack_start (*summary_arrows_left_left);
692 summary_arrows_left->pack_start (*summary_arrows_left_right);
694 Button* summary_arrows_right_up = manage (new Button);
695 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
696 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
697 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
699 Button* summary_arrows_right_down = manage (new Button);
700 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
701 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
702 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
704 VBox* summary_arrows_right = manage (new VBox);
705 summary_arrows_right->pack_start (*summary_arrows_right_up);
706 summary_arrows_right->pack_start (*summary_arrows_right_down);
708 Frame* summary_frame = manage (new Frame);
709 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
711 summary_frame->add (*_summary);
712 summary_frame->show ();
714 _summary_hbox.pack_start (*summary_arrows_left, false, false);
715 _summary_hbox.pack_start (*summary_frame, true, true);
716 _summary_hbox.pack_start (*summary_arrows_right, false, false);
718 if (!ARDOUR::Profile->get_trx()) {
719 editor_summary_pane.add (_summary_hbox);
722 edit_pane.set_check_divider_position (true);
723 edit_pane.add (editor_summary_pane);
724 if (!ARDOUR::Profile->get_trx()) {
725 edit_pane.add (_the_notebook);
728 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
729 edit_pane.set_child_minsize (_the_notebook, 30); /* rough guess at width of notebook tabs */
730 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
737 if (!settings || ((prop = settings->property ("edit-horizontal-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
738 /* initial allocation is 90% to canvas, 10% to notebook */
739 edit_pane.set_divider (0, 0.90);
741 edit_pane.set_divider (0, fract);
744 if (!settings || ((prop = settings->property ("edit-vertical-pane-pos")) == 0) || ((fract = atof (prop->value())) > 1.0)) {
745 /* initial allocation is 90% to canvas, 10% to summary */
746 editor_summary_pane.set_divider (0, 0.90);
749 editor_summary_pane.set_divider (0, fract);
753 top_hbox.pack_start (toolbar_frame);
755 HBox *hbox = manage (new HBox);
756 hbox->pack_start (edit_pane, true, true);
758 global_vpacker.pack_start (top_hbox, false, false);
759 global_vpacker.pack_start (*hbox, true, true);
760 global_hpacker.pack_start (global_vpacker, true, true);
762 /* need to show the "contents" widget so that notebook will show if tab is switched to
765 global_hpacker.show ();
767 /* register actions now so that set_state() can find them and set toggles/checks etc */
774 _playlist_selector = new PlaylistSelector();
775 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
777 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
781 nudge_forward_button.set_name ("nudge button");
782 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
784 nudge_backward_button.set_name ("nudge button");
785 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
787 fade_context_menu.set_name ("ArdourContextMenu");
789 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
791 /* allow external control surfaces/protocols to do various things */
793 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
794 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
795 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
796 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
797 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
798 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
799 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
800 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
801 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
802 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
803 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
804 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
805 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
806 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
808 ControlProtocol::AddStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
809 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
810 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
812 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
816 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
818 /* problematic: has to return a value and thus cannot be x-thread */
820 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
822 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
823 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
825 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
827 _ignore_region_action = false;
828 _last_region_menu_was_main = false;
829 _popup_region_menu_item = 0;
831 _ignore_follow_edits = false;
833 _show_marker_lines = false;
835 /* Button bindings */
837 button_bindings = new Bindings ("editor-mouse");
839 XMLNode* node = button_settings();
841 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
842 button_bindings->load_operation (**i);
848 /* grab current parameter state */
849 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
850 UIConfiguration::instance().map_parameters (pc);
852 setup_fade_images ();
854 LuaInstance::instance(); // instantiate
855 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
862 delete button_bindings;
864 delete _route_groups;
865 delete _track_canvas_viewport;
868 delete quantize_dialog;
874 delete _playlist_selector;
876 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
882 Editor::button_settings () const
884 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
885 XMLNode* node = find_named_node (*settings, X_("Buttons"));
888 node = new XMLNode (X_("Buttons"));
895 Editor::get_smart_mode () const
897 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
901 Editor::catch_vanishing_regionview (RegionView *rv)
903 /* note: the selection will take care of the vanishing
904 audioregionview by itself.
907 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
911 if (clicked_regionview == rv) {
912 clicked_regionview = 0;
915 if (entered_regionview == rv) {
916 set_entered_regionview (0);
919 if (!_all_region_actions_sensitized) {
920 sensitize_all_region_actions (true);
925 Editor::set_entered_regionview (RegionView* rv)
927 if (rv == entered_regionview) {
931 if (entered_regionview) {
932 entered_regionview->exited ();
935 entered_regionview = rv;
937 if (entered_regionview != 0) {
938 entered_regionview->entered ();
941 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
942 /* This RegionView entry might have changed what region actions
943 are allowed, so sensitize them all in case a key is pressed.
945 sensitize_all_region_actions (true);
950 Editor::set_entered_track (TimeAxisView* tav)
953 entered_track->exited ();
959 entered_track->entered ();
964 Editor::instant_save ()
966 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
971 _session->add_instant_xml(get_state());
973 Config->add_instant_xml(get_state());
978 Editor::control_vertical_zoom_in_all ()
980 tav_zoom_smooth (false, true);
984 Editor::control_vertical_zoom_out_all ()
986 tav_zoom_smooth (true, true);
990 Editor::control_vertical_zoom_in_selected ()
992 tav_zoom_smooth (false, false);
996 Editor::control_vertical_zoom_out_selected ()
998 tav_zoom_smooth (true, false);
1002 Editor::control_view (uint32_t view)
1004 goto_visual_state (view);
1008 Editor::control_unselect ()
1010 selection->clear_tracks ();
1014 Editor::control_select (PresentationInfo::order_t order, Selection::Operation op)
1016 /* handles the (static) signal from the ControlProtocol class that
1017 * requests setting the selected track to a given RID
1024 boost::shared_ptr<Stripable> s = _session->get_remote_nth_stripable (order, PresentationInfo::AllStripables);
1026 /* selected object may not be a Route */
1028 boost::shared_ptr<Route> r = boost::dynamic_pointer_cast<Route> (s);
1034 TimeAxisView* tav = axis_view_from_route (r);
1038 case Selection::Add:
1039 selection->add (tav);
1041 case Selection::Toggle:
1042 selection->toggle (tav);
1044 case Selection::Extend:
1046 case Selection::Set:
1047 selection->set (tav);
1051 selection->clear_tracks ();
1056 Editor::control_step_tracks_up ()
1058 scroll_tracks_up_line ();
1062 Editor::control_step_tracks_down ()
1064 scroll_tracks_down_line ();
1068 Editor::control_scroll (float fraction)
1070 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1076 double step = fraction * current_page_samples();
1079 _control_scroll_target is an optional<T>
1081 it acts like a pointer to an framepos_t, with
1082 a operator conversion to boolean to check
1083 that it has a value could possibly use
1084 playhead_cursor->current_frame to store the
1085 value and a boolean in the class to know
1086 when it's out of date
1089 if (!_control_scroll_target) {
1090 _control_scroll_target = _session->transport_frame();
1091 _dragging_playhead = true;
1094 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1095 *_control_scroll_target = 0;
1096 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1097 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1099 *_control_scroll_target += (framepos_t) trunc (step);
1102 /* move visuals, we'll catch up with it later */
1104 playhead_cursor->set_position (*_control_scroll_target);
1105 UpdateAllTransportClocks (*_control_scroll_target);
1107 if (*_control_scroll_target > (current_page_samples() / 2)) {
1108 /* try to center PH in window */
1109 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1115 Now we do a timeout to actually bring the session to the right place
1116 according to the playhead. This is to avoid reading disk buffers on every
1117 call to control_scroll, which is driven by ScrollTimeline and therefore
1118 probably by a control surface wheel which can generate lots of events.
1120 /* cancel the existing timeout */
1122 control_scroll_connection.disconnect ();
1124 /* add the next timeout */
1126 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1130 Editor::deferred_control_scroll (framepos_t /*target*/)
1132 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1133 // reset for next stream
1134 _control_scroll_target = boost::none;
1135 _dragging_playhead = false;
1140 Editor::access_action (std::string action_group, std::string action_item)
1146 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1149 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1157 Editor::on_realize ()
1161 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1162 start_lock_event_timing ();
1167 Editor::start_lock_event_timing ()
1169 /* check if we should lock the GUI every 30 seconds */
1171 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1175 Editor::generic_event_handler (GdkEvent* ev)
1178 case GDK_BUTTON_PRESS:
1179 case GDK_BUTTON_RELEASE:
1180 case GDK_MOTION_NOTIFY:
1182 case GDK_KEY_RELEASE:
1183 if (contents().is_mapped()) {
1184 gettimeofday (&last_event_time, 0);
1188 case GDK_LEAVE_NOTIFY:
1189 switch (ev->crossing.detail) {
1190 case GDK_NOTIFY_UNKNOWN:
1191 case GDK_NOTIFY_INFERIOR:
1192 case GDK_NOTIFY_ANCESTOR:
1194 case GDK_NOTIFY_VIRTUAL:
1195 case GDK_NOTIFY_NONLINEAR:
1196 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1197 /* leaving window, so reset focus, thus ending any and
1198 all text entry operations.
1200 reset_focus (&contents());
1213 Editor::lock_timeout_callback ()
1215 struct timeval now, delta;
1217 gettimeofday (&now, 0);
1219 timersub (&now, &last_event_time, &delta);
1221 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1223 /* don't call again. Returning false will effectively
1224 disconnect us from the timer callback.
1226 unlock() will call start_lock_event_timing() to get things
1236 Editor::map_position_change (framepos_t frame)
1238 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1240 if (_session == 0) {
1244 if (_follow_playhead) {
1245 center_screen (frame);
1248 playhead_cursor->set_position (frame);
1252 Editor::center_screen (framepos_t frame)
1254 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1256 /* if we're off the page, then scroll.
1259 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1260 center_screen_internal (frame, page);
1265 Editor::center_screen_internal (framepos_t frame, float page)
1270 frame -= (framepos_t) page;
1275 reset_x_origin (frame);
1280 Editor::update_title ()
1282 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1284 if (!own_window()) {
1289 bool dirty = _session->dirty();
1291 string session_name;
1293 if (_session->snap_name() != _session->name()) {
1294 session_name = _session->snap_name();
1296 session_name = _session->name();
1300 session_name = "*" + session_name;
1303 WindowTitle title(session_name);
1304 title += S_("Window|Editor");
1305 title += Glib::get_application_name();
1306 own_window()->set_title (title.get_string());
1308 /* ::session_going_away() will have taken care of it */
1313 Editor::set_session (Session *t)
1315 SessionHandlePtr::set_session (t);
1321 _playlist_selector->set_session (_session);
1322 nudge_clock->set_session (_session);
1323 _summary->set_session (_session);
1324 _group_tabs->set_session (_session);
1325 _route_groups->set_session (_session);
1326 _regions->set_session (_session);
1327 _snapshots->set_session (_session);
1328 _routes->set_session (_session);
1329 _locations->set_session (_session);
1331 if (rhythm_ferret) {
1332 rhythm_ferret->set_session (_session);
1335 if (analysis_window) {
1336 analysis_window->set_session (_session);
1340 sfbrowser->set_session (_session);
1343 compute_fixed_ruler_scale ();
1345 /* Make sure we have auto loop and auto punch ranges */
1347 Location* loc = _session->locations()->auto_loop_location();
1349 loc->set_name (_("Loop"));
1352 loc = _session->locations()->auto_punch_location();
1355 loc->set_name (_("Punch"));
1358 refresh_location_display ();
1360 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1361 the selected Marker; this needs the LocationMarker list to be available.
1363 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1364 set_state (*node, Stateful::loading_state_version);
1366 /* catch up with the playhead */
1368 _session->request_locate (playhead_cursor->current_frame ());
1369 _pending_initial_locate = true;
1373 /* These signals can all be emitted by a non-GUI thread. Therefore the
1374 handlers for them must not attempt to directly interact with the GUI,
1375 but use PBD::Signal<T>::connect() which accepts an event loop
1376 ("context") where the handler will be asked to run.
1379 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1380 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1381 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1382 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1383 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1384 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1385 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1386 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::marker_position_changed, this), gui_context());
1387 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1388 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1389 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1390 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1391 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1392 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1393 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1395 playhead_cursor->show ();
1397 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1398 Config->map_parameters (pc);
1399 _session->config.map_parameters (pc);
1401 restore_ruler_visibility ();
1402 //tempo_map_changed (PropertyChange (0));
1403 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1405 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1406 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1409 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1410 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1413 switch (_snap_type) {
1414 case SnapToRegionStart:
1415 case SnapToRegionEnd:
1416 case SnapToRegionSync:
1417 case SnapToRegionBoundary:
1418 build_region_boundary_cache ();
1425 /* register for undo history */
1426 _session->register_with_memento_command_factory(id(), this);
1427 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1429 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1431 LuaInstance::instance()->set_session(_session);
1433 start_updating_meters ();
1437 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1439 if (a->get_name() == "RegionMenu") {
1440 /* When the main menu's region menu is opened, we setup the actions so that they look right
1441 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1442 so we resensitize all region actions when the entered regionview or the region selection
1443 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1444 happens after the region context menu is opened. So we set a flag here, too.
1448 sensitize_the_right_region_actions ();
1449 _last_region_menu_was_main = true;
1454 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1456 using namespace Menu_Helpers;
1458 void (Editor::*emf)(FadeShape);
1459 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1462 images = &_xfade_in_images;
1463 emf = &Editor::set_fade_in_shape;
1465 images = &_xfade_out_images;
1466 emf = &Editor::set_fade_out_shape;
1471 _("Linear (for highly correlated material)"),
1472 *(*images)[FadeLinear],
1473 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1481 _("Constant power"),
1482 *(*images)[FadeConstantPower],
1483 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 *(*images)[FadeSymmetric],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *(*images)[FadeSlow],
1502 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 *(*images)[FadeFast],
1511 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1517 /** Pop up a context menu for when the user clicks on a start crossfade */
1519 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1521 using namespace Menu_Helpers;
1522 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1527 MenuList& items (xfade_in_context_menu.items());
1530 if (arv->audio_region()->fade_in_active()) {
1531 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1533 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1536 items.push_back (SeparatorElem());
1537 fill_xfade_menu (items, true);
1539 xfade_in_context_menu.popup (button, time);
1542 /** Pop up a context menu for when the user clicks on an end crossfade */
1544 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1546 using namespace Menu_Helpers;
1547 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1552 MenuList& items (xfade_out_context_menu.items());
1555 if (arv->audio_region()->fade_out_active()) {
1556 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1558 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1561 items.push_back (SeparatorElem());
1562 fill_xfade_menu (items, false);
1564 xfade_out_context_menu.popup (button, time);
1568 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1570 using namespace Menu_Helpers;
1571 Menu* (Editor::*build_menu_function)();
1574 switch (item_type) {
1576 case RegionViewName:
1577 case RegionViewNameHighlight:
1578 case LeftFrameHandle:
1579 case RightFrameHandle:
1580 if (with_selection) {
1581 build_menu_function = &Editor::build_track_selection_context_menu;
1583 build_menu_function = &Editor::build_track_region_context_menu;
1588 if (with_selection) {
1589 build_menu_function = &Editor::build_track_selection_context_menu;
1591 build_menu_function = &Editor::build_track_context_menu;
1596 if (clicked_routeview->track()) {
1597 build_menu_function = &Editor::build_track_context_menu;
1599 build_menu_function = &Editor::build_track_bus_context_menu;
1604 /* probably shouldn't happen but if it does, we don't care */
1608 menu = (this->*build_menu_function)();
1609 menu->set_name ("ArdourContextMenu");
1611 /* now handle specific situations */
1613 switch (item_type) {
1615 case RegionViewName:
1616 case RegionViewNameHighlight:
1617 case LeftFrameHandle:
1618 case RightFrameHandle:
1619 if (!with_selection) {
1620 if (region_edit_menu_split_item) {
1621 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1622 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1624 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1627 if (region_edit_menu_split_multichannel_item) {
1628 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1629 region_edit_menu_split_multichannel_item->set_sensitive (true);
1631 region_edit_menu_split_multichannel_item->set_sensitive (false);
1644 /* probably shouldn't happen but if it does, we don't care */
1648 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1650 /* Bounce to disk */
1652 using namespace Menu_Helpers;
1653 MenuList& edit_items = menu->items();
1655 edit_items.push_back (SeparatorElem());
1657 switch (clicked_routeview->audio_track()->freeze_state()) {
1658 case AudioTrack::NoFreeze:
1659 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1662 case AudioTrack::Frozen:
1663 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1666 case AudioTrack::UnFrozen:
1667 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1673 if (item_type == StreamItem && clicked_routeview) {
1674 clicked_routeview->build_underlay_menu(menu);
1677 /* When the region menu is opened, we setup the actions so that they look right
1680 sensitize_the_right_region_actions ();
1681 _last_region_menu_was_main = false;
1683 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1684 menu->popup (button, time);
1688 Editor::build_track_context_menu ()
1690 using namespace Menu_Helpers;
1692 MenuList& edit_items = track_context_menu.items();
1695 add_dstream_context_items (edit_items);
1696 return &track_context_menu;
1700 Editor::build_track_bus_context_menu ()
1702 using namespace Menu_Helpers;
1704 MenuList& edit_items = track_context_menu.items();
1707 add_bus_context_items (edit_items);
1708 return &track_context_menu;
1712 Editor::build_track_region_context_menu ()
1714 using namespace Menu_Helpers;
1715 MenuList& edit_items = track_region_context_menu.items();
1718 /* we've just cleared the track region context menu, so the menu that these
1719 two items were on will have disappeared; stop them dangling.
1721 region_edit_menu_split_item = 0;
1722 region_edit_menu_split_multichannel_item = 0;
1724 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1727 boost::shared_ptr<Track> tr;
1728 boost::shared_ptr<Playlist> pl;
1730 if ((tr = rtv->track())) {
1731 add_region_context_items (edit_items, tr);
1735 add_dstream_context_items (edit_items);
1737 return &track_region_context_menu;
1741 Editor::loudness_analyze_region_selection ()
1746 Selection& s (PublicEditor::instance ().get_selection ());
1747 RegionSelection ars = s.regions;
1748 ARDOUR::AnalysisGraph ag (_session);
1749 framecnt_t total_work = 0;
1751 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1752 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1756 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1759 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1760 total_work += arv->region ()->length ();
1763 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1765 ag.set_total_frames (total_work);
1766 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1769 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1770 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1774 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1778 ag.analyze_region (ar);
1781 if (!ag.canceled ()) {
1782 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1788 Editor::loudness_analyze_range_selection ()
1793 Selection& s (PublicEditor::instance ().get_selection ());
1794 TimeSelection ts = s.time;
1795 ARDOUR::AnalysisGraph ag (_session);
1796 framecnt_t total_work = 0;
1798 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1799 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1803 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1807 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1808 total_work += j->length ();
1812 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1814 ag.set_total_frames (total_work);
1815 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1818 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1819 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1823 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1827 ag.analyze_range (rui->route (), pl, ts);
1830 if (!ag.canceled ()) {
1831 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1837 Editor::spectral_analyze_region_selection ()
1839 if (analysis_window == 0) {
1840 analysis_window = new AnalysisWindow();
1843 analysis_window->set_session(_session);
1845 analysis_window->show_all();
1848 analysis_window->set_regionmode();
1849 analysis_window->analyze();
1851 analysis_window->present();
1855 Editor::spectral_analyze_range_selection()
1857 if (analysis_window == 0) {
1858 analysis_window = new AnalysisWindow();
1861 analysis_window->set_session(_session);
1863 analysis_window->show_all();
1866 analysis_window->set_rangemode();
1867 analysis_window->analyze();
1869 analysis_window->present();
1873 Editor::build_track_selection_context_menu ()
1875 using namespace Menu_Helpers;
1876 MenuList& edit_items = track_selection_context_menu.items();
1877 edit_items.clear ();
1879 add_selection_context_items (edit_items);
1880 // edit_items.push_back (SeparatorElem());
1881 // add_dstream_context_items (edit_items);
1883 return &track_selection_context_menu;
1887 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1889 using namespace Menu_Helpers;
1891 /* OK, stick the region submenu at the top of the list, and then add
1895 RegionSelection rs = get_regions_from_selection_and_entered ();
1897 string::size_type pos = 0;
1898 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1900 /* we have to hack up the region name because "_" has a special
1901 meaning for menu titles.
1904 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1905 menu_item_name.replace (pos, 1, "__");
1909 if (_popup_region_menu_item == 0) {
1910 _popup_region_menu_item = new MenuItem (menu_item_name);
1911 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1912 _popup_region_menu_item->show ();
1914 _popup_region_menu_item->set_label (menu_item_name);
1917 /* No latering allowed in later is higher layering model */
1918 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1919 if (act && Config->get_layer_model() == LaterHigher) {
1920 act->set_sensitive (false);
1922 act->set_sensitive (true);
1925 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1927 edit_items.push_back (*_popup_region_menu_item);
1928 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1929 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1931 edit_items.push_back (SeparatorElem());
1934 /** Add context menu items relevant to selection ranges.
1935 * @param edit_items List to add the items to.
1938 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1940 using namespace Menu_Helpers;
1942 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1943 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1945 edit_items.push_back (SeparatorElem());
1946 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1948 edit_items.push_back (SeparatorElem());
1949 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1950 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1952 edit_items.push_back (SeparatorElem());
1954 edit_items.push_back (
1956 _("Move Range Start to Previous Region Boundary"),
1957 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1961 edit_items.push_back (
1963 _("Move Range Start to Next Region Boundary"),
1964 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1968 edit_items.push_back (
1970 _("Move Range End to Previous Region Boundary"),
1971 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1975 edit_items.push_back (
1977 _("Move Range End to Next Region Boundary"),
1978 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1984 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1986 edit_items.push_back (SeparatorElem());
1987 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1989 edit_items.push_back (SeparatorElem());
1990 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1991 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1992 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1994 edit_items.push_back (SeparatorElem());
1995 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1997 edit_items.push_back (SeparatorElem());
1998 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1999 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
2001 edit_items.push_back (SeparatorElem());
2002 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2003 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2004 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2005 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2006 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2007 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2008 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2014 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2016 using namespace Menu_Helpers;
2020 Menu *play_menu = manage (new Menu);
2021 MenuList& play_items = play_menu->items();
2022 play_menu->set_name ("ArdourContextMenu");
2024 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2025 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2026 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2027 play_items.push_back (SeparatorElem());
2028 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2030 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2034 Menu *select_menu = manage (new Menu);
2035 MenuList& select_items = select_menu->items();
2036 select_menu->set_name ("ArdourContextMenu");
2038 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2039 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2040 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2041 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2042 select_items.push_back (SeparatorElem());
2043 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2044 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2045 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2046 select_items.push_back (SeparatorElem());
2047 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2048 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2049 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2050 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2051 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2052 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2053 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2055 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2059 Menu *cutnpaste_menu = manage (new Menu);
2060 MenuList& cutnpaste_items = cutnpaste_menu->items();
2061 cutnpaste_menu->set_name ("ArdourContextMenu");
2063 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2064 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2065 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2067 cutnpaste_items.push_back (SeparatorElem());
2069 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2070 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2072 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2074 /* Adding new material */
2076 edit_items.push_back (SeparatorElem());
2077 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2078 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2082 Menu *nudge_menu = manage (new Menu());
2083 MenuList& nudge_items = nudge_menu->items();
2084 nudge_menu->set_name ("ArdourContextMenu");
2086 edit_items.push_back (SeparatorElem());
2087 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2088 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2089 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2090 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2092 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2096 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2098 using namespace Menu_Helpers;
2102 Menu *play_menu = manage (new Menu);
2103 MenuList& play_items = play_menu->items();
2104 play_menu->set_name ("ArdourContextMenu");
2106 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2107 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2108 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2112 Menu *select_menu = manage (new Menu);
2113 MenuList& select_items = select_menu->items();
2114 select_menu->set_name ("ArdourContextMenu");
2116 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2117 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2118 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2119 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2120 select_items.push_back (SeparatorElem());
2121 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2122 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2123 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2124 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2126 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2130 Menu *cutnpaste_menu = manage (new Menu);
2131 MenuList& cutnpaste_items = cutnpaste_menu->items();
2132 cutnpaste_menu->set_name ("ArdourContextMenu");
2134 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2135 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2136 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2138 Menu *nudge_menu = manage (new Menu());
2139 MenuList& nudge_items = nudge_menu->items();
2140 nudge_menu->set_name ("ArdourContextMenu");
2142 edit_items.push_back (SeparatorElem());
2143 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2144 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2145 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2146 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2148 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2152 Editor::snap_type() const
2158 Editor::snap_musical() const
2160 switch (_snap_type) {
2161 case SnapToBeatDiv128:
2162 case SnapToBeatDiv64:
2163 case SnapToBeatDiv32:
2164 case SnapToBeatDiv28:
2165 case SnapToBeatDiv24:
2166 case SnapToBeatDiv20:
2167 case SnapToBeatDiv16:
2168 case SnapToBeatDiv14:
2169 case SnapToBeatDiv12:
2170 case SnapToBeatDiv10:
2171 case SnapToBeatDiv8:
2172 case SnapToBeatDiv7:
2173 case SnapToBeatDiv6:
2174 case SnapToBeatDiv5:
2175 case SnapToBeatDiv4:
2176 case SnapToBeatDiv3:
2177 case SnapToBeatDiv2:
2189 Editor::snap_mode() const
2195 Editor::set_snap_to (SnapType st)
2197 unsigned int snap_ind = (unsigned int)st;
2199 if (internal_editing()) {
2200 internal_snap_type = st;
2202 pre_internal_snap_type = st;
2207 if (snap_ind > snap_type_strings.size() - 1) {
2209 _snap_type = (SnapType)snap_ind;
2212 string str = snap_type_strings[snap_ind];
2214 if (str != snap_type_selector.get_text()) {
2215 snap_type_selector.set_text (str);
2220 switch (_snap_type) {
2221 case SnapToBeatDiv128:
2222 case SnapToBeatDiv64:
2223 case SnapToBeatDiv32:
2224 case SnapToBeatDiv28:
2225 case SnapToBeatDiv24:
2226 case SnapToBeatDiv20:
2227 case SnapToBeatDiv16:
2228 case SnapToBeatDiv14:
2229 case SnapToBeatDiv12:
2230 case SnapToBeatDiv10:
2231 case SnapToBeatDiv8:
2232 case SnapToBeatDiv7:
2233 case SnapToBeatDiv6:
2234 case SnapToBeatDiv5:
2235 case SnapToBeatDiv4:
2236 case SnapToBeatDiv3:
2237 case SnapToBeatDiv2: {
2238 std::vector<TempoMap::BBTPoint> grid;
2239 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2240 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2241 update_tempo_based_rulers (grid);
2245 case SnapToRegionStart:
2246 case SnapToRegionEnd:
2247 case SnapToRegionSync:
2248 case SnapToRegionBoundary:
2249 build_region_boundary_cache ();
2257 redisplay_tempo (false);
2259 SnapChanged (); /* EMIT SIGNAL */
2263 Editor::set_snap_mode (SnapMode mode)
2265 string str = snap_mode_strings[(int)mode];
2267 if (internal_editing()) {
2268 internal_snap_mode = mode;
2270 pre_internal_snap_mode = mode;
2275 if (str != snap_mode_selector.get_text ()) {
2276 snap_mode_selector.set_text (str);
2283 Editor::set_edit_point_preference (EditPoint ep, bool force)
2285 bool changed = (_edit_point != ep);
2288 if (Profile->get_mixbus())
2289 if (ep == EditAtSelectedMarker)
2290 ep = EditAtPlayhead;
2292 string str = edit_point_strings[(int)ep];
2293 if (str != edit_point_selector.get_text ()) {
2294 edit_point_selector.set_text (str);
2297 update_all_enter_cursors();
2299 if (!force && !changed) {
2303 const char* action=NULL;
2305 switch (_edit_point) {
2306 case EditAtPlayhead:
2307 action = "edit-at-playhead";
2309 case EditAtSelectedMarker:
2310 action = "edit-at-marker";
2313 action = "edit-at-mouse";
2317 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2319 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2323 bool in_track_canvas;
2325 if (!mouse_frame (foo, in_track_canvas)) {
2326 in_track_canvas = false;
2329 reset_canvas_action_sensitivity (in_track_canvas);
2335 Editor::set_state (const XMLNode& node, int version)
2337 XMLProperty const * prop;
2339 PBD::Unwinder<bool> nsi (no_save_instant, true);
2342 Tabbable::set_state (node, version);
2344 if (_session && (prop = node.property ("playhead"))) {
2346 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2348 playhead_cursor->set_position (pos);
2350 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2351 playhead_cursor->set_position (0);
2354 playhead_cursor->set_position (0);
2357 if ((prop = node.property ("mixer-width"))) {
2358 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2361 if ((prop = node.property ("zoom-focus"))) {
2362 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2364 zoom_focus_selection_done (zoom_focus);
2367 if ((prop = node.property ("zoom"))) {
2368 /* older versions of ardour used floating point samples_per_pixel */
2369 double f = PBD::atof (prop->value());
2370 reset_zoom (llrintf (f));
2372 reset_zoom (samples_per_pixel);
2375 if ((prop = node.property ("visible-track-count"))) {
2376 set_visible_track_count (PBD::atoi (prop->value()));
2379 if ((prop = node.property ("snap-to"))) {
2380 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2381 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2383 set_snap_to (_snap_type);
2386 if ((prop = node.property ("snap-mode"))) {
2387 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2388 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2389 * snap_mode_selection_done() will only mark an already active item as active
2390 * which does not trigger set_text().
2392 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2394 set_snap_mode (_snap_mode);
2397 if ((prop = node.property ("internal-snap-to"))) {
2398 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2401 if ((prop = node.property ("internal-snap-mode"))) {
2402 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2405 if ((prop = node.property ("pre-internal-snap-to"))) {
2406 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2409 if ((prop = node.property ("pre-internal-snap-mode"))) {
2410 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2413 if ((prop = node.property ("mouse-mode"))) {
2414 MouseMode m = str2mousemode(prop->value());
2415 set_mouse_mode (m, true);
2417 set_mouse_mode (MouseObject, true);
2420 if ((prop = node.property ("left-frame")) != 0) {
2422 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2426 reset_x_origin (pos);
2430 if ((prop = node.property ("y-origin")) != 0) {
2431 reset_y_origin (atof (prop->value ()));
2434 if ((prop = node.property ("join-object-range"))) {
2435 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2436 bool yn = string_is_affirmative (prop->value());
2438 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2439 tact->set_active (!yn);
2440 tact->set_active (yn);
2442 set_mouse_mode(mouse_mode, true);
2445 if ((prop = node.property ("edit-point"))) {
2446 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2448 set_edit_point_preference (_edit_point);
2451 if ((prop = node.property ("show-measures"))) {
2452 bool yn = string_is_affirmative (prop->value());
2453 _show_measures = yn;
2456 if ((prop = node.property ("follow-playhead"))) {
2457 bool yn = string_is_affirmative (prop->value());
2458 set_follow_playhead (yn);
2461 if ((prop = node.property ("stationary-playhead"))) {
2462 bool yn = string_is_affirmative (prop->value());
2463 set_stationary_playhead (yn);
2466 if ((prop = node.property ("region-list-sort-type"))) {
2467 RegionListSortType st;
2468 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2471 if ((prop = node.property ("show-editor-mixer"))) {
2473 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2476 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2477 bool yn = string_is_affirmative (prop->value());
2479 /* do it twice to force the change */
2481 tact->set_active (!yn);
2482 tact->set_active (yn);
2485 if ((prop = node.property ("show-editor-list"))) {
2487 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2490 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2491 bool yn = string_is_affirmative (prop->value());
2493 /* do it twice to force the change */
2495 tact->set_active (!yn);
2496 tact->set_active (yn);
2499 if ((prop = node.property (X_("editor-list-page")))) {
2500 _the_notebook.set_current_page (atoi (prop->value ()));
2503 if ((prop = node.property (X_("show-marker-lines")))) {
2504 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2506 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2507 bool yn = string_is_affirmative (prop->value ());
2509 tact->set_active (!yn);
2510 tact->set_active (yn);
2513 XMLNodeList children = node.children ();
2514 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2515 selection->set_state (**i, Stateful::current_state_version);
2516 _regions->set_state (**i);
2519 if ((prop = node.property ("maximised"))) {
2520 bool yn = string_is_affirmative (prop->value());
2521 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2523 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2524 bool fs = tact && tact->get_active();
2526 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2530 if ((prop = node.property ("nudge-clock-value"))) {
2532 sscanf (prop->value().c_str(), "%" PRId64, &f);
2533 nudge_clock->set (f);
2535 nudge_clock->set_mode (AudioClock::Timecode);
2536 nudge_clock->set (_session->frame_rate() * 5, true);
2541 * Not all properties may have been in XML, but
2542 * those that are linked to a private variable may need changing
2547 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2549 yn = _show_measures;
2550 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2551 /* do it twice to force the change */
2552 tact->set_active (!yn);
2553 tact->set_active (yn);
2556 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2557 yn = _follow_playhead;
2559 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2560 if (tact->get_active() != yn) {
2561 tact->set_active (yn);
2565 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2566 yn = _stationary_playhead;
2568 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2569 if (tact->get_active() != yn) {
2570 tact->set_active (yn);
2575 return LuaInstance::instance()->set_state(node);
2579 Editor::get_state ()
2581 XMLNode* node = new XMLNode (X_("Editor"));
2585 id().print (buf, sizeof (buf));
2586 node->add_property ("id", buf);
2588 node->add_child_nocopy (Tabbable::get_state());
2590 snprintf(buf,sizeof(buf), "%f", edit_pane.get_divider ());
2591 node->add_property("edit-horizontal-pane-pos", string(buf));
2592 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2593 snprintf(buf,sizeof(buf), "%f", editor_summary_pane.get_divider());
2594 node->add_property("edit-vertical-pane-pos", string(buf));
2596 maybe_add_mixer_strip_width (*node);
2598 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2600 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2601 node->add_property ("zoom", buf);
2602 node->add_property ("snap-to", enum_2_string (_snap_type));
2603 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2604 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2605 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2606 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2607 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2608 node->add_property ("edit-point", enum_2_string (_edit_point));
2609 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2610 node->add_property ("visible-track-count", buf);
2612 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2613 node->add_property ("playhead", buf);
2614 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2615 node->add_property ("left-frame", buf);
2616 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2617 node->add_property ("y-origin", buf);
2619 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2620 node->add_property ("maximised", _maximised ? "yes" : "no");
2621 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2622 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2623 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2624 node->add_property ("mouse-mode", enum2str(mouse_mode));
2625 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2627 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2629 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2630 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2633 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2635 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2636 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2639 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2640 node->add_property (X_("editor-list-page"), buf);
2642 if (button_bindings) {
2643 XMLNode* bb = new XMLNode (X_("Buttons"));
2644 button_bindings->save (*bb);
2645 node->add_child_nocopy (*bb);
2648 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2650 node->add_child_nocopy (selection->get_state ());
2651 node->add_child_nocopy (_regions->get_state ());
2653 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2654 node->add_property ("nudge-clock-value", buf);
2656 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2657 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2662 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2663 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2665 * @return pair: TimeAxisView that y is over, layer index.
2667 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2668 * in stacked or expanded region display mode, otherwise 0.
2670 std::pair<TimeAxisView *, double>
2671 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2673 if (!trackview_relative_offset) {
2674 y -= _trackview_group->canvas_origin().y;
2678 return std::make_pair ( (TimeAxisView *) 0, 0);
2681 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2683 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2690 return std::make_pair ( (TimeAxisView *) 0, 0);
2693 /** Snap a position to the grid, if appropriate, taking into account current
2694 * grid settings and also the state of any snap modifier keys that may be pressed.
2695 * @param start Position to snap.
2696 * @param event Event to get current key modifier information from, or 0.
2699 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2701 if (!_session || !event) {
2705 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2706 if (_snap_mode == SnapOff) {
2707 snap_to_internal (start, direction, for_mark);
2710 if (_snap_mode != SnapOff) {
2711 snap_to_internal (start, direction, for_mark);
2712 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2713 /* SnapOff, but we pressed the snap_delta modifier */
2714 snap_to_internal (start, direction, for_mark);
2720 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2722 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2726 snap_to_internal (start, direction, for_mark, ensure_snap);
2730 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2732 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2733 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2735 switch (_snap_type) {
2736 case SnapToTimecodeFrame:
2737 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2738 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2739 /* start is already on a whole timecode frame, do nothing */
2740 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2741 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2743 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2747 case SnapToTimecodeSeconds:
2748 if (_session->config.get_timecode_offset_negative()) {
2749 start += _session->config.get_timecode_offset ();
2751 start -= _session->config.get_timecode_offset ();
2753 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2754 (start % one_timecode_second == 0)) {
2755 /* start is already on a whole second, do nothing */
2756 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2757 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2759 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2762 if (_session->config.get_timecode_offset_negative()) {
2763 start -= _session->config.get_timecode_offset ();
2765 start += _session->config.get_timecode_offset ();
2769 case SnapToTimecodeMinutes:
2770 if (_session->config.get_timecode_offset_negative()) {
2771 start += _session->config.get_timecode_offset ();
2773 start -= _session->config.get_timecode_offset ();
2775 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2776 (start % one_timecode_minute == 0)) {
2777 /* start is already on a whole minute, do nothing */
2778 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2779 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2781 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2783 if (_session->config.get_timecode_offset_negative()) {
2784 start -= _session->config.get_timecode_offset ();
2786 start += _session->config.get_timecode_offset ();
2790 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2791 abort(); /*NOTREACHED*/
2796 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2798 const framepos_t one_second = _session->frame_rate();
2799 const framepos_t one_minute = _session->frame_rate() * 60;
2800 framepos_t presnap = start;
2804 switch (_snap_type) {
2805 case SnapToTimecodeFrame:
2806 case SnapToTimecodeSeconds:
2807 case SnapToTimecodeMinutes:
2808 return timecode_snap_to_internal (start, direction, for_mark);
2811 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2812 start % (one_second/75) == 0) {
2813 /* start is already on a whole CD frame, do nothing */
2814 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2815 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2817 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2822 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2823 start % one_second == 0) {
2824 /* start is already on a whole second, do nothing */
2825 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2826 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2828 start = (framepos_t) floor ((double) start / one_second) * one_second;
2833 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2834 start % one_minute == 0) {
2835 /* start is already on a whole minute, do nothing */
2836 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2837 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2839 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2844 start = _session->tempo_map().round_to_bar (start, direction);
2848 start = _session->tempo_map().round_to_beat (start, direction);
2851 case SnapToBeatDiv128:
2852 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2854 case SnapToBeatDiv64:
2855 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2857 case SnapToBeatDiv32:
2858 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2860 case SnapToBeatDiv28:
2861 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2863 case SnapToBeatDiv24:
2864 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2866 case SnapToBeatDiv20:
2867 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2869 case SnapToBeatDiv16:
2870 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2872 case SnapToBeatDiv14:
2873 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2875 case SnapToBeatDiv12:
2876 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2878 case SnapToBeatDiv10:
2879 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2881 case SnapToBeatDiv8:
2882 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2884 case SnapToBeatDiv7:
2885 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2887 case SnapToBeatDiv6:
2888 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2890 case SnapToBeatDiv5:
2891 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2893 case SnapToBeatDiv4:
2894 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2896 case SnapToBeatDiv3:
2897 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2899 case SnapToBeatDiv2:
2900 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2908 _session->locations()->marks_either_side (start, before, after);
2910 if (before == max_framepos && after == max_framepos) {
2911 /* No marks to snap to, so just don't snap */
2913 } else if (before == max_framepos) {
2915 } else if (after == max_framepos) {
2917 } else if (before != max_framepos && after != max_framepos) {
2918 /* have before and after */
2919 if ((start - before) < (after - start)) {
2928 case SnapToRegionStart:
2929 case SnapToRegionEnd:
2930 case SnapToRegionSync:
2931 case SnapToRegionBoundary:
2932 if (!region_boundary_cache.empty()) {
2934 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2935 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2937 if (direction > 0) {
2938 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2940 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2943 if (next != region_boundary_cache.begin ()) {
2948 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2949 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2951 if (start > (p + n) / 2) {
2960 switch (_snap_mode) {
2970 if (presnap > start) {
2971 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2975 } else if (presnap < start) {
2976 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2982 /* handled at entry */
2990 Editor::setup_toolbar ()
2992 HBox* mode_box = manage(new HBox);
2993 mode_box->set_border_width (2);
2994 mode_box->set_spacing(2);
2996 HBox* mouse_mode_box = manage (new HBox);
2997 HBox* mouse_mode_hbox = manage (new HBox);
2998 VBox* mouse_mode_vbox = manage (new VBox);
2999 Alignment* mouse_mode_align = manage (new Alignment);
3001 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3002 mouse_mode_size_group->add_widget (smart_mode_button);
3003 mouse_mode_size_group->add_widget (mouse_move_button);
3004 mouse_mode_size_group->add_widget (mouse_cut_button);
3005 mouse_mode_size_group->add_widget (mouse_select_button);
3006 mouse_mode_size_group->add_widget (mouse_timefx_button);
3007 mouse_mode_size_group->add_widget (mouse_audition_button);
3008 mouse_mode_size_group->add_widget (mouse_draw_button);
3009 mouse_mode_size_group->add_widget (mouse_content_button);
3011 mouse_mode_size_group->add_widget (zoom_in_button);
3012 mouse_mode_size_group->add_widget (zoom_out_button);
3013 mouse_mode_size_group->add_widget (zoom_preset_selector);
3014 mouse_mode_size_group->add_widget (zoom_out_full_button);
3015 mouse_mode_size_group->add_widget (zoom_focus_selector);
3017 mouse_mode_size_group->add_widget (tav_shrink_button);
3018 mouse_mode_size_group->add_widget (tav_expand_button);
3019 mouse_mode_size_group->add_widget (visible_tracks_selector);
3021 mouse_mode_size_group->add_widget (snap_type_selector);
3022 mouse_mode_size_group->add_widget (snap_mode_selector);
3024 mouse_mode_size_group->add_widget (edit_point_selector);
3025 mouse_mode_size_group->add_widget (edit_mode_selector);
3027 mouse_mode_size_group->add_widget (*nudge_clock);
3028 mouse_mode_size_group->add_widget (nudge_forward_button);
3029 mouse_mode_size_group->add_widget (nudge_backward_button);
3031 mouse_mode_hbox->set_spacing (2);
3033 if (!ARDOUR::Profile->get_trx()) {
3034 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3037 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3038 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3040 if (!ARDOUR::Profile->get_mixbus()) {
3041 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3044 if (!ARDOUR::Profile->get_trx()) {
3045 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3046 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3047 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3048 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3051 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3053 mouse_mode_align->add (*mouse_mode_vbox);
3054 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3056 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3058 edit_mode_selector.set_name ("mouse mode button");
3060 if (!ARDOUR::Profile->get_trx()) {
3061 mode_box->pack_start (edit_mode_selector, false, false);
3064 mode_box->pack_start (*mouse_mode_box, false, false);
3068 _zoom_box.set_spacing (2);
3069 _zoom_box.set_border_width (2);
3073 zoom_preset_selector.set_name ("zoom button");
3074 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3075 zoom_preset_selector.set_size_request (42, -1);
3077 zoom_in_button.set_name ("zoom button");
3078 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3079 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3080 zoom_in_button.set_related_action (act);
3082 zoom_out_button.set_name ("zoom button");
3083 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3084 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3085 zoom_out_button.set_related_action (act);
3087 zoom_out_full_button.set_name ("zoom button");
3088 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3089 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3090 zoom_out_full_button.set_related_action (act);
3092 zoom_focus_selector.set_name ("zoom button");
3094 if (ARDOUR::Profile->get_mixbus()) {
3095 _zoom_box.pack_start (zoom_preset_selector, false, false);
3096 } else if (ARDOUR::Profile->get_trx()) {
3097 mode_box->pack_start (zoom_out_button, false, false);
3098 mode_box->pack_start (zoom_in_button, false, false);
3100 _zoom_box.pack_start (zoom_out_button, false, false);
3101 _zoom_box.pack_start (zoom_in_button, false, false);
3102 _zoom_box.pack_start (zoom_out_full_button, false, false);
3103 _zoom_box.pack_start (zoom_focus_selector, false, false);
3106 /* Track zoom buttons */
3107 visible_tracks_selector.set_name ("zoom button");
3108 if (Profile->get_mixbus()) {
3109 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3110 visible_tracks_selector.set_size_request (42, -1);
3112 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3115 tav_expand_button.set_name ("zoom button");
3116 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3117 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3118 tav_expand_button.set_related_action (act);
3120 tav_shrink_button.set_name ("zoom button");
3121 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3122 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3123 tav_shrink_button.set_related_action (act);
3125 if (ARDOUR::Profile->get_mixbus()) {
3126 _zoom_box.pack_start (visible_tracks_selector);
3127 } else if (ARDOUR::Profile->get_trx()) {
3128 _zoom_box.pack_start (tav_shrink_button);
3129 _zoom_box.pack_start (tav_expand_button);
3131 _zoom_box.pack_start (visible_tracks_selector);
3132 _zoom_box.pack_start (tav_shrink_button);
3133 _zoom_box.pack_start (tav_expand_button);
3136 snap_box.set_spacing (2);
3137 snap_box.set_border_width (2);
3139 snap_type_selector.set_name ("mouse mode button");
3141 snap_mode_selector.set_name ("mouse mode button");
3143 edit_point_selector.set_name ("mouse mode button");
3145 snap_box.pack_start (snap_mode_selector, false, false);
3146 snap_box.pack_start (snap_type_selector, false, false);
3147 snap_box.pack_start (edit_point_selector, false, false);
3151 HBox *nudge_box = manage (new HBox);
3152 nudge_box->set_spacing (2);
3153 nudge_box->set_border_width (2);
3155 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3156 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3158 nudge_box->pack_start (nudge_backward_button, false, false);
3159 nudge_box->pack_start (nudge_forward_button, false, false);
3160 nudge_box->pack_start (*nudge_clock, false, false);
3163 /* Pack everything in... */
3165 HBox* hbox = manage (new HBox);
3166 hbox->set_spacing(2);
3168 toolbar_hbox.set_spacing (2);
3169 toolbar_hbox.set_border_width (1);
3171 toolbar_hbox.pack_start (*mode_box, false, false);
3172 if (!ARDOUR::Profile->get_trx()) {
3173 toolbar_hbox.pack_start (_zoom_box, false, false);
3174 toolbar_hbox.pack_start (*hbox, false, false);
3177 if (!ARDOUR::Profile->get_trx()) {
3178 hbox->pack_start (snap_box, false, false);
3179 hbox->pack_start (*nudge_box, false, false);
3184 toolbar_base.set_name ("ToolBarBase");
3185 toolbar_base.add (toolbar_hbox);
3187 _toolbar_viewport.add (toolbar_base);
3188 /* stick to the required height but allow width to vary if there's not enough room */
3189 _toolbar_viewport.set_size_request (1, -1);
3191 toolbar_frame.set_shadow_type (SHADOW_OUT);
3192 toolbar_frame.set_name ("BaseFrame");
3193 toolbar_frame.add (_toolbar_viewport);
3197 Editor::build_edit_point_menu ()
3199 using namespace Menu_Helpers;
3201 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3202 if(!Profile->get_mixbus())
3203 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3204 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3206 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3210 Editor::build_edit_mode_menu ()
3212 using namespace Menu_Helpers;
3214 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3215 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3216 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3217 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3219 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3223 Editor::build_snap_mode_menu ()
3225 using namespace Menu_Helpers;
3227 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3228 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3229 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3231 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3235 Editor::build_snap_type_menu ()
3237 using namespace Menu_Helpers;
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3266 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3267 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3268 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3270 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3275 Editor::setup_tooltips ()
3277 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3278 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3279 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3280 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3281 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3282 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3283 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3284 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3285 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3286 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3287 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3288 set_tooltip (zoom_in_button, _("Zoom In"));
3289 set_tooltip (zoom_out_button, _("Zoom Out"));
3290 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3291 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3292 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3293 set_tooltip (tav_expand_button, _("Expand Tracks"));
3294 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3295 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3296 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3297 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3298 set_tooltip (edit_point_selector, _("Edit Point"));
3299 set_tooltip (edit_mode_selector, _("Edit Mode"));
3300 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3304 Editor::convert_drop_to_paths (
3305 vector<string>& paths,
3306 const RefPtr<Gdk::DragContext>& /*context*/,
3309 const SelectionData& data,
3313 if (_session == 0) {
3317 vector<string> uris = data.get_uris();
3321 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3322 are actually URI lists. So do it by hand.
3325 if (data.get_target() != "text/plain") {
3329 /* Parse the "uri-list" format that Nautilus provides,
3330 where each pathname is delimited by \r\n.
3332 THERE MAY BE NO NULL TERMINATING CHAR!!!
3335 string txt = data.get_text();
3339 p = (char *) malloc (txt.length() + 1);
3340 txt.copy (p, txt.length(), 0);
3341 p[txt.length()] = '\0';
3347 while (g_ascii_isspace (*p))
3351 while (*q && (*q != '\n') && (*q != '\r')) {
3358 while (q > p && g_ascii_isspace (*q))
3363 uris.push_back (string (p, q - p + 1));
3367 p = strchr (p, '\n');
3379 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3380 if ((*i).substr (0,7) == "file://") {
3381 paths.push_back (Glib::filename_from_uri (*i));
3389 Editor::new_tempo_section ()
3394 Editor::map_transport_state ()
3396 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3398 if (_session && _session->transport_stopped()) {
3399 have_pending_keyboard_selection = false;
3402 update_loop_range_view ();
3408 Editor::begin_selection_op_history ()
3410 selection_op_cmd_depth = 0;
3411 selection_op_history_it = 0;
3413 while(!selection_op_history.empty()) {
3414 delete selection_op_history.front();
3415 selection_op_history.pop_front();
3418 selection_undo_action->set_sensitive (false);
3419 selection_redo_action->set_sensitive (false);
3420 selection_op_history.push_front (&_selection_memento->get_state ());
3424 Editor::begin_reversible_selection_op (string name)
3427 //cerr << name << endl;
3428 /* begin/commit pairs can be nested */
3429 selection_op_cmd_depth++;
3434 Editor::commit_reversible_selection_op ()
3437 if (selection_op_cmd_depth == 1) {
3439 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3441 The user has undone some selection ops and then made a new one,
3442 making anything earlier in the list invalid.
3445 list<XMLNode *>::iterator it = selection_op_history.begin();
3446 list<XMLNode *>::iterator e_it = it;
3447 advance (e_it, selection_op_history_it);
3449 for ( ; it != e_it; ++it) {
3452 selection_op_history.erase (selection_op_history.begin(), e_it);
3455 selection_op_history.push_front (&_selection_memento->get_state ());
3456 selection_op_history_it = 0;
3458 selection_undo_action->set_sensitive (true);
3459 selection_redo_action->set_sensitive (false);
3462 if (selection_op_cmd_depth > 0) {
3463 selection_op_cmd_depth--;
3469 Editor::undo_selection_op ()
3472 selection_op_history_it++;
3474 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3475 if (n == selection_op_history_it) {
3476 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3477 selection_redo_action->set_sensitive (true);
3481 /* is there an earlier entry? */
3482 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3483 selection_undo_action->set_sensitive (false);
3489 Editor::redo_selection_op ()
3492 if (selection_op_history_it > 0) {
3493 selection_op_history_it--;
3496 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3497 if (n == selection_op_history_it) {
3498 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3499 selection_undo_action->set_sensitive (true);
3504 if (selection_op_history_it == 0) {
3505 selection_redo_action->set_sensitive (false);
3511 Editor::begin_reversible_command (string name)
3514 before.push_back (&_selection_memento->get_state ());
3515 _session->begin_reversible_command (name);
3520 Editor::begin_reversible_command (GQuark q)
3523 before.push_back (&_selection_memento->get_state ());
3524 _session->begin_reversible_command (q);
3529 Editor::abort_reversible_command ()
3532 while(!before.empty()) {
3533 delete before.front();
3536 _session->abort_reversible_command ();
3541 Editor::commit_reversible_command ()
3544 if (before.size() == 1) {
3545 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3546 redo_action->set_sensitive(false);
3547 undo_action->set_sensitive(true);
3548 begin_selection_op_history ();
3551 if (before.empty()) {
3552 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3557 _session->commit_reversible_command ();
3562 Editor::history_changed ()
3566 if (undo_action && _session) {
3567 if (_session->undo_depth() == 0) {
3568 label = S_("Command|Undo");
3570 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3572 undo_action->property_label() = label;
3575 if (redo_action && _session) {
3576 if (_session->redo_depth() == 0) {
3578 redo_action->set_sensitive (false);
3580 label = string_compose(_("Redo (%1)"), _session->next_redo());
3581 redo_action->set_sensitive (true);
3583 redo_action->property_label() = label;
3588 Editor::duplicate_range (bool with_dialog)
3592 RegionSelection rs = get_regions_from_selection_and_entered ();
3594 if ( selection->time.length() == 0 && rs.empty()) {
3600 ArdourDialog win (_("Duplicate"));
3601 Label label (_("Number of duplications:"));
3602 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3603 SpinButton spinner (adjustment, 0.0, 1);
3606 win.get_vbox()->set_spacing (12);
3607 win.get_vbox()->pack_start (hbox);
3608 hbox.set_border_width (6);
3609 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3611 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3612 place, visually. so do this by hand.
3615 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3616 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3617 spinner.grab_focus();
3623 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3624 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3625 win.set_default_response (RESPONSE_ACCEPT);
3627 spinner.grab_focus ();
3629 switch (win.run ()) {
3630 case RESPONSE_ACCEPT:
3636 times = adjustment.get_value();
3639 if ((current_mouse_mode() == Editing::MouseRange)) {
3640 if (selection->time.length()) {
3641 duplicate_selection (times);
3643 } else if (get_smart_mode()) {
3644 if (selection->time.length()) {
3645 duplicate_selection (times);
3647 duplicate_some_regions (rs, times);
3649 duplicate_some_regions (rs, times);
3654 Editor::set_edit_mode (EditMode m)
3656 Config->set_edit_mode (m);
3660 Editor::cycle_edit_mode ()
3662 switch (Config->get_edit_mode()) {
3664 Config->set_edit_mode (Ripple);
3668 Config->set_edit_mode (Lock);
3671 Config->set_edit_mode (Slide);
3677 Editor::edit_mode_selection_done ( EditMode m )
3679 Config->set_edit_mode ( m );
3683 Editor::snap_type_selection_done (SnapType snaptype)
3685 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3687 ract->set_active ();
3692 Editor::snap_mode_selection_done (SnapMode mode)
3694 RefPtr<RadioAction> ract = snap_mode_action (mode);
3697 ract->set_active (true);
3702 Editor::cycle_edit_point (bool with_marker)
3704 if(Profile->get_mixbus())
3705 with_marker = false;
3707 switch (_edit_point) {
3709 set_edit_point_preference (EditAtPlayhead);
3711 case EditAtPlayhead:
3713 set_edit_point_preference (EditAtSelectedMarker);
3715 set_edit_point_preference (EditAtMouse);
3718 case EditAtSelectedMarker:
3719 set_edit_point_preference (EditAtMouse);
3725 Editor::edit_point_selection_done (EditPoint ep)
3727 set_edit_point_preference ( ep );
3731 Editor::build_zoom_focus_menu ()
3733 using namespace Menu_Helpers;
3735 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3736 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3737 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3738 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3739 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3740 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3742 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3746 Editor::zoom_focus_selection_done ( ZoomFocus f )
3748 RefPtr<RadioAction> ract = zoom_focus_action (f);
3750 ract->set_active ();
3755 Editor::build_track_count_menu ()
3757 using namespace Menu_Helpers;
3759 if (!Profile->get_mixbus()) {
3760 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3785 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3786 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3787 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3788 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3789 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3790 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3792 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3800 Editor::set_zoom_preset (int64_t ms)
3803 temporal_zoom_session();
3807 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3808 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3812 Editor::set_visible_track_count (int32_t n)
3814 _visible_track_count = n;
3816 /* if the canvas hasn't really been allocated any size yet, just
3817 record the desired number of visible tracks and return. when canvas
3818 allocation happens, we will get called again and then we can do the
3822 if (_visible_canvas_height <= 1) {
3828 DisplaySuspender ds;
3830 if (_visible_track_count > 0) {
3831 h = trackviews_height() / _visible_track_count;
3832 std::ostringstream s;
3833 s << _visible_track_count;
3835 } else if (_visible_track_count == 0) {
3837 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3838 if ((*i)->marked_for_display()) {
3842 h = trackviews_height() / n;
3845 /* negative value means that the visible track count has
3846 been overridden by explicit track height changes.
3848 visible_tracks_selector.set_text (X_("*"));
3852 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3853 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3856 if (str != visible_tracks_selector.get_text()) {
3857 visible_tracks_selector.set_text (str);
3862 Editor::override_visible_track_count ()
3864 _visible_track_count = -1;
3865 visible_tracks_selector.set_text ( _("*") );
3869 Editor::edit_controls_button_release (GdkEventButton* ev)
3871 if (Keyboard::is_context_menu_event (ev)) {
3872 ARDOUR_UI::instance()->add_route ();
3873 } else if (ev->button == 1) {
3874 selection->clear_tracks ();
3881 Editor::mouse_select_button_release (GdkEventButton* ev)
3883 /* this handles just right-clicks */
3885 if (ev->button != 3) {
3893 Editor::set_zoom_focus (ZoomFocus f)
3895 string str = zoom_focus_strings[(int)f];
3897 if (str != zoom_focus_selector.get_text()) {
3898 zoom_focus_selector.set_text (str);
3901 if (zoom_focus != f) {
3908 Editor::cycle_zoom_focus ()
3910 switch (zoom_focus) {
3912 set_zoom_focus (ZoomFocusRight);
3914 case ZoomFocusRight:
3915 set_zoom_focus (ZoomFocusCenter);
3917 case ZoomFocusCenter:
3918 set_zoom_focus (ZoomFocusPlayhead);
3920 case ZoomFocusPlayhead:
3921 set_zoom_focus (ZoomFocusMouse);
3923 case ZoomFocusMouse:
3924 set_zoom_focus (ZoomFocusEdit);
3927 set_zoom_focus (ZoomFocusLeft);
3933 Editor::set_show_measures (bool yn)
3935 if (_show_measures != yn) {
3938 if ((_show_measures = yn) == true) {
3940 tempo_lines->show();
3943 std::vector<TempoMap::BBTPoint> grid;
3944 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3945 draw_measures (grid);
3953 Editor::toggle_follow_playhead ()
3955 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3957 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3958 set_follow_playhead (tact->get_active());
3962 /** @param yn true to follow playhead, otherwise false.
3963 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3966 Editor::set_follow_playhead (bool yn, bool catch_up)
3968 if (_follow_playhead != yn) {
3969 if ((_follow_playhead = yn) == true && catch_up) {
3971 reset_x_origin_to_follow_playhead ();
3978 Editor::toggle_stationary_playhead ()
3980 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3982 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3983 set_stationary_playhead (tact->get_active());
3988 Editor::set_stationary_playhead (bool yn)
3990 if (_stationary_playhead != yn) {
3991 if ((_stationary_playhead = yn) == true) {
3993 // FIXME need a 3.0 equivalent of this 2.X call
3994 // update_current_screen ();
4001 Editor::playlist_selector () const
4003 return *_playlist_selector;
4007 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4009 if (paste_count == 0) {
4010 /* don't bother calculating an offset that will be zero anyway */
4014 /* calculate basic unsnapped multi-paste offset */
4015 framecnt_t offset = paste_count * duration;
4017 /* snap offset so pos + offset is aligned to the grid */
4018 framepos_t offset_pos = pos + offset;
4019 snap_to(offset_pos, RoundUpMaybe);
4020 offset = offset_pos - pos;
4026 Editor::get_grid_beat_divisions(framepos_t position)
4028 switch (_snap_type) {
4029 case SnapToBeatDiv128: return 128;
4030 case SnapToBeatDiv64: return 64;
4031 case SnapToBeatDiv32: return 32;
4032 case SnapToBeatDiv28: return 28;
4033 case SnapToBeatDiv24: return 24;
4034 case SnapToBeatDiv20: return 20;
4035 case SnapToBeatDiv16: return 16;
4036 case SnapToBeatDiv14: return 14;
4037 case SnapToBeatDiv12: return 12;
4038 case SnapToBeatDiv10: return 10;
4039 case SnapToBeatDiv8: return 8;
4040 case SnapToBeatDiv7: return 7;
4041 case SnapToBeatDiv6: return 6;
4042 case SnapToBeatDiv5: return 5;
4043 case SnapToBeatDiv4: return 4;
4044 case SnapToBeatDiv3: return 3;
4045 case SnapToBeatDiv2: return 2;
4051 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4052 if the grid is non-musical, returns 0.
4053 if the grid is snapped to bars, returns -1.
4054 @param event_state the current keyboard modifier mask.
4057 Editor::get_grid_music_divisions (uint32_t event_state)
4059 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4063 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4067 switch (_snap_type) {
4068 case SnapToBeatDiv128: return 128;
4069 case SnapToBeatDiv64: return 64;
4070 case SnapToBeatDiv32: return 32;
4071 case SnapToBeatDiv28: return 28;
4072 case SnapToBeatDiv24: return 24;
4073 case SnapToBeatDiv20: return 20;
4074 case SnapToBeatDiv16: return 16;
4075 case SnapToBeatDiv14: return 14;
4076 case SnapToBeatDiv12: return 12;
4077 case SnapToBeatDiv10: return 10;
4078 case SnapToBeatDiv8: return 8;
4079 case SnapToBeatDiv7: return 7;
4080 case SnapToBeatDiv6: return 6;
4081 case SnapToBeatDiv5: return 5;
4082 case SnapToBeatDiv4: return 4;
4083 case SnapToBeatDiv3: return 3;
4084 case SnapToBeatDiv2: return 2;
4085 case SnapToBeat: return 1;
4086 case SnapToBar : return -1;
4093 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4097 const unsigned divisions = get_grid_beat_divisions(position);
4099 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4102 switch (_snap_type) {
4104 return Evoral::Beats(1.0);
4107 return Evoral::Beats(_session->tempo_map().meter_at_frame (position).divisions_per_bar());
4115 return Evoral::Beats();
4119 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4123 ret = nudge_clock->current_duration (pos);
4124 next = ret + 1; /* XXXX fix me */
4130 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4132 ArdourDialog dialog (_("Playlist Deletion"));
4133 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4134 "If it is kept, its audio files will not be cleaned.\n"
4135 "If it is deleted, audio files used by it alone will be cleaned."),
4138 dialog.set_position (WIN_POS_CENTER);
4139 dialog.get_vbox()->pack_start (label);
4143 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4144 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4145 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4146 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4147 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4149 // by default gtk uses the left most button
4150 keep->grab_focus ();
4152 switch (dialog.run ()) {
4154 /* keep this and all remaining ones */
4159 /* delete this and all others */
4163 case RESPONSE_ACCEPT:
4164 /* delete the playlist */
4168 case RESPONSE_REJECT:
4169 /* keep the playlist */
4181 Editor::audio_region_selection_covers (framepos_t where)
4183 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4184 if ((*a)->region()->covers (where)) {
4193 Editor::prepare_for_cleanup ()
4195 cut_buffer->clear_regions ();
4196 cut_buffer->clear_playlists ();
4198 selection->clear_regions ();
4199 selection->clear_playlists ();
4201 _regions->suspend_redisplay ();
4205 Editor::finish_cleanup ()
4207 _regions->resume_redisplay ();
4211 Editor::transport_loop_location()
4214 return _session->locations()->auto_loop_location();
4221 Editor::transport_punch_location()
4224 return _session->locations()->auto_punch_location();
4231 Editor::control_layout_scroll (GdkEventScroll* ev)
4233 /* Just forward to the normal canvas scroll method. The coordinate
4234 systems are different but since the canvas is always larger than the
4235 track headers, and aligned with the trackview area, this will work.
4237 In the not too distant future this layout is going away anyway and
4238 headers will be on the canvas.
4240 return canvas_scroll_event (ev, false);
4244 Editor::session_state_saved (string)
4247 _snapshots->redisplay ();
4251 Editor::maximise_editing_space ()
4257 Gtk::Window* toplevel = current_toplevel();
4260 toplevel->fullscreen ();
4266 Editor::restore_editing_space ()
4272 Gtk::Window* toplevel = current_toplevel();
4275 toplevel->unfullscreen();
4281 * Make new playlists for a given track and also any others that belong
4282 * to the same active route group with the `select' property.
4287 Editor::new_playlists (TimeAxisView* v)
4289 begin_reversible_command (_("new playlists"));
4290 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4291 _session->playlists->get (playlists);
4292 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4293 commit_reversible_command ();
4297 * Use a copy of the current playlist for a given track and also any others that belong
4298 * to the same active route group with the `select' property.
4303 Editor::copy_playlists (TimeAxisView* v)
4305 begin_reversible_command (_("copy playlists"));
4306 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4307 _session->playlists->get (playlists);
4308 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4309 commit_reversible_command ();
4312 /** Clear the current playlist for a given track and also any others that belong
4313 * to the same active route group with the `select' property.
4318 Editor::clear_playlists (TimeAxisView* v)
4320 begin_reversible_command (_("clear playlists"));
4321 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4322 _session->playlists->get (playlists);
4323 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4324 commit_reversible_command ();
4328 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4330 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4334 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4336 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4340 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4342 atv.clear_playlist ();
4346 Editor::get_y_origin () const
4348 return vertical_adjustment.get_value ();
4351 /** Queue up a change to the viewport x origin.
4352 * @param frame New x origin.
4355 Editor::reset_x_origin (framepos_t frame)
4357 pending_visual_change.add (VisualChange::TimeOrigin);
4358 pending_visual_change.time_origin = frame;
4359 ensure_visual_change_idle_handler ();
4363 Editor::reset_y_origin (double y)
4365 pending_visual_change.add (VisualChange::YOrigin);
4366 pending_visual_change.y_origin = y;
4367 ensure_visual_change_idle_handler ();
4371 Editor::reset_zoom (framecnt_t spp)
4373 if (spp == samples_per_pixel) {
4377 pending_visual_change.add (VisualChange::ZoomLevel);
4378 pending_visual_change.samples_per_pixel = spp;
4379 ensure_visual_change_idle_handler ();
4383 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4385 reset_x_origin (frame);
4388 if (!no_save_visual) {
4389 undo_visual_stack.push_back (current_visual_state(false));
4393 Editor::VisualState::VisualState (bool with_tracks)
4394 : gui_state (with_tracks ? new GUIObjectState : 0)
4398 Editor::VisualState::~VisualState ()
4403 Editor::VisualState*
4404 Editor::current_visual_state (bool with_tracks)
4406 VisualState* vs = new VisualState (with_tracks);
4407 vs->y_position = vertical_adjustment.get_value();
4408 vs->samples_per_pixel = samples_per_pixel;
4409 vs->leftmost_frame = leftmost_frame;
4410 vs->zoom_focus = zoom_focus;
4413 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4420 Editor::undo_visual_state ()
4422 if (undo_visual_stack.empty()) {
4426 VisualState* vs = undo_visual_stack.back();
4427 undo_visual_stack.pop_back();
4430 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4433 use_visual_state (*vs);
4438 Editor::redo_visual_state ()
4440 if (redo_visual_stack.empty()) {
4444 VisualState* vs = redo_visual_stack.back();
4445 redo_visual_stack.pop_back();
4447 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4448 // why do we check here?
4449 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4452 use_visual_state (*vs);
4457 Editor::swap_visual_state ()
4459 if (undo_visual_stack.empty()) {
4460 redo_visual_state ();
4462 undo_visual_state ();
4467 Editor::use_visual_state (VisualState& vs)
4469 PBD::Unwinder<bool> nsv (no_save_visual, true);
4470 DisplaySuspender ds;
4472 vertical_adjustment.set_value (vs.y_position);
4474 set_zoom_focus (vs.zoom_focus);
4475 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4478 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4480 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4481 (*i)->clear_property_cache();
4482 (*i)->reset_visual_state ();
4486 _routes->update_visibility ();
4489 /** This is the core function that controls the zoom level of the canvas. It is called
4490 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4491 * @param spp new number of samples per pixel
4494 Editor::set_samples_per_pixel (framecnt_t spp)
4500 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4501 const framecnt_t lots_of_pixels = 4000;
4503 /* if the zoom level is greater than what you'd get trying to display 3
4504 * days of audio on a really big screen, then it's too big.
4507 if (spp * lots_of_pixels > three_days) {
4511 samples_per_pixel = spp;
4514 tempo_lines->tempo_map_changed();
4517 bool const showing_time_selection = selection->time.length() > 0;
4519 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4520 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4521 (*i)->reshow_selection (selection->time);
4525 ZoomChanged (); /* EMIT_SIGNAL */
4527 ArdourCanvas::GtkCanvasViewport* c;
4529 c = get_track_canvas();
4531 c->canvas()->zoomed ();
4534 if (playhead_cursor) {
4535 playhead_cursor->set_position (playhead_cursor->current_frame ());
4538 refresh_location_display();
4539 _summary->set_overlays_dirty ();
4541 update_marker_labels ();
4547 Editor::queue_visual_videotimeline_update ()
4550 * pending_visual_change.add (VisualChange::VideoTimeline);
4551 * or maybe even more specific: which videotimeline-image
4552 * currently it calls update_video_timeline() to update
4553 * _all outdated_ images on the video-timeline.
4554 * see 'exposeimg()' in video_image_frame.cc
4556 ensure_visual_change_idle_handler ();
4560 Editor::ensure_visual_change_idle_handler ()
4562 if (pending_visual_change.idle_handler_id < 0) {
4563 // see comment in add_to_idle_resize above.
4564 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4565 pending_visual_change.being_handled = false;
4570 Editor::_idle_visual_changer (void* arg)
4572 return static_cast<Editor*>(arg)->idle_visual_changer ();
4576 Editor::idle_visual_changer ()
4578 /* set_horizontal_position() below (and maybe other calls) call
4579 gtk_main_iteration(), so it's possible that a signal will be handled
4580 half-way through this method. If this signal wants an
4581 idle_visual_changer we must schedule another one after this one, so
4582 mark the idle_handler_id as -1 here to allow that. Also make a note
4583 that we are doing the visual change, so that changes in response to
4584 super-rapid-screen-update can be dropped if we are still processing
4588 pending_visual_change.idle_handler_id = -1;
4589 pending_visual_change.being_handled = true;
4591 VisualChange vc = pending_visual_change;
4593 pending_visual_change.pending = (VisualChange::Type) 0;
4595 visual_changer (vc);
4597 pending_visual_change.being_handled = false;
4599 return 0; /* this is always a one-shot call */
4603 Editor::visual_changer (const VisualChange& vc)
4605 double const last_time_origin = horizontal_position ();
4607 if (vc.pending & VisualChange::ZoomLevel) {
4608 set_samples_per_pixel (vc.samples_per_pixel);
4610 compute_fixed_ruler_scale ();
4612 std::vector<TempoMap::BBTPoint> grid;
4613 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4614 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4615 update_tempo_based_rulers (grid);
4617 update_video_timeline();
4620 if (vc.pending & VisualChange::TimeOrigin) {
4621 set_horizontal_position (vc.time_origin / samples_per_pixel);
4624 if (vc.pending & VisualChange::YOrigin) {
4625 vertical_adjustment.set_value (vc.y_origin);
4628 if (last_time_origin == horizontal_position ()) {
4629 /* changed signal not emitted */
4630 update_fixed_rulers ();
4631 redisplay_tempo (true);
4634 if (!(vc.pending & VisualChange::ZoomLevel)) {
4635 update_video_timeline();
4638 _summary->set_overlays_dirty ();
4641 struct EditorOrderTimeAxisSorter {
4642 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4643 return a->order () < b->order ();
4648 Editor::sort_track_selection (TrackViewList& sel)
4650 EditorOrderTimeAxisSorter cmp;
4655 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4658 framepos_t where = 0;
4659 EditPoint ep = _edit_point;
4661 if (Profile->get_mixbus())
4662 if (ep == EditAtSelectedMarker)
4663 ep = EditAtPlayhead;
4665 if (from_outside_canvas && (ep == EditAtMouse)) {
4666 ep = EditAtPlayhead;
4667 } else if (from_context_menu && (ep == EditAtMouse)) {
4668 return canvas_event_sample (&context_click_event, 0, 0);
4671 if (entered_marker) {
4672 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4673 return entered_marker->position();
4676 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4677 ep = EditAtSelectedMarker;
4680 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4681 ep = EditAtPlayhead;
4685 case EditAtPlayhead:
4686 if (_dragging_playhead) {
4687 where = *_control_scroll_target;
4689 where = _session->audible_frame();
4691 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4694 case EditAtSelectedMarker:
4695 if (!selection->markers.empty()) {
4697 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4700 where = loc->start();
4704 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4712 if (!mouse_frame (where, ignored)) {
4713 /* XXX not right but what can we do ? */
4717 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4725 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4727 if (!_session) return;
4729 begin_reversible_command (cmd);
4733 if ((tll = transport_loop_location()) == 0) {
4734 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4735 XMLNode &before = _session->locations()->get_state();
4736 _session->locations()->add (loc, true);
4737 _session->set_auto_loop_location (loc);
4738 XMLNode &after = _session->locations()->get_state();
4739 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4741 XMLNode &before = tll->get_state();
4742 tll->set_hidden (false, this);
4743 tll->set (start, end);
4744 XMLNode &after = tll->get_state();
4745 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4748 commit_reversible_command ();
4752 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4754 if (!_session) return;
4756 begin_reversible_command (cmd);
4760 if ((tpl = transport_punch_location()) == 0) {
4761 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4762 XMLNode &before = _session->locations()->get_state();
4763 _session->locations()->add (loc, true);
4764 _session->set_auto_punch_location (loc);
4765 XMLNode &after = _session->locations()->get_state();
4766 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4768 XMLNode &before = tpl->get_state();
4769 tpl->set_hidden (false, this);
4770 tpl->set (start, end);
4771 XMLNode &after = tpl->get_state();
4772 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4775 commit_reversible_command ();
4778 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4779 * @param rs List to which found regions are added.
4780 * @param where Time to look at.
4781 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4784 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4786 const TrackViewList* tracks;
4789 tracks = &track_views;
4794 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4796 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4799 boost::shared_ptr<Track> tr;
4800 boost::shared_ptr<Playlist> pl;
4802 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4804 boost::shared_ptr<RegionList> regions = pl->regions_at (
4805 (framepos_t) floor ( (double) where * tr->speed()));
4807 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4808 RegionView* rv = rtv->view()->find_view (*i);
4819 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4821 const TrackViewList* tracks;
4824 tracks = &track_views;
4829 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4830 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4832 boost::shared_ptr<Track> tr;
4833 boost::shared_ptr<Playlist> pl;
4835 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4837 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4838 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4840 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4842 RegionView* rv = rtv->view()->find_view (*i);
4853 /** Get regions using the following method:
4855 * Make a region list using:
4856 * (a) any selected regions
4857 * (b) the intersection of any selected tracks and the edit point(*)
4858 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4860 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4862 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4866 Editor::get_regions_from_selection_and_edit_point ()
4868 RegionSelection regions;
4870 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4871 regions.add (entered_regionview);
4873 regions = selection->regions;
4876 if ( regions.empty() ) {
4877 TrackViewList tracks = selection->tracks;
4879 if (!tracks.empty()) {
4880 /* no region selected or entered, but some selected tracks:
4881 * act on all regions on the selected tracks at the edit point
4883 framepos_t const where = get_preferred_edit_position ();
4884 get_regions_at(regions, where, tracks);
4891 /** Get regions using the following method:
4893 * Make a region list using:
4894 * (a) any selected regions
4895 * (b) the intersection of any selected tracks and the edit point(*)
4896 * (c) if neither exists, then whatever region is under the mouse
4898 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4900 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4903 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4905 RegionSelection regions;
4907 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4908 regions.add (entered_regionview);
4910 regions = selection->regions;
4913 if ( regions.empty() ) {
4914 TrackViewList tracks = selection->tracks;
4916 if (!tracks.empty()) {
4917 /* no region selected or entered, but some selected tracks:
4918 * act on all regions on the selected tracks at the edit point
4920 get_regions_at(regions, pos, tracks);
4927 /** Start with regions that are selected, or the entered regionview if none are selected.
4928 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4929 * of the regions that we started with.
4933 Editor::get_regions_from_selection_and_entered () const
4935 RegionSelection regions = selection->regions;
4937 if (regions.empty() && entered_regionview) {
4938 regions.add (entered_regionview);
4945 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4947 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4948 RouteTimeAxisView* rtav;
4950 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4951 boost::shared_ptr<Playlist> pl;
4952 std::vector<boost::shared_ptr<Region> > results;
4953 boost::shared_ptr<Track> tr;
4955 if ((tr = rtav->track()) == 0) {
4960 if ((pl = (tr->playlist())) != 0) {
4961 boost::shared_ptr<Region> r = pl->region_by_id (id);
4963 RegionView* rv = rtav->view()->find_view (r);
4965 regions.push_back (rv);
4974 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4977 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4978 MidiTimeAxisView* mtav;
4980 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4982 mtav->get_per_region_note_selection (selection);
4989 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4991 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4993 RouteTimeAxisView* tatv;
4995 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4997 boost::shared_ptr<Playlist> pl;
4998 vector<boost::shared_ptr<Region> > results;
5000 boost::shared_ptr<Track> tr;
5002 if ((tr = tatv->track()) == 0) {
5007 if ((pl = (tr->playlist())) != 0) {
5008 if (src_comparison) {
5009 pl->get_source_equivalent_regions (region, results);
5011 pl->get_region_list_equivalent_regions (region, results);
5015 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5016 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5017 regions.push_back (marv);
5026 Editor::show_rhythm_ferret ()
5028 if (rhythm_ferret == 0) {
5029 rhythm_ferret = new RhythmFerret(*this);
5032 rhythm_ferret->set_session (_session);
5033 rhythm_ferret->show ();
5034 rhythm_ferret->present ();
5038 Editor::first_idle ()
5040 MessageDialog* dialog = 0;
5042 if (track_views.size() > 1) {
5043 Timers::TimerSuspender t;
5044 dialog = new MessageDialog (
5045 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5049 ARDOUR_UI::instance()->flush_pending ();
5052 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5056 // first idle adds route children (automation tracks), so we need to redisplay here
5057 _routes->redisplay ();
5061 if (_session->undo_depth() == 0) {
5062 undo_action->set_sensitive(false);
5064 redo_action->set_sensitive(false);
5065 begin_selection_op_history ();
5071 Editor::_idle_resize (gpointer arg)
5073 return ((Editor*)arg)->idle_resize ();
5077 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5079 if (resize_idle_id < 0) {
5080 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5081 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5082 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5084 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5085 _pending_resize_amount = 0;
5088 /* make a note of the smallest resulting height, so that we can clamp the
5089 lower limit at TimeAxisView::hSmall */
5091 int32_t min_resulting = INT32_MAX;
5093 _pending_resize_amount += h;
5094 _pending_resize_view = view;
5096 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5098 if (selection->tracks.contains (_pending_resize_view)) {
5099 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5100 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5104 if (min_resulting < 0) {
5109 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5110 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5114 /** Handle pending resizing of tracks */
5116 Editor::idle_resize ()
5118 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5120 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5121 selection->tracks.contains (_pending_resize_view)) {
5123 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5124 if (*i != _pending_resize_view) {
5125 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5130 _pending_resize_amount = 0;
5131 _group_tabs->set_dirty ();
5132 resize_idle_id = -1;
5140 ENSURE_GUI_THREAD (*this, &Editor::located);
5143 playhead_cursor->set_position (_session->audible_frame ());
5144 if (_follow_playhead && !_pending_initial_locate) {
5145 reset_x_origin_to_follow_playhead ();
5149 _pending_locate_request = false;
5150 _pending_initial_locate = false;
5154 Editor::region_view_added (RegionView * rv)
5156 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5157 if (rv->region ()->id () == (*pr)) {
5158 selection->add (rv);
5159 selection->regions.pending.erase (pr);
5164 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5166 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5167 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5168 if (rv->region()->id () == (*rnote).first) {
5169 mrv->select_notes ((*rnote).second);
5170 selection->pending_midi_note_selection.erase(rnote);
5176 _summary->set_background_dirty ();
5180 Editor::region_view_removed ()
5182 _summary->set_background_dirty ();
5186 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5188 TrackViewList::const_iterator j = track_views.begin ();
5189 while (j != track_views.end()) {
5190 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5191 if (rtv && rtv->route() == r) {
5202 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5206 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5207 TimeAxisView* tv = axis_view_from_route (*i);
5217 Editor::suspend_route_redisplay ()
5220 _routes->suspend_redisplay();
5225 Editor::resume_route_redisplay ()
5228 _routes->redisplay(); // queue redisplay
5229 _routes->resume_redisplay();
5234 Editor::add_vcas (VCAList& vlist)
5238 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5239 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5242 add_stripables (sl);
5246 Editor::add_routes (RouteList& rlist)
5250 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5254 add_stripables (sl);
5258 Editor::add_stripables (StripableList& sl)
5260 list<TimeAxisView*> new_views;
5261 boost::shared_ptr<VCA> v;
5262 boost::shared_ptr<Route> r;
5263 TrackViewList new_selection;
5264 bool from_scratch = (track_views.size() == 0);
5266 sl.sort (StripablePresentationInfoSorter());
5268 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5270 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5272 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5274 new_views.push_back (vtv);
5276 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5278 if (r->is_auditioner() || r->is_monitor()) {
5282 RouteTimeAxisView* rtv;
5283 DataType dt = r->input()->default_type();
5285 if (dt == ARDOUR::DataType::AUDIO) {
5286 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5288 } else if (dt == ARDOUR::DataType::MIDI) {
5289 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5292 throw unknown_type();
5295 new_views.push_back (rtv);
5296 track_views.push_back (rtv);
5297 new_selection.push_back (rtv);
5299 rtv->effective_gain_display ();
5301 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5302 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5306 if (new_views.size() > 0) {
5307 _routes->time_axis_views_added (new_views);
5308 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5311 /* note: !new_selection.empty() means that we got some routes rather
5315 if (!from_scratch && !new_selection.empty()) {
5316 selection->tracks.clear();
5317 selection->add (new_selection);
5318 begin_selection_op_history();
5321 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5322 show_editor_mixer (true);
5325 editor_list_button.set_sensitive (true);
5329 Editor::timeaxisview_deleted (TimeAxisView *tv)
5331 if (tv == entered_track) {
5335 if (_session && _session->deletion_in_progress()) {
5336 /* the situation is under control */
5340 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5342 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5344 _routes->route_removed (tv);
5346 TimeAxisView::Children c = tv->get_child_list ();
5347 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5348 if (entered_track == i->get()) {
5353 /* remove it from the list of track views */
5355 TrackViewList::iterator i;
5357 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5358 i = track_views.erase (i);
5361 /* update whatever the current mixer strip is displaying, if revelant */
5363 boost::shared_ptr<Route> route;
5366 route = rtav->route ();
5369 if (current_mixer_strip && current_mixer_strip->route() == route) {
5371 TimeAxisView* next_tv;
5373 if (track_views.empty()) {
5375 } else if (i == track_views.end()) {
5376 next_tv = track_views.front();
5383 set_selected_mixer_strip (*next_tv);
5385 /* make the editor mixer strip go away setting the
5386 * button to inactive (which also unticks the menu option)
5389 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5395 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5397 if (apply_to_selection) {
5398 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5400 TrackSelection::iterator j = i;
5403 hide_track_in_display (*i, false);
5408 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5410 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5411 // this will hide the mixer strip
5412 set_selected_mixer_strip (*tv);
5415 _routes->hide_track_in_display (*tv);
5420 Editor::sync_track_view_list_and_routes ()
5422 track_views = TrackViewList (_routes->views ());
5424 _summary->set_background_dirty();
5425 _group_tabs->set_dirty ();
5427 return false; // do not call again (until needed)
5431 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5433 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5438 /** Find a RouteTimeAxisView by the ID of its route */
5440 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5442 RouteTimeAxisView* v;
5444 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5445 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5446 if(v->route()->id() == id) {
5456 Editor::fit_route_group (RouteGroup *g)
5458 TrackViewList ts = axis_views_from_routes (g->route_list ());
5463 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5465 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5468 _session->cancel_audition ();
5472 if (_session->is_auditioning()) {
5473 _session->cancel_audition ();
5474 if (r == last_audition_region) {
5479 _session->audition_region (r);
5480 last_audition_region = r;
5485 Editor::hide_a_region (boost::shared_ptr<Region> r)
5487 r->set_hidden (true);
5491 Editor::show_a_region (boost::shared_ptr<Region> r)
5493 r->set_hidden (false);
5497 Editor::audition_region_from_region_list ()
5499 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5503 Editor::hide_region_from_region_list ()
5505 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5509 Editor::show_region_in_region_list ()
5511 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5515 Editor::step_edit_status_change (bool yn)
5518 start_step_editing ();
5520 stop_step_editing ();
5525 Editor::start_step_editing ()
5527 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5531 Editor::stop_step_editing ()
5533 step_edit_connection.disconnect ();
5537 Editor::check_step_edit ()
5539 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5540 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5542 mtv->check_step_edit ();
5546 return true; // do it again, till we stop
5550 Editor::scroll_press (Direction dir)
5552 ++_scroll_callbacks;
5554 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5555 /* delay the first auto-repeat */
5561 scroll_backward (1);
5569 scroll_up_one_track ();
5573 scroll_down_one_track ();
5577 /* do hacky auto-repeat */
5578 if (!_scroll_connection.connected ()) {
5580 _scroll_connection = Glib::signal_timeout().connect (
5581 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5584 _scroll_callbacks = 0;
5591 Editor::scroll_release ()
5593 _scroll_connection.disconnect ();
5596 /** Queue a change for the Editor viewport x origin to follow the playhead */
5598 Editor::reset_x_origin_to_follow_playhead ()
5600 framepos_t const frame = playhead_cursor->current_frame ();
5602 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5604 if (_session->transport_speed() < 0) {
5606 if (frame > (current_page_samples() / 2)) {
5607 center_screen (frame-(current_page_samples()/2));
5609 center_screen (current_page_samples()/2);
5616 if (frame < leftmost_frame) {
5618 if (_session->transport_rolling()) {
5619 /* rolling; end up with the playhead at the right of the page */
5620 l = frame - current_page_samples ();
5622 /* not rolling: end up with the playhead 1/4 of the way along the page */
5623 l = frame - current_page_samples() / 4;
5627 if (_session->transport_rolling()) {
5628 /* rolling: end up with the playhead on the left of the page */
5631 /* not rolling: end up with the playhead 3/4 of the way along the page */
5632 l = frame - 3 * current_page_samples() / 4;
5640 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5646 Editor::super_rapid_screen_update ()
5648 if (!_session || !_session->engine().running()) {
5652 /* METERING / MIXER STRIPS */
5654 /* update track meters, if required */
5655 if (contents().is_mapped() && meters_running) {
5656 RouteTimeAxisView* rtv;
5657 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5658 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5659 rtv->fast_update ();
5664 /* and any current mixer strip */
5665 if (current_mixer_strip) {
5666 current_mixer_strip->fast_update ();
5669 /* PLAYHEAD AND VIEWPORT */
5671 framepos_t const frame = _session->audible_frame();
5673 /* There are a few reasons why we might not update the playhead / viewport stuff:
5675 * 1. we don't update things when there's a pending locate request, otherwise
5676 * when the editor requests a locate there is a chance that this method
5677 * will move the playhead before the locate request is processed, causing
5679 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5680 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5683 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5685 last_update_frame = frame;
5687 if (!_dragging_playhead) {
5688 playhead_cursor->set_position (frame);
5691 if (!_stationary_playhead) {
5693 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5694 /* We only do this if we aren't already
5695 handling a visual change (ie if
5696 pending_visual_change.being_handled is
5697 false) so that these requests don't stack
5698 up there are too many of them to handle in
5701 reset_x_origin_to_follow_playhead ();
5706 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5707 framepos_t const frame = playhead_cursor->current_frame ();
5708 double target = ((double)frame - (double)current_page_samples()/2.0);
5709 if (target <= 0.0) {
5712 // compare to EditorCursor::set_position()
5713 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5714 double const new_pos = sample_to_pixel_unrounded (target);
5715 if (rint (new_pos) != rint (old_pos)) {
5716 reset_x_origin (pixel_to_sample (floor (new_pos)));
5727 Editor::session_going_away ()
5729 _have_idled = false;
5731 _session_connections.drop_connections ();
5733 super_rapid_screen_update_connection.disconnect ();
5735 selection->clear ();
5736 cut_buffer->clear ();
5738 clicked_regionview = 0;
5739 clicked_axisview = 0;
5740 clicked_routeview = 0;
5741 entered_regionview = 0;
5743 last_update_frame = 0;
5746 playhead_cursor->hide ();
5748 /* rip everything out of the list displays */
5752 _route_groups->clear ();
5754 /* do this first so that deleting a track doesn't reset cms to null
5755 and thus cause a leak.
5758 if (current_mixer_strip) {
5759 if (current_mixer_strip->get_parent() != 0) {
5760 global_hpacker.remove (*current_mixer_strip);
5762 delete current_mixer_strip;
5763 current_mixer_strip = 0;
5766 /* delete all trackviews */
5768 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5771 track_views.clear ();
5773 nudge_clock->set_session (0);
5775 editor_list_button.set_active(false);
5776 editor_list_button.set_sensitive(false);
5778 /* clear tempo/meter rulers */
5779 remove_metric_marks ();
5781 clear_marker_display ();
5783 stop_step_editing ();
5787 /* get rid of any existing editor mixer strip */
5789 WindowTitle title(Glib::get_application_name());
5790 title += _("Editor");
5792 own_window()->set_title (title.get_string());
5795 SessionHandlePtr::session_going_away ();
5799 Editor::trigger_script (int i)
5801 LuaInstance::instance()-> call_action (i);
5805 Editor::set_script_action_name (int i, const std::string& n)
5807 string const a = string_compose (X_("script-action-%1"), i + 1);
5808 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5811 act->set_label (string_compose (_("Unset #%1"), i + 1));
5812 act->set_tooltip (_("no action bound"));
5813 act->set_sensitive (false);
5816 act->set_tooltip (n);
5817 act->set_sensitive (true);
5819 KeyEditor::UpdateBindings ();
5823 Editor::show_editor_list (bool yn)
5826 _the_notebook.show ();
5828 _the_notebook.hide ();
5833 Editor::change_region_layering_order (bool from_context_menu)
5835 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5837 if (!clicked_routeview) {
5838 if (layering_order_editor) {
5839 layering_order_editor->hide ();
5844 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5850 boost::shared_ptr<Playlist> pl = track->playlist();
5856 if (layering_order_editor == 0) {
5857 layering_order_editor = new RegionLayeringOrderEditor (*this);
5860 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5861 layering_order_editor->maybe_present ();
5865 Editor::update_region_layering_order_editor ()
5867 if (layering_order_editor && layering_order_editor->is_visible ()) {
5868 change_region_layering_order (true);
5873 Editor::setup_fade_images ()
5875 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5876 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5877 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5878 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5879 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5881 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5882 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5883 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5884 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5885 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5887 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5888 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5889 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5890 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5891 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5893 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5894 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5895 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5896 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5897 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5901 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5903 Editor::action_menu_item (std::string const & name)
5905 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5908 return *manage (a->create_menu_item ());
5912 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5914 EventBox* b = manage (new EventBox);
5915 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5916 Label* l = manage (new Label (name));
5920 _the_notebook.append_page (widget, *b);
5924 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5926 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5927 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5930 if (ev->type == GDK_2BUTTON_PRESS) {
5932 /* double-click on a notebook tab shrinks or expands the notebook */
5934 if (_notebook_shrunk) {
5935 if (pre_notebook_shrink_pane_width) {
5936 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
5938 _notebook_shrunk = false;
5940 pre_notebook_shrink_pane_width = edit_pane.get_divider();
5942 /* this expands the LHS of the edit pane to cover the notebook
5943 PAGE but leaves the tabs visible.
5945 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
5946 _notebook_shrunk = true;
5954 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5956 using namespace Menu_Helpers;
5958 MenuList& items = _control_point_context_menu.items ();
5961 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5962 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5963 if (!can_remove_control_point (item)) {
5964 items.back().set_sensitive (false);
5967 _control_point_context_menu.popup (event->button.button, event->button.time);
5971 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5973 using namespace Menu_Helpers;
5975 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5980 /* We need to get the selection here and pass it to the operations, since
5981 popping up the menu will cause a region leave event which clears
5982 entered_regionview. */
5984 MidiRegionView& mrv = note->region_view();
5985 const RegionSelection rs = get_regions_from_selection_and_entered ();
5986 const uint32_t sel_size = mrv.selection_size ();
5988 MenuList& items = _note_context_menu.items();
5992 items.push_back(MenuElem(_("Delete"),
5993 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5996 items.push_back(MenuElem(_("Edit..."),
5997 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5998 if (sel_size != 1) {
5999 items.back().set_sensitive (false);
6002 items.push_back(MenuElem(_("Transpose..."),
6003 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6006 items.push_back(MenuElem(_("Legatize"),
6007 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6009 items.back().set_sensitive (false);
6012 items.push_back(MenuElem(_("Quantize..."),
6013 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6015 items.push_back(MenuElem(_("Remove Overlap"),
6016 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6018 items.back().set_sensitive (false);
6021 items.push_back(MenuElem(_("Transform..."),
6022 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6024 _note_context_menu.popup (event->button.button, event->button.time);
6028 Editor::zoom_vertical_modifier_released()
6030 _stepping_axis_view = 0;
6034 Editor::ui_parameter_changed (string parameter)
6036 if (parameter == "icon-set") {
6037 while (!_cursor_stack.empty()) {
6038 _cursor_stack.pop_back();
6040 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6041 _cursor_stack.push_back(_cursors->grabber);
6042 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6043 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6045 } else if (parameter == "draggable-playhead") {
6046 if (_verbose_cursor) {
6047 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6053 Editor::use_own_window (bool and_fill_it)
6055 bool new_window = !own_window();
6057 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6059 if (win && new_window) {
6060 win->set_name ("EditorWindow");
6062 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6064 // win->signal_realize().connect (*this, &Editor::on_realize);
6065 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6066 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6067 win->set_data ("ardour-bindings", bindings);
6072 DisplaySuspender ds;
6073 contents().show_all ();
6075 /* XXX: this is a bit unfortunate; it would probably
6076 be nicer if we could just call show () above rather
6077 than needing the show_all ()
6080 /* re-hide stuff if necessary */
6081 editor_list_button_toggled ();
6082 parameter_changed ("show-summary");
6083 parameter_changed ("show-group-tabs");
6084 parameter_changed ("show-zoom-tools");
6086 /* now reset all audio_time_axis heights, because widgets might need
6092 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6093 tv = (static_cast<TimeAxisView*>(*i));
6094 tv->reset_height ();
6097 if (current_mixer_strip) {
6098 current_mixer_strip->hide_things ();
6099 current_mixer_strip->parameter_changed ("mixer-element-visibility");