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/eventboxext.h"
61 #include "gtkmm2ext/grouped_buttons.h"
62 #include "gtkmm2ext/gtk_ui.h"
63 #include <gtkmm2ext/keyboard.h>
64 #include "gtkmm2ext/utils.h"
65 #include "gtkmm2ext/window_title.h"
66 #include "gtkmm2ext/choice.h"
67 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
69 #include "ardour/analysis_graph.h"
70 #include "ardour/audio_track.h"
71 #include "ardour/audioengine.h"
72 #include "ardour/audioregion.h"
73 #include "ardour/lmath.h"
74 #include "ardour/location.h"
75 #include "ardour/profile.h"
76 #include "ardour/route.h"
77 #include "ardour/route_group.h"
78 #include "ardour/session_playlists.h"
79 #include "ardour/tempo.h"
80 #include "ardour/utils.h"
81 #include "ardour/vca_manager.h"
82 #include "ardour/vca.h"
84 #include "canvas/debug.h"
85 #include "canvas/text.h"
87 #include "control_protocol/control_protocol.h"
90 #include "analysis_window.h"
91 #include "ardour_spacer.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
101 #include "editing_convert.h"
103 #include "editor_cursors.h"
104 #include "editor_drag.h"
105 #include "editor_group_tabs.h"
106 #include "editor_locations.h"
107 #include "editor_regions.h"
108 #include "editor_route_groups.h"
109 #include "editor_routes.h"
110 #include "editor_snapshots.h"
111 #include "editor_summary.h"
112 #include "enums_convert.h"
113 #include "export_report.h"
114 #include "global_port_matrix.h"
115 #include "gui_object.h"
116 #include "gui_thread.h"
117 #include "keyboard.h"
118 #include "luainstance.h"
120 #include "midi_region_view.h"
121 #include "midi_time_axis.h"
122 #include "mixer_strip.h"
123 #include "mixer_ui.h"
124 #include "mouse_cursors.h"
125 #include "note_base.h"
126 #include "playlist_selector.h"
127 #include "public_editor.h"
128 #include "quantize_dialog.h"
129 #include "region_layering_order_editor.h"
130 #include "rgb_macros.h"
131 #include "rhythm_ferret.h"
132 #include "route_sorter.h"
133 #include "selection.h"
134 #include "simple_progress_dialog.h"
136 #include "tempo_lines.h"
137 #include "time_axis_view.h"
138 #include "time_info_box.h"
140 #include "tooltips.h"
141 #include "ui_config.h"
143 #include "vca_time_axis.h"
144 #include "verbose_cursor.h"
146 #include "pbd/i18n.h"
149 using namespace ARDOUR;
150 using namespace ARDOUR_UI_UTILS;
153 using namespace Glib;
154 using namespace Gtkmm2ext;
155 using namespace Editing;
157 using PBD::internationalize;
159 using Gtkmm2ext::Keyboard;
161 double Editor::timebar_height = 15.0;
163 static const gchar *_snap_type_strings[] = {
197 static const gchar *_snap_mode_strings[] = {
204 static const gchar *_edit_point_strings[] = {
211 static const gchar *_edit_mode_strings[] = {
219 static const gchar *_zoom_focus_strings[] = {
229 #ifdef USE_RUBBERBAND
230 static const gchar *_rb_opt_strings[] = {
233 N_("Balanced multitimbral mixture"),
234 N_("Unpitched percussion with stable notes"),
235 N_("Crisp monophonic instrumental"),
236 N_("Unpitched solo percussion"),
237 N_("Resample without preserving pitch"),
242 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
245 : PublicEditor (global_hpacker)
246 , editor_mixer_strip_width (Wide)
247 , constructed (false)
248 , _playlist_selector (0)
250 , no_save_visual (false)
252 , samples_per_pixel (2048)
253 , zoom_focus (ZoomFocusPlayhead)
254 , mouse_mode (MouseObject)
255 , pre_internal_snap_type (SnapToBeat)
256 , pre_internal_snap_mode (SnapOff)
257 , internal_snap_type (SnapToBeat)
258 , internal_snap_mode (SnapOff)
259 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
260 , _notebook_shrunk (false)
261 , location_marker_color (0)
262 , location_range_color (0)
263 , location_loop_color (0)
264 , location_punch_color (0)
265 , location_cd_marker_color (0)
267 , _show_marker_lines (false)
268 , clicked_axisview (0)
269 , clicked_routeview (0)
270 , clicked_regionview (0)
271 , clicked_selection (0)
272 , clicked_control_point (0)
273 , button_release_can_deselect (true)
274 , _mouse_changed_selection (false)
275 , region_edit_menu_split_item (0)
276 , region_edit_menu_split_multichannel_item (0)
277 , track_region_edit_playlist_menu (0)
278 , track_edit_playlist_submenu (0)
279 , track_selection_edit_playlist_submenu (0)
280 , _popup_region_menu_item (0)
282 , _track_canvas_viewport (0)
283 , within_track_canvas (false)
284 , _verbose_cursor (0)
288 , range_marker_group (0)
289 , transport_marker_group (0)
290 , cd_marker_group (0)
291 , _time_markers_group (0)
292 , hv_scroll_group (0)
294 , cursor_scroll_group (0)
295 , no_scroll_group (0)
296 , _trackview_group (0)
297 , _drag_motion_group (0)
298 , _canvas_drop_zone (0)
299 , no_ruler_shown_update (false)
300 , ruler_grabbed_widget (0)
302 , minsec_mark_interval (0)
303 , minsec_mark_modulo (0)
305 , timecode_mark_modulo (0)
306 , timecode_nmarks (0)
307 , _samples_ruler_interval (0)
310 , bbt_bar_helper_on (0)
311 , bbt_accent_modulo (0)
316 , visible_timebars (0)
317 , editor_ruler_menu (0)
321 , range_marker_bar (0)
322 , transport_marker_bar (0)
324 , minsec_label (_("Mins:Secs"))
325 , bbt_label (_("Bars:Beats"))
326 , timecode_label (_("Timecode"))
327 , samples_label (_("Samples"))
328 , tempo_label (_("Tempo"))
329 , meter_label (_("Meter"))
330 , mark_label (_("Location Markers"))
331 , range_mark_label (_("Range Markers"))
332 , transport_mark_label (_("Loop/Punch Ranges"))
333 , cd_mark_label (_("CD Markers"))
334 , videotl_label (_("Video Timeline"))
336 , playhead_cursor (0)
337 , edit_packer (4, 4, true)
338 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
339 , horizontal_adjustment (0.0, 0.0, 1e16)
340 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
341 , controls_layout (unused_adjustment, vertical_adjustment)
342 , _scroll_callbacks (0)
343 , _visible_canvas_width (0)
344 , _visible_canvas_height (0)
345 , _full_canvas_height (0)
346 , edit_controls_left_menu (0)
347 , edit_controls_right_menu (0)
348 , _last_update_time (0)
349 , _err_screen_engine (0)
350 , cut_buffer_start (0)
351 , cut_buffer_length (0)
352 , button_bindings (0)
356 , current_interthread_info (0)
357 , analysis_window (0)
358 , select_new_marker (false)
360 , scrubbing_direction (0)
361 , scrub_reversals (0)
362 , scrub_reverse_distance (0)
363 , have_pending_keyboard_selection (false)
364 , pending_keyboard_selection_start (0)
365 , _snap_type (SnapToBeat)
366 , _snap_mode (SnapOff)
367 , snap_threshold (5.0)
368 , ignore_gui_changes (false)
369 , _drags (new DragManager (this))
371 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
372 , _dragging_playhead (false)
373 , _dragging_edit_point (false)
374 , _show_measures (true)
375 , _follow_playhead (true)
376 , _stationary_playhead (false)
379 , global_rect_group (0)
380 , time_line_group (0)
381 , tempo_marker_menu (0)
382 , meter_marker_menu (0)
384 , range_marker_menu (0)
385 , transport_marker_menu (0)
386 , new_transport_marker_menu (0)
388 , marker_menu_item (0)
389 , bbt_beat_subdivision (4)
390 , _visible_track_count (-1)
391 , toolbar_selection_clock_table (2,3)
392 , automation_mode_button (_("mode"))
393 , selection (new Selection (this))
394 , cut_buffer (new Selection (this))
395 , _selection_memento (new SelectionMemento())
396 , _all_region_actions_sensitized (false)
397 , _ignore_region_action (false)
398 , _last_region_menu_was_main (false)
399 , _track_selection_change_without_scroll (false)
400 , cd_marker_bar_drag_rect (0)
401 , range_bar_drag_rect (0)
402 , transport_bar_drag_rect (0)
403 , transport_bar_range_rect (0)
404 , transport_bar_preroll_rect (0)
405 , transport_bar_postroll_rect (0)
406 , transport_loop_range_rect (0)
407 , transport_punch_range_rect (0)
408 , transport_punchin_line (0)
409 , transport_punchout_line (0)
410 , transport_preroll_rect (0)
411 , transport_postroll_rect (0)
413 , rubberband_rect (0)
419 , autoscroll_horizontal_allowed (false)
420 , autoscroll_vertical_allowed (false)
422 , autoscroll_widget (0)
423 , show_gain_after_trim (false)
424 , selection_op_cmd_depth (0)
425 , selection_op_history_it (0)
426 , no_save_instant (false)
428 , current_mixer_strip (0)
429 , show_editor_mixer_when_tracks_arrive (false)
430 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
431 , current_stepping_trackview (0)
432 , last_track_height_step_timestamp (0)
434 , entered_regionview (0)
435 , clear_entered_track (false)
436 , _edit_point (EditAtMouse)
437 , meters_running (false)
439 , _have_idled (false)
440 , resize_idle_id (-1)
441 , _pending_resize_amount (0)
442 , _pending_resize_view (0)
443 , _pending_locate_request (false)
444 , _pending_initial_locate (false)
448 , layering_order_editor (0)
449 , _last_cut_copy_source_track (0)
450 , _region_selection_change_updates_region_list (true)
452 , _following_mixer_selection (false)
453 , _control_point_toggled_on_press (false)
454 , _stepping_axis_view (0)
455 , quantize_dialog (0)
456 , _main_menu_disabler (0)
457 , myactions (X_("editor"))
459 /* we are a singleton */
461 PublicEditor::_instance = this;
465 last_event_time.tv_sec = 0;
466 last_event_time.tv_usec = 0;
468 selection_op_history.clear();
471 snap_type_strings = I18N (_snap_type_strings);
472 snap_mode_strings = I18N (_snap_mode_strings);
473 zoom_focus_strings = I18N (_zoom_focus_strings);
474 edit_mode_strings = I18N (_edit_mode_strings);
475 edit_point_strings = I18N (_edit_point_strings);
476 #ifdef USE_RUBBERBAND
477 rb_opt_strings = I18N (_rb_opt_strings);
481 build_edit_mode_menu();
482 build_zoom_focus_menu();
483 build_track_count_menu();
484 build_snap_mode_menu();
485 build_snap_type_menu();
486 build_edit_point_menu();
488 location_marker_color = UIConfiguration::instance().color ("location marker");
489 location_range_color = UIConfiguration::instance().color ("location range");
490 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
491 location_loop_color = UIConfiguration::instance().color ("location loop");
492 location_punch_color = UIConfiguration::instance().color ("location punch");
494 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
496 TimeAxisView::setup_sizes ();
497 ArdourMarker::setup_sizes (timebar_height);
498 TempoCurve::setup_sizes (timebar_height);
500 bbt_label.set_name ("EditorRulerLabel");
501 bbt_label.set_size_request (-1, (int)timebar_height);
502 bbt_label.set_alignment (1.0, 0.5);
503 bbt_label.set_padding (5,0);
505 bbt_label.set_no_show_all();
506 minsec_label.set_name ("EditorRulerLabel");
507 minsec_label.set_size_request (-1, (int)timebar_height);
508 minsec_label.set_alignment (1.0, 0.5);
509 minsec_label.set_padding (5,0);
510 minsec_label.hide ();
511 minsec_label.set_no_show_all();
512 timecode_label.set_name ("EditorRulerLabel");
513 timecode_label.set_size_request (-1, (int)timebar_height);
514 timecode_label.set_alignment (1.0, 0.5);
515 timecode_label.set_padding (5,0);
516 timecode_label.hide ();
517 timecode_label.set_no_show_all();
518 samples_label.set_name ("EditorRulerLabel");
519 samples_label.set_size_request (-1, (int)timebar_height);
520 samples_label.set_alignment (1.0, 0.5);
521 samples_label.set_padding (5,0);
522 samples_label.hide ();
523 samples_label.set_no_show_all();
525 tempo_label.set_name ("EditorRulerLabel");
526 tempo_label.set_size_request (-1, (int)timebar_height);
527 tempo_label.set_alignment (1.0, 0.5);
528 tempo_label.set_padding (5,0);
530 tempo_label.set_no_show_all();
532 meter_label.set_name ("EditorRulerLabel");
533 meter_label.set_size_request (-1, (int)timebar_height);
534 meter_label.set_alignment (1.0, 0.5);
535 meter_label.set_padding (5,0);
537 meter_label.set_no_show_all();
539 if (Profile->get_trx()) {
540 mark_label.set_text (_("Markers"));
542 mark_label.set_name ("EditorRulerLabel");
543 mark_label.set_size_request (-1, (int)timebar_height);
544 mark_label.set_alignment (1.0, 0.5);
545 mark_label.set_padding (5,0);
547 mark_label.set_no_show_all();
549 cd_mark_label.set_name ("EditorRulerLabel");
550 cd_mark_label.set_size_request (-1, (int)timebar_height);
551 cd_mark_label.set_alignment (1.0, 0.5);
552 cd_mark_label.set_padding (5,0);
553 cd_mark_label.hide();
554 cd_mark_label.set_no_show_all();
556 videotl_bar_height = 4;
557 videotl_label.set_name ("EditorRulerLabel");
558 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
559 videotl_label.set_alignment (1.0, 0.5);
560 videotl_label.set_padding (5,0);
561 videotl_label.hide();
562 videotl_label.set_no_show_all();
564 range_mark_label.set_name ("EditorRulerLabel");
565 range_mark_label.set_size_request (-1, (int)timebar_height);
566 range_mark_label.set_alignment (1.0, 0.5);
567 range_mark_label.set_padding (5,0);
568 range_mark_label.hide();
569 range_mark_label.set_no_show_all();
571 transport_mark_label.set_name ("EditorRulerLabel");
572 transport_mark_label.set_size_request (-1, (int)timebar_height);
573 transport_mark_label.set_alignment (1.0, 0.5);
574 transport_mark_label.set_padding (5,0);
575 transport_mark_label.hide();
576 transport_mark_label.set_no_show_all();
578 initialize_canvas ();
580 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
582 _summary = new EditorSummary (this);
584 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
586 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
588 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
589 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
591 edit_controls_vbox.set_spacing (0);
592 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
593 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
595 HBox* h = manage (new HBox);
596 _group_tabs = new EditorGroupTabs (this);
597 if (!ARDOUR::Profile->get_trx()) {
598 h->pack_start (*_group_tabs, PACK_SHRINK);
600 h->pack_start (edit_controls_vbox);
601 controls_layout.add (*h);
603 controls_layout.set_name ("EditControlsBase");
604 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
605 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
606 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
608 _cursors = new MouseCursors;
609 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
610 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
612 /* Push default cursor to ever-present bottom of cursor stack. */
613 push_canvas_cursor(_cursors->grabber);
615 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
617 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
618 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
619 pad_line_1->set_outline_color (0xFF0000FF);
625 edit_packer.set_col_spacings (0);
626 edit_packer.set_row_spacings (0);
627 edit_packer.set_homogeneous (false);
628 edit_packer.set_border_width (0);
629 edit_packer.set_name ("EditorWindow");
631 time_bars_event_box.add (time_bars_vbox);
632 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
633 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
635 /* labels for the time bars */
636 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
638 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
640 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
642 bottom_hbox.set_border_width (2);
643 bottom_hbox.set_spacing (3);
645 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
647 _route_groups = new EditorRouteGroups (this);
648 _routes = new EditorRoutes (this);
649 _regions = new EditorRegions (this);
650 _snapshots = new EditorSnapshots (this);
651 _locations = new EditorLocations (this);
652 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
654 /* these are static location signals */
656 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
657 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
658 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
660 add_notebook_page (_("Regions"), _regions->widget ());
661 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
662 add_notebook_page (_("Snapshots"), _snapshots->widget ());
663 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
664 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
666 _the_notebook.set_show_tabs (true);
667 _the_notebook.set_scrollable (true);
668 _the_notebook.popup_disable ();
669 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
670 _the_notebook.show_all ();
672 _notebook_shrunk = false;
675 /* Pick up some settings we need to cache, early */
677 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
680 settings->get_property ("notebook-shrunk", _notebook_shrunk);
683 editor_summary_pane.set_check_divider_position (true);
684 editor_summary_pane.add (edit_packer);
686 Button* summary_arrows_left_left = manage (new Button);
687 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
688 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
689 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 Button* summary_arrows_left_right = manage (new Button);
692 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
693 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
694 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
696 VBox* summary_arrows_left = manage (new VBox);
697 summary_arrows_left->pack_start (*summary_arrows_left_left);
698 summary_arrows_left->pack_start (*summary_arrows_left_right);
700 Button* summary_arrows_right_up = manage (new Button);
701 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
702 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
703 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 Button* summary_arrows_right_down = manage (new Button);
706 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
707 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
708 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
710 VBox* summary_arrows_right = manage (new VBox);
711 summary_arrows_right->pack_start (*summary_arrows_right_up);
712 summary_arrows_right->pack_start (*summary_arrows_right_down);
714 Frame* summary_frame = manage (new Frame);
715 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
717 summary_frame->add (*_summary);
718 summary_frame->show ();
720 _summary_hbox.pack_start (*summary_arrows_left, false, false);
721 _summary_hbox.pack_start (*summary_frame, true, true);
722 _summary_hbox.pack_start (*summary_arrows_right, false, false);
724 if (!ARDOUR::Profile->get_trx()) {
725 editor_summary_pane.add (_summary_hbox);
728 edit_pane.set_check_divider_position (true);
729 edit_pane.add (editor_summary_pane);
730 if (!ARDOUR::Profile->get_trx()) {
731 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
732 _editor_list_vbox.pack_start (_the_notebook);
733 edit_pane.add (_editor_list_vbox);
734 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
737 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
738 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
745 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
746 /* initial allocation is 90% to canvas, 10% to notebook */
749 edit_pane.set_divider (0, fract);
751 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
752 /* initial allocation is 90% to canvas, 10% to summary */
755 editor_summary_pane.set_divider (0, fract);
758 global_vpacker.set_spacing (2);
759 global_vpacker.set_border_width (0);
761 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
763 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
764 ebox->set_name("EditorWindow");
765 ebox->add (toolbar_hbox);
767 Gtk::EventBox* epane_box = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
768 epane_box->set_name("EditorWindow");
769 epane_box->add (edit_pane);
771 Gtk::EventBox* epane_box2 = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
772 epane_box2->set_name("EditorWindow");
773 epane_box2->add (global_vpacker);
775 global_vpacker.pack_start (*ebox, false, false);
776 global_vpacker.pack_start (*epane_box, true, true);
777 global_hpacker.pack_start (*epane_box2, true, true);
779 /* need to show the "contents" widget so that notebook will show if tab is switched to
782 global_hpacker.show ();
784 /* register actions now so that set_state() can find them and set toggles/checks etc */
791 _playlist_selector = new PlaylistSelector();
792 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
794 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
798 nudge_forward_button.set_name ("nudge button");
799 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
801 nudge_backward_button.set_name ("nudge button");
802 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
804 fade_context_menu.set_name ("ArdourContextMenu");
806 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
808 /* allow external control surfaces/protocols to do various things */
810 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
811 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
812 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
813 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
814 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
815 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
816 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
817 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
818 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
819 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
820 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
821 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
822 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
823 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
825 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
826 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
827 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
828 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
829 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
831 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
835 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
837 /* problematic: has to return a value and thus cannot be x-thread */
839 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
841 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
842 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
844 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
846 _ignore_region_action = false;
847 _last_region_menu_was_main = false;
848 _popup_region_menu_item = 0;
850 _show_marker_lines = false;
852 /* Button bindings */
854 button_bindings = new Bindings ("editor-mouse");
856 XMLNode* node = button_settings();
858 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
859 button_bindings->load_operation (**i);
865 /* grab current parameter state */
866 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
867 UIConfiguration::instance().map_parameters (pc);
869 setup_fade_images ();
876 delete button_bindings;
878 delete _route_groups;
879 delete _track_canvas_viewport;
882 delete _verbose_cursor;
883 delete quantize_dialog;
889 delete _playlist_selector;
890 delete _time_info_box;
895 LuaInstance::destroy_instance ();
897 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
900 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
903 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
909 Editor::button_settings () const
911 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
912 XMLNode* node = find_named_node (*settings, X_("Buttons"));
915 node = new XMLNode (X_("Buttons"));
922 Editor::get_smart_mode () const
924 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
928 Editor::catch_vanishing_regionview (RegionView *rv)
930 /* note: the selection will take care of the vanishing
931 audioregionview by itself.
934 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
938 if (clicked_regionview == rv) {
939 clicked_regionview = 0;
942 if (entered_regionview == rv) {
943 set_entered_regionview (0);
946 if (!_all_region_actions_sensitized) {
947 sensitize_all_region_actions (true);
952 Editor::set_entered_regionview (RegionView* rv)
954 if (rv == entered_regionview) {
958 if (entered_regionview) {
959 entered_regionview->exited ();
962 entered_regionview = rv;
964 if (entered_regionview != 0) {
965 entered_regionview->entered ();
968 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
969 /* This RegionView entry might have changed what region actions
970 are allowed, so sensitize them all in case a key is pressed.
972 sensitize_all_region_actions (true);
977 Editor::set_entered_track (TimeAxisView* tav)
980 entered_track->exited ();
986 entered_track->entered ();
991 Editor::instant_save ()
993 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
998 _session->add_instant_xml(get_state());
1000 Config->add_instant_xml(get_state());
1005 Editor::control_vertical_zoom_in_all ()
1007 tav_zoom_smooth (false, true);
1011 Editor::control_vertical_zoom_out_all ()
1013 tav_zoom_smooth (true, true);
1017 Editor::control_vertical_zoom_in_selected ()
1019 tav_zoom_smooth (false, false);
1023 Editor::control_vertical_zoom_out_selected ()
1025 tav_zoom_smooth (true, false);
1029 Editor::control_view (uint32_t view)
1031 goto_visual_state (view);
1035 Editor::control_unselect ()
1037 selection->clear_tracks ();
1041 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1043 TimeAxisView* tav = time_axis_view_from_stripable (s);
1047 case Selection::Add:
1048 selection->add (tav);
1050 case Selection::Toggle:
1051 selection->toggle (tav);
1053 case Selection::Extend:
1055 case Selection::Set:
1056 selection->set (tav);
1060 selection->clear_tracks ();
1065 Editor::control_step_tracks_up ()
1067 scroll_tracks_up_line ();
1071 Editor::control_step_tracks_down ()
1073 scroll_tracks_down_line ();
1077 Editor::control_scroll (float fraction)
1079 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1085 double step = fraction * current_page_samples();
1088 _control_scroll_target is an optional<T>
1090 it acts like a pointer to an framepos_t, with
1091 a operator conversion to boolean to check
1092 that it has a value could possibly use
1093 playhead_cursor->current_frame to store the
1094 value and a boolean in the class to know
1095 when it's out of date
1098 if (!_control_scroll_target) {
1099 _control_scroll_target = _session->transport_frame();
1100 _dragging_playhead = true;
1103 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1104 *_control_scroll_target = 0;
1105 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1106 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1108 *_control_scroll_target += (framepos_t) trunc (step);
1111 /* move visuals, we'll catch up with it later */
1113 playhead_cursor->set_position (*_control_scroll_target);
1114 UpdateAllTransportClocks (*_control_scroll_target);
1116 if (*_control_scroll_target > (current_page_samples() / 2)) {
1117 /* try to center PH in window */
1118 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1124 Now we do a timeout to actually bring the session to the right place
1125 according to the playhead. This is to avoid reading disk buffers on every
1126 call to control_scroll, which is driven by ScrollTimeline and therefore
1127 probably by a control surface wheel which can generate lots of events.
1129 /* cancel the existing timeout */
1131 control_scroll_connection.disconnect ();
1133 /* add the next timeout */
1135 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1139 Editor::deferred_control_scroll (framepos_t /*target*/)
1141 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1142 // reset for next stream
1143 _control_scroll_target = boost::none;
1144 _dragging_playhead = false;
1149 Editor::access_action (std::string action_group, std::string action_item)
1155 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1158 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1166 Editor::on_realize ()
1170 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1171 start_lock_event_timing ();
1176 Editor::start_lock_event_timing ()
1178 /* check if we should lock the GUI every 30 seconds */
1180 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1184 Editor::generic_event_handler (GdkEvent* ev)
1187 case GDK_BUTTON_PRESS:
1188 case GDK_BUTTON_RELEASE:
1189 case GDK_MOTION_NOTIFY:
1191 case GDK_KEY_RELEASE:
1192 if (contents().is_mapped()) {
1193 gettimeofday (&last_event_time, 0);
1197 case GDK_LEAVE_NOTIFY:
1198 switch (ev->crossing.detail) {
1199 case GDK_NOTIFY_UNKNOWN:
1200 case GDK_NOTIFY_INFERIOR:
1201 case GDK_NOTIFY_ANCESTOR:
1203 case GDK_NOTIFY_VIRTUAL:
1204 case GDK_NOTIFY_NONLINEAR:
1205 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1206 /* leaving window, so reset focus, thus ending any and
1207 all text entry operations.
1209 ARDOUR_UI::instance()->reset_focus (&contents());
1222 Editor::lock_timeout_callback ()
1224 struct timeval now, delta;
1226 gettimeofday (&now, 0);
1228 timersub (&now, &last_event_time, &delta);
1230 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1232 /* don't call again. Returning false will effectively
1233 disconnect us from the timer callback.
1235 unlock() will call start_lock_event_timing() to get things
1245 Editor::map_position_change (framepos_t frame)
1247 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1249 if (_session == 0) {
1253 if (_follow_playhead) {
1254 center_screen (frame);
1257 playhead_cursor->set_position (frame);
1261 Editor::center_screen (framepos_t frame)
1263 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1265 /* if we're off the page, then scroll.
1268 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1269 center_screen_internal (frame, page);
1274 Editor::center_screen_internal (framepos_t frame, float page)
1279 frame -= (framepos_t) page;
1284 reset_x_origin (frame);
1289 Editor::update_title ()
1291 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1293 if (!own_window()) {
1298 bool dirty = _session->dirty();
1300 string session_name;
1302 if (_session->snap_name() != _session->name()) {
1303 session_name = _session->snap_name();
1305 session_name = _session->name();
1309 session_name = "*" + session_name;
1312 WindowTitle title(session_name);
1313 title += S_("Window|Editor");
1314 title += Glib::get_application_name();
1315 own_window()->set_title (title.get_string());
1317 /* ::session_going_away() will have taken care of it */
1322 Editor::set_session (Session *t)
1324 SessionHandlePtr::set_session (t);
1330 _playlist_selector->set_session (_session);
1331 nudge_clock->set_session (_session);
1332 _summary->set_session (_session);
1333 _group_tabs->set_session (_session);
1334 _route_groups->set_session (_session);
1335 _regions->set_session (_session);
1336 _snapshots->set_session (_session);
1337 _routes->set_session (_session);
1338 _locations->set_session (_session);
1339 _time_info_box->set_session (_session);
1341 if (rhythm_ferret) {
1342 rhythm_ferret->set_session (_session);
1345 if (analysis_window) {
1346 analysis_window->set_session (_session);
1350 sfbrowser->set_session (_session);
1353 compute_fixed_ruler_scale ();
1355 /* Make sure we have auto loop and auto punch ranges */
1357 Location* loc = _session->locations()->auto_loop_location();
1359 loc->set_name (_("Loop"));
1362 loc = _session->locations()->auto_punch_location();
1365 loc->set_name (_("Punch"));
1368 refresh_location_display ();
1370 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1371 the selected Marker; this needs the LocationMarker list to be available.
1373 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1374 set_state (*node, Stateful::loading_state_version);
1376 /* catch up on selection state, etc. */
1379 sc.add (Properties::selected);
1380 presentation_info_changed (sc);
1382 /* catch up with the playhead */
1384 _session->request_locate (playhead_cursor->current_frame ());
1385 _pending_initial_locate = true;
1389 /* These signals can all be emitted by a non-GUI thread. Therefore the
1390 handlers for them must not attempt to directly interact with the GUI,
1391 but use PBD::Signal<T>::connect() which accepts an event loop
1392 ("context") where the handler will be asked to run.
1395 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1396 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1397 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1398 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1399 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1400 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1401 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1402 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1403 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1404 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1405 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1406 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1407 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1408 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1409 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1410 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1412 playhead_cursor->show ();
1414 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1415 Config->map_parameters (pc);
1416 _session->config.map_parameters (pc);
1418 restore_ruler_visibility ();
1419 //tempo_map_changed (PropertyChange (0));
1420 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1422 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1423 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1426 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1427 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1430 switch (_snap_type) {
1431 case SnapToRegionStart:
1432 case SnapToRegionEnd:
1433 case SnapToRegionSync:
1434 case SnapToRegionBoundary:
1435 build_region_boundary_cache ();
1442 /* register for undo history */
1443 _session->register_with_memento_command_factory(id(), this);
1444 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1446 LuaInstance::instance()->set_session(_session);
1448 start_updating_meters ();
1452 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1454 using namespace Menu_Helpers;
1456 void (Editor::*emf)(FadeShape);
1457 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1460 images = &_xfade_in_images;
1461 emf = &Editor::set_fade_in_shape;
1463 images = &_xfade_out_images;
1464 emf = &Editor::set_fade_out_shape;
1469 _("Linear (for highly correlated material)"),
1470 *(*images)[FadeLinear],
1471 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1475 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 _("Constant power"),
1480 *(*images)[FadeConstantPower],
1481 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1484 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1489 *(*images)[FadeSymmetric],
1490 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1494 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 *(*images)[FadeSlow],
1500 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1503 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1508 *(*images)[FadeFast],
1509 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1512 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1515 /** Pop up a context menu for when the user clicks on a start crossfade */
1517 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1519 using namespace Menu_Helpers;
1520 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1525 MenuList& items (xfade_in_context_menu.items());
1528 if (arv->audio_region()->fade_in_active()) {
1529 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1531 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1534 items.push_back (SeparatorElem());
1535 fill_xfade_menu (items, true);
1537 xfade_in_context_menu.popup (button, time);
1540 /** Pop up a context menu for when the user clicks on an end crossfade */
1542 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1544 using namespace Menu_Helpers;
1545 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1550 MenuList& items (xfade_out_context_menu.items());
1553 if (arv->audio_region()->fade_out_active()) {
1554 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1556 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1559 items.push_back (SeparatorElem());
1560 fill_xfade_menu (items, false);
1562 xfade_out_context_menu.popup (button, time);
1566 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1568 using namespace Menu_Helpers;
1569 Menu* (Editor::*build_menu_function)();
1572 switch (item_type) {
1574 case RegionViewName:
1575 case RegionViewNameHighlight:
1576 case LeftFrameHandle:
1577 case RightFrameHandle:
1578 if (with_selection) {
1579 build_menu_function = &Editor::build_track_selection_context_menu;
1581 build_menu_function = &Editor::build_track_region_context_menu;
1586 if (with_selection) {
1587 build_menu_function = &Editor::build_track_selection_context_menu;
1589 build_menu_function = &Editor::build_track_context_menu;
1594 if (clicked_routeview->track()) {
1595 build_menu_function = &Editor::build_track_context_menu;
1597 build_menu_function = &Editor::build_track_bus_context_menu;
1602 /* probably shouldn't happen but if it does, we don't care */
1606 menu = (this->*build_menu_function)();
1607 menu->set_name ("ArdourContextMenu");
1609 /* now handle specific situations */
1611 switch (item_type) {
1613 case RegionViewName:
1614 case RegionViewNameHighlight:
1615 case LeftFrameHandle:
1616 case RightFrameHandle:
1617 if (!with_selection) {
1618 if (region_edit_menu_split_item) {
1619 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1620 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1622 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1625 if (region_edit_menu_split_multichannel_item) {
1626 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1627 region_edit_menu_split_multichannel_item->set_sensitive (true);
1629 region_edit_menu_split_multichannel_item->set_sensitive (false);
1642 /* probably shouldn't happen but if it does, we don't care */
1646 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1648 /* Bounce to disk */
1650 using namespace Menu_Helpers;
1651 MenuList& edit_items = menu->items();
1653 edit_items.push_back (SeparatorElem());
1655 switch (clicked_routeview->audio_track()->freeze_state()) {
1656 case AudioTrack::NoFreeze:
1657 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1660 case AudioTrack::Frozen:
1661 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1664 case AudioTrack::UnFrozen:
1665 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1671 if (item_type == StreamItem && clicked_routeview) {
1672 clicked_routeview->build_underlay_menu(menu);
1675 /* When the region menu is opened, we setup the actions so that they look right
1678 sensitize_the_right_region_actions (false);
1679 _last_region_menu_was_main = false;
1681 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1682 menu->popup (button, time);
1686 Editor::build_track_context_menu ()
1688 using namespace Menu_Helpers;
1690 MenuList& edit_items = track_context_menu.items();
1693 add_dstream_context_items (edit_items);
1694 return &track_context_menu;
1698 Editor::build_track_bus_context_menu ()
1700 using namespace Menu_Helpers;
1702 MenuList& edit_items = track_context_menu.items();
1705 add_bus_context_items (edit_items);
1706 return &track_context_menu;
1710 Editor::build_track_region_context_menu ()
1712 using namespace Menu_Helpers;
1713 MenuList& edit_items = track_region_context_menu.items();
1716 /* we've just cleared the track region context menu, so the menu that these
1717 two items were on will have disappeared; stop them dangling.
1719 region_edit_menu_split_item = 0;
1720 region_edit_menu_split_multichannel_item = 0;
1722 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1725 boost::shared_ptr<Track> tr;
1726 boost::shared_ptr<Playlist> pl;
1728 if ((tr = rtv->track())) {
1729 add_region_context_items (edit_items, tr);
1733 add_dstream_context_items (edit_items);
1735 return &track_region_context_menu;
1739 Editor::loudness_analyze_region_selection ()
1744 Selection& s (PublicEditor::instance ().get_selection ());
1745 RegionSelection ars = s.regions;
1746 ARDOUR::AnalysisGraph ag (_session);
1747 framecnt_t total_work = 0;
1749 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1750 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1754 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1757 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1758 total_work += arv->region ()->length ();
1761 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1763 ag.set_total_frames (total_work);
1764 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1767 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1768 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1772 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1776 ag.analyze_region (ar);
1779 if (!ag.canceled ()) {
1780 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1786 Editor::loudness_analyze_range_selection ()
1791 Selection& s (PublicEditor::instance ().get_selection ());
1792 TimeSelection ts = s.time;
1793 ARDOUR::AnalysisGraph ag (_session);
1794 framecnt_t total_work = 0;
1796 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1797 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1801 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1805 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1806 total_work += j->length ();
1810 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1812 ag.set_total_frames (total_work);
1813 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1816 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1817 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1821 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1825 ag.analyze_range (rui->route (), pl, ts);
1828 if (!ag.canceled ()) {
1829 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1835 Editor::spectral_analyze_region_selection ()
1837 if (analysis_window == 0) {
1838 analysis_window = new AnalysisWindow();
1841 analysis_window->set_session(_session);
1843 analysis_window->show_all();
1846 analysis_window->set_regionmode();
1847 analysis_window->analyze();
1849 analysis_window->present();
1853 Editor::spectral_analyze_range_selection()
1855 if (analysis_window == 0) {
1856 analysis_window = new AnalysisWindow();
1859 analysis_window->set_session(_session);
1861 analysis_window->show_all();
1864 analysis_window->set_rangemode();
1865 analysis_window->analyze();
1867 analysis_window->present();
1871 Editor::build_track_selection_context_menu ()
1873 using namespace Menu_Helpers;
1874 MenuList& edit_items = track_selection_context_menu.items();
1875 edit_items.clear ();
1877 add_selection_context_items (edit_items);
1878 // edit_items.push_back (SeparatorElem());
1879 // add_dstream_context_items (edit_items);
1881 return &track_selection_context_menu;
1885 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1887 using namespace Menu_Helpers;
1889 /* OK, stick the region submenu at the top of the list, and then add
1893 RegionSelection rs = get_regions_from_selection_and_entered ();
1895 string::size_type pos = 0;
1896 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1898 /* we have to hack up the region name because "_" has a special
1899 meaning for menu titles.
1902 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1903 menu_item_name.replace (pos, 1, "__");
1907 if (_popup_region_menu_item == 0) {
1908 _popup_region_menu_item = new MenuItem (menu_item_name);
1909 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1910 _popup_region_menu_item->show ();
1912 _popup_region_menu_item->set_label (menu_item_name);
1915 /* No layering allowed in later is higher layering model */
1916 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1917 if (act && Config->get_layer_model() == LaterHigher) {
1918 act->set_sensitive (false);
1920 act->set_sensitive (true);
1923 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1925 edit_items.push_back (*_popup_region_menu_item);
1926 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1927 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1929 edit_items.push_back (SeparatorElem());
1932 /** Add context menu items relevant to selection ranges.
1933 * @param edit_items List to add the items to.
1936 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1938 using namespace Menu_Helpers;
1940 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1941 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1943 edit_items.push_back (SeparatorElem());
1944 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1946 edit_items.push_back (SeparatorElem());
1947 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1948 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1950 edit_items.push_back (SeparatorElem());
1952 edit_items.push_back (
1954 _("Move Range Start to Previous Region Boundary"),
1955 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1959 edit_items.push_back (
1961 _("Move Range Start to Next Region Boundary"),
1962 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1966 edit_items.push_back (
1968 _("Move Range End to Previous Region Boundary"),
1969 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1973 edit_items.push_back (
1975 _("Move Range End to Next Region Boundary"),
1976 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1982 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1984 edit_items.push_back (SeparatorElem());
1985 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1987 edit_items.push_back (SeparatorElem());
1988 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1989 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1990 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1992 edit_items.push_back (SeparatorElem());
1993 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1995 edit_items.push_back (SeparatorElem());
1996 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1997 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1999 edit_items.push_back (SeparatorElem());
2000 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
2001 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
2002 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
2003 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
2004 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2005 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2006 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2012 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2014 using namespace Menu_Helpers;
2018 Menu *play_menu = manage (new Menu);
2019 MenuList& play_items = play_menu->items();
2020 play_menu->set_name ("ArdourContextMenu");
2022 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2023 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2024 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2025 play_items.push_back (SeparatorElem());
2026 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2028 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2032 Menu *select_menu = manage (new Menu);
2033 MenuList& select_items = select_menu->items();
2034 select_menu->set_name ("ArdourContextMenu");
2036 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2037 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2038 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2039 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2040 select_items.push_back (SeparatorElem());
2041 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2042 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2043 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2044 select_items.push_back (SeparatorElem());
2045 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2046 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2047 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2048 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2049 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2050 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2051 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2053 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2057 Menu *cutnpaste_menu = manage (new Menu);
2058 MenuList& cutnpaste_items = cutnpaste_menu->items();
2059 cutnpaste_menu->set_name ("ArdourContextMenu");
2061 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2062 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2063 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2065 cutnpaste_items.push_back (SeparatorElem());
2067 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2068 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2070 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2072 /* Adding new material */
2074 edit_items.push_back (SeparatorElem());
2075 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2076 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2080 Menu *nudge_menu = manage (new Menu());
2081 MenuList& nudge_items = nudge_menu->items();
2082 nudge_menu->set_name ("ArdourContextMenu");
2084 edit_items.push_back (SeparatorElem());
2085 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2086 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2087 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2088 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2090 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2094 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2096 using namespace Menu_Helpers;
2100 Menu *play_menu = manage (new Menu);
2101 MenuList& play_items = play_menu->items();
2102 play_menu->set_name ("ArdourContextMenu");
2104 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2105 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2106 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2110 Menu *select_menu = manage (new Menu);
2111 MenuList& select_items = select_menu->items();
2112 select_menu->set_name ("ArdourContextMenu");
2114 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2115 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2116 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2117 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2118 select_items.push_back (SeparatorElem());
2119 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2120 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2121 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2122 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2124 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2128 Menu *cutnpaste_menu = manage (new Menu);
2129 MenuList& cutnpaste_items = cutnpaste_menu->items();
2130 cutnpaste_menu->set_name ("ArdourContextMenu");
2132 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2133 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2134 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2136 Menu *nudge_menu = manage (new Menu());
2137 MenuList& nudge_items = nudge_menu->items();
2138 nudge_menu->set_name ("ArdourContextMenu");
2140 edit_items.push_back (SeparatorElem());
2141 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2142 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2143 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2144 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2146 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2150 Editor::snap_type() const
2156 Editor::snap_musical() const
2158 switch (_snap_type) {
2159 case SnapToBeatDiv128:
2160 case SnapToBeatDiv64:
2161 case SnapToBeatDiv32:
2162 case SnapToBeatDiv28:
2163 case SnapToBeatDiv24:
2164 case SnapToBeatDiv20:
2165 case SnapToBeatDiv16:
2166 case SnapToBeatDiv14:
2167 case SnapToBeatDiv12:
2168 case SnapToBeatDiv10:
2169 case SnapToBeatDiv8:
2170 case SnapToBeatDiv7:
2171 case SnapToBeatDiv6:
2172 case SnapToBeatDiv5:
2173 case SnapToBeatDiv4:
2174 case SnapToBeatDiv3:
2175 case SnapToBeatDiv2:
2187 Editor::snap_mode() const
2193 Editor::set_snap_to (SnapType st)
2195 unsigned int snap_ind = (unsigned int)st;
2197 if (internal_editing()) {
2198 internal_snap_type = st;
2200 pre_internal_snap_type = st;
2205 if (snap_ind > snap_type_strings.size() - 1) {
2207 _snap_type = (SnapType)snap_ind;
2210 string str = snap_type_strings[snap_ind];
2212 if (str != snap_type_selector.get_text()) {
2213 snap_type_selector.set_text (str);
2218 switch (_snap_type) {
2219 case SnapToBeatDiv128:
2220 case SnapToBeatDiv64:
2221 case SnapToBeatDiv32:
2222 case SnapToBeatDiv28:
2223 case SnapToBeatDiv24:
2224 case SnapToBeatDiv20:
2225 case SnapToBeatDiv16:
2226 case SnapToBeatDiv14:
2227 case SnapToBeatDiv12:
2228 case SnapToBeatDiv10:
2229 case SnapToBeatDiv8:
2230 case SnapToBeatDiv7:
2231 case SnapToBeatDiv6:
2232 case SnapToBeatDiv5:
2233 case SnapToBeatDiv4:
2234 case SnapToBeatDiv3:
2235 case SnapToBeatDiv2: {
2236 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2237 update_tempo_based_rulers ();
2241 case SnapToRegionStart:
2242 case SnapToRegionEnd:
2243 case SnapToRegionSync:
2244 case SnapToRegionBoundary:
2245 build_region_boundary_cache ();
2253 redisplay_tempo (false);
2255 SnapChanged (); /* EMIT SIGNAL */
2259 Editor::set_snap_mode (SnapMode mode)
2261 string str = snap_mode_strings[(int)mode];
2263 if (internal_editing()) {
2264 internal_snap_mode = mode;
2266 pre_internal_snap_mode = mode;
2271 if (str != snap_mode_selector.get_text ()) {
2272 snap_mode_selector.set_text (str);
2279 Editor::set_edit_point_preference (EditPoint ep, bool force)
2281 bool changed = (_edit_point != ep);
2284 if (Profile->get_mixbus())
2285 if (ep == EditAtSelectedMarker)
2286 ep = EditAtPlayhead;
2288 string str = edit_point_strings[(int)ep];
2289 if (str != edit_point_selector.get_text ()) {
2290 edit_point_selector.set_text (str);
2293 update_all_enter_cursors();
2295 if (!force && !changed) {
2299 const char* action=NULL;
2301 switch (_edit_point) {
2302 case EditAtPlayhead:
2303 action = "edit-at-playhead";
2305 case EditAtSelectedMarker:
2306 action = "edit-at-marker";
2309 action = "edit-at-mouse";
2313 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2315 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2319 bool in_track_canvas;
2321 if (!mouse_frame (foo, in_track_canvas)) {
2322 in_track_canvas = false;
2325 reset_canvas_action_sensitivity (in_track_canvas);
2326 sensitize_the_right_region_actions (false);
2332 Editor::set_state (const XMLNode& node, int version)
2335 PBD::Unwinder<bool> nsi (no_save_instant, true);
2339 Tabbable::set_state (node, version);
2342 if (_session && node.get_property ("playhead", ph_pos)) {
2344 playhead_cursor->set_position (ph_pos);
2346 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2347 playhead_cursor->set_position (0);
2350 playhead_cursor->set_position (0);
2353 node.get_property ("mixer-width", editor_mixer_strip_width);
2355 node.get_property ("zoom-focus", zoom_focus);
2356 zoom_focus_selection_done (zoom_focus);
2359 if (node.get_property ("zoom", z)) {
2360 /* older versions of ardour used floating point samples_per_pixel */
2361 reset_zoom (llrintf (z));
2363 reset_zoom (samples_per_pixel);
2367 if (node.get_property ("visible-track-count", cnt)) {
2368 set_visible_track_count (cnt);
2372 if (!node.get_property ("snap-to", snap_type)) {
2373 snap_type = _snap_type;
2375 set_snap_to (snap_type);
2378 if (node.get_property ("snap-mode", sm)) {
2379 snap_mode_selection_done(sm);
2380 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2381 * snap_mode_selection_done() will only mark an already active item as active
2382 * which does not trigger set_text().
2386 set_snap_mode (_snap_mode);
2389 node.get_property ("internal-snap-to", internal_snap_type);
2390 node.get_property ("internal-snap-mode", internal_snap_mode);
2391 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2392 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2395 if (node.get_property ("mouse-mode", mm_str)) {
2396 MouseMode m = str2mousemode(mm_str);
2397 set_mouse_mode (m, true);
2399 set_mouse_mode (MouseObject, true);
2403 if (node.get_property ("left-frame", lf_pos)) {
2407 reset_x_origin (lf_pos);
2411 if (node.get_property ("y-origin", y_origin)) {
2412 reset_y_origin (y_origin);
2415 if (node.get_property ("join-object-range", yn)) {
2416 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2418 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2419 tact->set_active (!yn);
2420 tact->set_active (yn);
2422 set_mouse_mode(mouse_mode, true);
2426 if (node.get_property ("edit-point", ep)) {
2427 set_edit_point_preference (ep, true);
2429 set_edit_point_preference (_edit_point);
2432 node.get_property ("show-measures", _show_measures);
2434 if (node.get_property ("follow-playhead", yn)) {
2435 set_follow_playhead (yn);
2438 if (node.get_property ("stationary-playhead", yn)) {
2439 set_stationary_playhead (yn);
2442 RegionListSortType sort_type;
2443 if (node.get_property ("region-list-sort-type", sort_type)) {
2444 _regions->reset_sort_type (sort_type, true);
2447 if (node.get_property ("show-editor-mixer", yn)) {
2449 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2452 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2454 /* do it twice to force the change */
2456 tact->set_active (!yn);
2457 tact->set_active (yn);
2460 if (node.get_property ("show-editor-list", yn)) {
2462 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2465 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2467 /* do it twice to force the change */
2469 tact->set_active (!yn);
2470 tact->set_active (yn);
2474 if (node.get_property (X_("editor-list-page"), el_page)) {
2475 _the_notebook.set_current_page (el_page);
2478 if (node.get_property (X_("show-marker-lines"), yn)) {
2479 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2481 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2483 tact->set_active (!yn);
2484 tact->set_active (yn);
2487 XMLNodeList children = node.children ();
2488 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2489 selection->set_state (**i, Stateful::current_state_version);
2490 _regions->set_state (**i);
2491 _locations->set_state (**i);
2494 if (node.get_property ("maximised", yn)) {
2495 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2497 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2498 bool fs = tact && tact->get_active();
2500 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2504 framepos_t nudge_clock_value;
2505 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2506 nudge_clock->set (nudge_clock_value);
2508 nudge_clock->set_mode (AudioClock::Timecode);
2509 nudge_clock->set (_session->frame_rate() * 5, true);
2514 * Not all properties may have been in XML, but
2515 * those that are linked to a private variable may need changing
2519 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2521 yn = _show_measures;
2522 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2523 /* do it twice to force the change */
2524 tact->set_active (!yn);
2525 tact->set_active (yn);
2528 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2529 yn = _follow_playhead;
2531 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2532 if (tact->get_active() != yn) {
2533 tact->set_active (yn);
2537 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2538 yn = _stationary_playhead;
2540 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2541 if (tact->get_active() != yn) {
2542 tact->set_active (yn);
2547 return LuaInstance::instance()->set_state(node);
2551 Editor::get_state ()
2553 XMLNode* node = new XMLNode (X_("Editor"));
2556 node->set_property ("id", id().to_s ());
2558 node->add_child_nocopy (Tabbable::get_state());
2560 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2561 node->set_property("notebook-shrunk", _notebook_shrunk);
2562 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2564 maybe_add_mixer_strip_width (*node);
2566 node->set_property ("zoom-focus", zoom_focus);
2568 node->set_property ("zoom", samples_per_pixel);
2569 node->set_property ("snap-to", _snap_type);
2570 node->set_property ("snap-mode", _snap_mode);
2571 node->set_property ("internal-snap-to", internal_snap_type);
2572 node->set_property ("internal-snap-mode", internal_snap_mode);
2573 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2574 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2575 node->set_property ("edit-point", _edit_point);
2576 node->set_property ("visible-track-count", _visible_track_count);
2578 node->set_property ("playhead", playhead_cursor->current_frame ());
2579 node->set_property ("left-frame", leftmost_frame);
2580 node->set_property ("y-origin", vertical_adjustment.get_value ());
2582 node->set_property ("show-measures", _show_measures);
2583 node->set_property ("maximised", _maximised);
2584 node->set_property ("follow-playhead", _follow_playhead);
2585 node->set_property ("stationary-playhead", _stationary_playhead);
2586 node->set_property ("region-list-sort-type", _regions->sort_type ());
2587 node->set_property ("mouse-mode", mouse_mode);
2588 node->set_property ("join-object-range", smart_mode_action->get_active ());
2590 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2592 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2593 node->set_property (X_("show-editor-mixer"), tact->get_active());
2596 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2598 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2599 node->set_property (X_("show-editor-list"), tact->get_active());
2602 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2604 if (button_bindings) {
2605 XMLNode* bb = new XMLNode (X_("Buttons"));
2606 button_bindings->save (*bb);
2607 node->add_child_nocopy (*bb);
2610 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2612 node->add_child_nocopy (selection->get_state ());
2613 node->add_child_nocopy (_regions->get_state ());
2615 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2617 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2618 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2619 node->add_child_nocopy (_locations->get_state ());
2624 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2625 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2627 * @return pair: TimeAxisView that y is over, layer index.
2629 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2630 * in stacked or expanded region display mode, otherwise 0.
2632 std::pair<TimeAxisView *, double>
2633 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2635 if (!trackview_relative_offset) {
2636 y -= _trackview_group->canvas_origin().y;
2640 return std::make_pair ( (TimeAxisView *) 0, 0);
2643 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2645 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2652 return std::make_pair ( (TimeAxisView *) 0, 0);
2655 /** Snap a position to the grid, if appropriate, taking into account current
2656 * grid settings and also the state of any snap modifier keys that may be pressed.
2657 * @param start Position to snap.
2658 * @param event Event to get current key modifier information from, or 0.
2661 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2663 if (!_session || !event) {
2667 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2668 if (_snap_mode == SnapOff) {
2669 snap_to_internal (start, direction, for_mark);
2671 start.set (start.frame, 0);
2674 if (_snap_mode != SnapOff) {
2675 snap_to_internal (start, direction, for_mark);
2676 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2677 /* SnapOff, but we pressed the snap_delta modifier */
2678 snap_to_internal (start, direction, for_mark);
2680 start.set (start.frame, 0);
2686 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2688 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2689 start.set (start.frame, 0);
2693 snap_to_internal (start, direction, for_mark, ensure_snap);
2697 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2699 framepos_t start = pos.frame;
2700 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2701 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2703 switch (_snap_type) {
2704 case SnapToTimecodeFrame:
2705 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2706 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2707 /* start is already on a whole timecode frame, do nothing */
2708 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2709 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2711 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2715 case SnapToTimecodeSeconds:
2716 if (_session->config.get_timecode_offset_negative()) {
2717 start += _session->config.get_timecode_offset ();
2719 start -= _session->config.get_timecode_offset ();
2721 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2722 (start % one_timecode_second == 0)) {
2723 /* start is already on a whole second, do nothing */
2724 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2725 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2727 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2730 if (_session->config.get_timecode_offset_negative()) {
2731 start -= _session->config.get_timecode_offset ();
2733 start += _session->config.get_timecode_offset ();
2737 case SnapToTimecodeMinutes:
2738 if (_session->config.get_timecode_offset_negative()) {
2739 start += _session->config.get_timecode_offset ();
2741 start -= _session->config.get_timecode_offset ();
2743 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2744 (start % one_timecode_minute == 0)) {
2745 /* start is already on a whole minute, do nothing */
2746 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2747 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2749 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2751 if (_session->config.get_timecode_offset_negative()) {
2752 start -= _session->config.get_timecode_offset ();
2754 start += _session->config.get_timecode_offset ();
2758 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2759 abort(); /*NOTREACHED*/
2766 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2768 const framepos_t one_second = _session->frame_rate();
2769 const framepos_t one_minute = _session->frame_rate() * 60;
2770 framepos_t presnap = start.frame;
2774 switch (_snap_type) {
2775 case SnapToTimecodeFrame:
2776 case SnapToTimecodeSeconds:
2777 case SnapToTimecodeMinutes:
2778 return timecode_snap_to_internal (start, direction, for_mark);
2781 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2782 start.frame % (one_second/75) == 0) {
2783 /* start is already on a whole CD frame, do nothing */
2784 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2785 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2787 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2790 start.set (start.frame, 0);
2795 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2796 start.frame % one_second == 0) {
2797 /* start is already on a whole second, do nothing */
2798 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2799 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2801 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2804 start.set (start.frame, 0);
2809 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2810 start.frame % one_minute == 0) {
2811 /* start is already on a whole minute, do nothing */
2812 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2813 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2815 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2818 start.set (start.frame, 0);
2823 start = _session->tempo_map().round_to_bar (start.frame, direction);
2827 start = _session->tempo_map().round_to_beat (start.frame, direction);
2830 case SnapToBeatDiv128:
2831 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2833 case SnapToBeatDiv64:
2834 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2836 case SnapToBeatDiv32:
2837 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2839 case SnapToBeatDiv28:
2840 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2842 case SnapToBeatDiv24:
2843 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2845 case SnapToBeatDiv20:
2846 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2848 case SnapToBeatDiv16:
2849 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2851 case SnapToBeatDiv14:
2852 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2854 case SnapToBeatDiv12:
2855 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2857 case SnapToBeatDiv10:
2858 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2860 case SnapToBeatDiv8:
2861 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2863 case SnapToBeatDiv7:
2864 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2866 case SnapToBeatDiv6:
2867 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2869 case SnapToBeatDiv5:
2870 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2872 case SnapToBeatDiv4:
2873 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2875 case SnapToBeatDiv3:
2876 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2878 case SnapToBeatDiv2:
2879 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2887 _session->locations()->marks_either_side (start.frame, before, after);
2889 if (before == max_framepos && after == max_framepos) {
2890 /* No marks to snap to, so just don't snap */
2892 } else if (before == max_framepos) {
2893 start.frame = after;
2894 } else if (after == max_framepos) {
2895 start.frame = before;
2896 } else if (before != max_framepos && after != max_framepos) {
2897 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2898 start.frame = after;
2899 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2900 start.frame = before;
2901 else if (direction == 0 ) {
2902 if ((start.frame - before) < (after - start.frame)) {
2903 start.frame = before;
2905 start.frame = after;
2910 start.set (start.frame, 0);
2914 case SnapToRegionStart:
2915 case SnapToRegionEnd:
2916 case SnapToRegionSync:
2917 case SnapToRegionBoundary:
2918 if (!region_boundary_cache.empty()) {
2920 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2921 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2923 if (direction > 0) {
2924 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2926 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2929 if (next != region_boundary_cache.begin ()) {
2934 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2935 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2937 if (start.frame > (p + n) / 2) {
2944 start.set (start.frame, 0);
2949 switch (_snap_mode) {
2959 if (presnap > start.frame) {
2960 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
2961 start.set (presnap, 0);
2964 } else if (presnap < start.frame) {
2965 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
2966 start.set (presnap, 0);
2971 /* handled at entry */
2978 Editor::setup_toolbar ()
2980 HBox* mode_box = manage(new HBox);
2981 mode_box->set_border_width (2);
2982 mode_box->set_spacing(2);
2984 HBox* mouse_mode_box = manage (new HBox);
2985 HBox* mouse_mode_hbox = manage (new HBox);
2986 VBox* mouse_mode_vbox = manage (new VBox);
2987 Alignment* mouse_mode_align = manage (new Alignment);
2989 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2990 mouse_mode_size_group->add_widget (smart_mode_button);
2991 mouse_mode_size_group->add_widget (mouse_move_button);
2992 mouse_mode_size_group->add_widget (mouse_cut_button);
2993 mouse_mode_size_group->add_widget (mouse_select_button);
2994 mouse_mode_size_group->add_widget (mouse_timefx_button);
2995 mouse_mode_size_group->add_widget (mouse_audition_button);
2996 mouse_mode_size_group->add_widget (mouse_draw_button);
2997 mouse_mode_size_group->add_widget (mouse_content_button);
2999 if (!Profile->get_mixbus()) {
3000 mouse_mode_size_group->add_widget (zoom_in_button);
3001 mouse_mode_size_group->add_widget (zoom_out_button);
3002 mouse_mode_size_group->add_widget (zoom_out_full_button);
3003 mouse_mode_size_group->add_widget (zoom_focus_selector);
3004 mouse_mode_size_group->add_widget (tav_shrink_button);
3005 mouse_mode_size_group->add_widget (tav_expand_button);
3007 mouse_mode_size_group->add_widget (zoom_preset_selector);
3008 mouse_mode_size_group->add_widget (visible_tracks_selector);
3011 mouse_mode_size_group->add_widget (snap_type_selector);
3012 mouse_mode_size_group->add_widget (snap_mode_selector);
3014 mouse_mode_size_group->add_widget (edit_point_selector);
3015 mouse_mode_size_group->add_widget (edit_mode_selector);
3017 mouse_mode_size_group->add_widget (*nudge_clock);
3018 mouse_mode_size_group->add_widget (nudge_forward_button);
3019 mouse_mode_size_group->add_widget (nudge_backward_button);
3021 mouse_mode_hbox->set_spacing (2);
3023 if (!ARDOUR::Profile->get_trx()) {
3024 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3027 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3028 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3030 if (!ARDOUR::Profile->get_mixbus()) {
3031 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3034 if (!ARDOUR::Profile->get_trx()) {
3035 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3036 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3037 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3038 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3041 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3043 mouse_mode_align->add (*mouse_mode_vbox);
3044 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3046 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3048 edit_mode_selector.set_name ("mouse mode button");
3050 if (!ARDOUR::Profile->get_trx()) {
3051 mode_box->pack_start (edit_mode_selector, false, false);
3054 mode_box->pack_start (*mouse_mode_box, false, false);
3058 _zoom_box.set_spacing (2);
3059 _zoom_box.set_border_width (2);
3063 zoom_preset_selector.set_name ("zoom button");
3064 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3066 zoom_in_button.set_name ("zoom button");
3067 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3068 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3069 zoom_in_button.set_related_action (act);
3071 zoom_out_button.set_name ("zoom button");
3072 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3073 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3074 zoom_out_button.set_related_action (act);
3076 zoom_out_full_button.set_name ("zoom button");
3077 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3078 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3079 zoom_out_full_button.set_related_action (act);
3081 zoom_focus_selector.set_name ("zoom button");
3083 if (ARDOUR::Profile->get_mixbus()) {
3084 _zoom_box.pack_start (zoom_preset_selector, false, false);
3085 } else if (ARDOUR::Profile->get_trx()) {
3086 mode_box->pack_start (zoom_out_button, false, false);
3087 mode_box->pack_start (zoom_in_button, false, false);
3089 _zoom_box.pack_start (zoom_out_button, false, false);
3090 _zoom_box.pack_start (zoom_in_button, false, false);
3091 _zoom_box.pack_start (zoom_out_full_button, false, false);
3092 _zoom_box.pack_start (zoom_focus_selector, false, false);
3095 /* Track zoom buttons */
3096 _track_box.set_spacing (2);
3097 _track_box.set_border_width (2);
3099 visible_tracks_selector.set_name ("zoom button");
3100 if (Profile->get_mixbus()) {
3101 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3103 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3106 tav_expand_button.set_name ("zoom button");
3107 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3108 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3109 tav_expand_button.set_related_action (act);
3111 tav_shrink_button.set_name ("zoom button");
3112 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3113 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3114 tav_shrink_button.set_related_action (act);
3116 if (ARDOUR::Profile->get_mixbus()) {
3117 _track_box.pack_start (visible_tracks_selector);
3118 } else if (ARDOUR::Profile->get_trx()) {
3119 _track_box.pack_start (tav_shrink_button);
3120 _track_box.pack_start (tav_expand_button);
3122 _track_box.pack_start (visible_tracks_selector);
3123 _track_box.pack_start (tav_shrink_button);
3124 _track_box.pack_start (tav_expand_button);
3127 snap_box.set_spacing (2);
3128 snap_box.set_border_width (2);
3130 snap_type_selector.set_name ("mouse mode button");
3132 snap_mode_selector.set_name ("mouse mode button");
3134 edit_point_selector.set_name ("mouse mode button");
3136 snap_box.pack_start (snap_mode_selector, false, false);
3137 snap_box.pack_start (snap_type_selector, false, false);
3140 HBox *ep_box = manage (new HBox);
3141 ep_box->set_spacing (2);
3142 ep_box->set_border_width (2);
3144 ep_box->pack_start (edit_point_selector, false, false);
3148 HBox *nudge_box = manage (new HBox);
3149 nudge_box->set_spacing (2);
3150 nudge_box->set_border_width (2);
3152 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3153 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3155 nudge_box->pack_start (nudge_backward_button, false, false);
3156 nudge_box->pack_start (nudge_forward_button, false, false);
3157 nudge_box->pack_start (*nudge_clock, false, false);
3160 /* Pack everything in... */
3162 toolbar_hbox.set_spacing (2);
3163 toolbar_hbox.set_border_width (2);
3165 toolbar_hbox.pack_start (*mode_box, false, false);
3167 if (!ARDOUR::Profile->get_trx()) {
3169 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3171 toolbar_hbox.pack_start (_zoom_box, false, false);
3173 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3175 toolbar_hbox.pack_start (_track_box, false, false);
3177 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3179 toolbar_hbox.pack_start (snap_box, false, false);
3181 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3183 toolbar_hbox.pack_start (*ep_box, false, false);
3185 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3187 toolbar_hbox.pack_start (*nudge_box, false, false);
3190 toolbar_hbox.show_all ();
3194 Editor::build_edit_point_menu ()
3196 using namespace Menu_Helpers;
3198 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3199 if(!Profile->get_mixbus())
3200 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3201 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3203 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3207 Editor::build_edit_mode_menu ()
3209 using namespace Menu_Helpers;
3211 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3212 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3213 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3214 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3216 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3220 Editor::build_snap_mode_menu ()
3222 using namespace Menu_Helpers;
3224 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3225 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3226 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3228 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3232 Editor::build_snap_type_menu ()
3234 using namespace Menu_Helpers;
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3259 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3260 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3261 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3262 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3263 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3264 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3265 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3267 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3272 Editor::setup_tooltips ()
3274 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3275 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3276 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3277 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3278 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3279 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3280 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3281 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3282 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3283 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3284 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3285 set_tooltip (zoom_in_button, _("Zoom In"));
3286 set_tooltip (zoom_out_button, _("Zoom Out"));
3287 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3288 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3289 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3290 set_tooltip (tav_expand_button, _("Expand Tracks"));
3291 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3292 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3293 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3294 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3295 set_tooltip (edit_point_selector, _("Edit Point"));
3296 set_tooltip (edit_mode_selector, _("Edit Mode"));
3297 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3301 Editor::convert_drop_to_paths (
3302 vector<string>& paths,
3303 const RefPtr<Gdk::DragContext>& /*context*/,
3306 const SelectionData& data,
3310 if (_session == 0) {
3314 vector<string> uris = data.get_uris();
3318 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3319 are actually URI lists. So do it by hand.
3322 if (data.get_target() != "text/plain") {
3326 /* Parse the "uri-list" format that Nautilus provides,
3327 where each pathname is delimited by \r\n.
3329 THERE MAY BE NO NULL TERMINATING CHAR!!!
3332 string txt = data.get_text();
3336 p = (char *) malloc (txt.length() + 1);
3337 txt.copy (p, txt.length(), 0);
3338 p[txt.length()] = '\0';
3344 while (g_ascii_isspace (*p))
3348 while (*q && (*q != '\n') && (*q != '\r')) {
3355 while (q > p && g_ascii_isspace (*q))
3360 uris.push_back (string (p, q - p + 1));
3364 p = strchr (p, '\n');
3376 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3377 if ((*i).substr (0,7) == "file://") {
3378 paths.push_back (Glib::filename_from_uri (*i));
3386 Editor::new_tempo_section ()
3391 Editor::map_transport_state ()
3393 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3395 if (_session && _session->transport_stopped()) {
3396 have_pending_keyboard_selection = false;
3399 update_loop_range_view ();
3403 Editor::transport_looped ()
3405 /* reset Playhead position interpolation.
3406 * see Editor::super_rapid_screen_update
3408 _last_update_time = 0;
3414 Editor::begin_selection_op_history ()
3416 selection_op_cmd_depth = 0;
3417 selection_op_history_it = 0;
3419 while(!selection_op_history.empty()) {
3420 delete selection_op_history.front();
3421 selection_op_history.pop_front();
3424 selection_undo_action->set_sensitive (false);
3425 selection_redo_action->set_sensitive (false);
3426 selection_op_history.push_front (&_selection_memento->get_state ());
3430 Editor::begin_reversible_selection_op (string name)
3433 //cerr << name << endl;
3434 /* begin/commit pairs can be nested */
3435 selection_op_cmd_depth++;
3440 Editor::commit_reversible_selection_op ()
3443 if (selection_op_cmd_depth == 1) {
3445 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3447 The user has undone some selection ops and then made a new one,
3448 making anything earlier in the list invalid.
3451 list<XMLNode *>::iterator it = selection_op_history.begin();
3452 list<XMLNode *>::iterator e_it = it;
3453 advance (e_it, selection_op_history_it);
3455 for ( ; it != e_it; ++it) {
3458 selection_op_history.erase (selection_op_history.begin(), e_it);
3461 selection_op_history.push_front (&_selection_memento->get_state ());
3462 selection_op_history_it = 0;
3464 selection_undo_action->set_sensitive (true);
3465 selection_redo_action->set_sensitive (false);
3468 if (selection_op_cmd_depth > 0) {
3469 selection_op_cmd_depth--;
3475 Editor::undo_selection_op ()
3478 selection_op_history_it++;
3480 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3481 if (n == selection_op_history_it) {
3482 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3483 selection_redo_action->set_sensitive (true);
3487 /* is there an earlier entry? */
3488 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3489 selection_undo_action->set_sensitive (false);
3495 Editor::redo_selection_op ()
3498 if (selection_op_history_it > 0) {
3499 selection_op_history_it--;
3502 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3503 if (n == selection_op_history_it) {
3504 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3505 selection_undo_action->set_sensitive (true);
3510 if (selection_op_history_it == 0) {
3511 selection_redo_action->set_sensitive (false);
3517 Editor::begin_reversible_command (string name)
3520 before.push_back (&_selection_memento->get_state ());
3521 _session->begin_reversible_command (name);
3526 Editor::begin_reversible_command (GQuark q)
3529 before.push_back (&_selection_memento->get_state ());
3530 _session->begin_reversible_command (q);
3535 Editor::abort_reversible_command ()
3538 while(!before.empty()) {
3539 delete before.front();
3542 _session->abort_reversible_command ();
3547 Editor::commit_reversible_command ()
3550 if (before.size() == 1) {
3551 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3552 redo_action->set_sensitive(false);
3553 undo_action->set_sensitive(true);
3554 begin_selection_op_history ();
3557 if (before.empty()) {
3558 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3563 _session->commit_reversible_command ();
3568 Editor::history_changed ()
3572 if (undo_action && _session) {
3573 if (_session->undo_depth() == 0) {
3574 label = S_("Command|Undo");
3576 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3578 undo_action->property_label() = label;
3581 if (redo_action && _session) {
3582 if (_session->redo_depth() == 0) {
3584 redo_action->set_sensitive (false);
3586 label = string_compose(_("Redo (%1)"), _session->next_redo());
3587 redo_action->set_sensitive (true);
3589 redo_action->property_label() = label;
3594 Editor::duplicate_range (bool with_dialog)
3598 RegionSelection rs = get_regions_from_selection_and_entered ();
3600 if ( selection->time.length() == 0 && rs.empty()) {
3606 ArdourDialog win (_("Duplicate"));
3607 Label label (_("Number of duplications:"));
3608 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3609 SpinButton spinner (adjustment, 0.0, 1);
3612 win.get_vbox()->set_spacing (12);
3613 win.get_vbox()->pack_start (hbox);
3614 hbox.set_border_width (6);
3615 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3617 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3618 place, visually. so do this by hand.
3621 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3622 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3623 spinner.grab_focus();
3629 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3630 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3631 win.set_default_response (RESPONSE_ACCEPT);
3633 spinner.grab_focus ();
3635 switch (win.run ()) {
3636 case RESPONSE_ACCEPT:
3642 times = adjustment.get_value();
3645 if ((current_mouse_mode() == Editing::MouseRange)) {
3646 if (selection->time.length()) {
3647 duplicate_selection (times);
3649 } else if (get_smart_mode()) {
3650 if (selection->time.length()) {
3651 duplicate_selection (times);
3653 duplicate_some_regions (rs, times);
3655 duplicate_some_regions (rs, times);
3660 Editor::set_edit_mode (EditMode m)
3662 Config->set_edit_mode (m);
3666 Editor::cycle_edit_mode ()
3668 switch (Config->get_edit_mode()) {
3670 Config->set_edit_mode (Ripple);
3674 Config->set_edit_mode (Lock);
3677 Config->set_edit_mode (Slide);
3683 Editor::edit_mode_selection_done ( EditMode m )
3685 Config->set_edit_mode ( m );
3689 Editor::snap_type_selection_done (SnapType snaptype)
3691 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3693 ract->set_active ();
3698 Editor::snap_mode_selection_done (SnapMode mode)
3700 RefPtr<RadioAction> ract = snap_mode_action (mode);
3703 ract->set_active (true);
3708 Editor::cycle_edit_point (bool with_marker)
3710 if(Profile->get_mixbus())
3711 with_marker = false;
3713 switch (_edit_point) {
3715 set_edit_point_preference (EditAtPlayhead);
3717 case EditAtPlayhead:
3719 set_edit_point_preference (EditAtSelectedMarker);
3721 set_edit_point_preference (EditAtMouse);
3724 case EditAtSelectedMarker:
3725 set_edit_point_preference (EditAtMouse);
3731 Editor::edit_point_selection_done (EditPoint ep)
3733 set_edit_point_preference ( ep );
3737 Editor::build_zoom_focus_menu ()
3739 using namespace Menu_Helpers;
3741 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3742 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3743 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3744 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3745 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3746 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3748 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3752 Editor::zoom_focus_selection_done ( ZoomFocus f )
3754 RefPtr<RadioAction> ract = zoom_focus_action (f);
3756 ract->set_active ();
3761 Editor::build_track_count_menu ()
3763 using namespace Menu_Helpers;
3765 if (!Profile->get_mixbus()) {
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3772 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3783 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3784 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3785 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3786 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3787 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3788 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3789 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3792 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3795 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3796 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3797 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3798 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3799 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3800 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3801 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3806 Editor::set_zoom_preset (int64_t ms)
3809 temporal_zoom_session();
3813 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3814 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3818 Editor::set_visible_track_count (int32_t n)
3820 _visible_track_count = n;
3822 /* if the canvas hasn't really been allocated any size yet, just
3823 record the desired number of visible tracks and return. when canvas
3824 allocation happens, we will get called again and then we can do the
3828 if (_visible_canvas_height <= 1) {
3834 DisplaySuspender ds;
3836 if (_visible_track_count > 0) {
3837 h = trackviews_height() / _visible_track_count;
3838 std::ostringstream s;
3839 s << _visible_track_count;
3841 } else if (_visible_track_count == 0) {
3843 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3844 if ((*i)->marked_for_display()) {
3848 h = trackviews_height() / n;
3851 /* negative value means that the visible track count has
3852 been overridden by explicit track height changes.
3854 visible_tracks_selector.set_text (X_("*"));
3858 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3859 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3862 if (str != visible_tracks_selector.get_text()) {
3863 visible_tracks_selector.set_text (str);
3868 Editor::override_visible_track_count ()
3870 _visible_track_count = -1;
3871 visible_tracks_selector.set_text ( _("*") );
3875 Editor::edit_controls_button_release (GdkEventButton* ev)
3877 if (Keyboard::is_context_menu_event (ev)) {
3878 ARDOUR_UI::instance()->add_route ();
3879 } else if (ev->button == 1) {
3880 selection->clear_tracks ();
3887 Editor::mouse_select_button_release (GdkEventButton* ev)
3889 /* this handles just right-clicks */
3891 if (ev->button != 3) {
3899 Editor::set_zoom_focus (ZoomFocus f)
3901 string str = zoom_focus_strings[(int)f];
3903 if (str != zoom_focus_selector.get_text()) {
3904 zoom_focus_selector.set_text (str);
3907 if (zoom_focus != f) {
3914 Editor::cycle_zoom_focus ()
3916 switch (zoom_focus) {
3918 set_zoom_focus (ZoomFocusRight);
3920 case ZoomFocusRight:
3921 set_zoom_focus (ZoomFocusCenter);
3923 case ZoomFocusCenter:
3924 set_zoom_focus (ZoomFocusPlayhead);
3926 case ZoomFocusPlayhead:
3927 set_zoom_focus (ZoomFocusMouse);
3929 case ZoomFocusMouse:
3930 set_zoom_focus (ZoomFocusEdit);
3933 set_zoom_focus (ZoomFocusLeft);
3939 Editor::set_show_measures (bool yn)
3941 if (_show_measures != yn) {
3944 if ((_show_measures = yn) == true) {
3946 tempo_lines->show();
3949 std::vector<TempoMap::BBTPoint> grid;
3950 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3951 draw_measures (grid);
3959 Editor::toggle_follow_playhead ()
3961 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3963 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3964 set_follow_playhead (tact->get_active());
3968 /** @param yn true to follow playhead, otherwise false.
3969 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3972 Editor::set_follow_playhead (bool yn, bool catch_up)
3974 if (_follow_playhead != yn) {
3975 if ((_follow_playhead = yn) == true && catch_up) {
3977 reset_x_origin_to_follow_playhead ();
3984 Editor::toggle_stationary_playhead ()
3986 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3988 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3989 set_stationary_playhead (tact->get_active());
3994 Editor::set_stationary_playhead (bool yn)
3996 if (_stationary_playhead != yn) {
3997 if ((_stationary_playhead = yn) == true) {
3999 // FIXME need a 3.0 equivalent of this 2.X call
4000 // update_current_screen ();
4007 Editor::playlist_selector () const
4009 return *_playlist_selector;
4013 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4015 if (paste_count == 0) {
4016 /* don't bother calculating an offset that will be zero anyway */
4020 /* calculate basic unsnapped multi-paste offset */
4021 framecnt_t offset = paste_count * duration;
4023 /* snap offset so pos + offset is aligned to the grid */
4024 MusicFrame offset_pos (pos + offset, 0);
4025 snap_to(offset_pos, RoundUpMaybe);
4026 offset = offset_pos.frame - pos;
4032 Editor::get_grid_beat_divisions(framepos_t position)
4034 switch (_snap_type) {
4035 case SnapToBeatDiv128: return 128;
4036 case SnapToBeatDiv64: return 64;
4037 case SnapToBeatDiv32: return 32;
4038 case SnapToBeatDiv28: return 28;
4039 case SnapToBeatDiv24: return 24;
4040 case SnapToBeatDiv20: return 20;
4041 case SnapToBeatDiv16: return 16;
4042 case SnapToBeatDiv14: return 14;
4043 case SnapToBeatDiv12: return 12;
4044 case SnapToBeatDiv10: return 10;
4045 case SnapToBeatDiv8: return 8;
4046 case SnapToBeatDiv7: return 7;
4047 case SnapToBeatDiv6: return 6;
4048 case SnapToBeatDiv5: return 5;
4049 case SnapToBeatDiv4: return 4;
4050 case SnapToBeatDiv3: return 3;
4051 case SnapToBeatDiv2: return 2;
4057 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4058 if the grid is non-musical, returns 0.
4059 if the grid is snapped to bars, returns -1.
4060 @param event_state the current keyboard modifier mask.
4063 Editor::get_grid_music_divisions (uint32_t event_state)
4065 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4069 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4073 switch (_snap_type) {
4074 case SnapToBeatDiv128: return 128;
4075 case SnapToBeatDiv64: return 64;
4076 case SnapToBeatDiv32: return 32;
4077 case SnapToBeatDiv28: return 28;
4078 case SnapToBeatDiv24: return 24;
4079 case SnapToBeatDiv20: return 20;
4080 case SnapToBeatDiv16: return 16;
4081 case SnapToBeatDiv14: return 14;
4082 case SnapToBeatDiv12: return 12;
4083 case SnapToBeatDiv10: return 10;
4084 case SnapToBeatDiv8: return 8;
4085 case SnapToBeatDiv7: return 7;
4086 case SnapToBeatDiv6: return 6;
4087 case SnapToBeatDiv5: return 5;
4088 case SnapToBeatDiv4: return 4;
4089 case SnapToBeatDiv3: return 3;
4090 case SnapToBeatDiv2: return 2;
4091 case SnapToBeat: return 1;
4092 case SnapToBar : return -1;
4099 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4103 const unsigned divisions = get_grid_beat_divisions(position);
4105 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4108 switch (_snap_type) {
4110 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4113 const Meter& m = _session->tempo_map().meter_at_frame (position);
4114 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4122 return Evoral::Beats();
4126 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4130 ret = nudge_clock->current_duration (pos);
4131 next = ret + 1; /* XXXX fix me */
4137 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4139 ArdourDialog dialog (_("Playlist Deletion"));
4140 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4141 "If it is kept, its audio files will not be cleaned.\n"
4142 "If it is deleted, audio files used by it alone will be cleaned."),
4145 dialog.set_position (WIN_POS_CENTER);
4146 dialog.get_vbox()->pack_start (label);
4150 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4151 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4152 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4153 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4154 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4156 // by default gtk uses the left most button
4157 keep->grab_focus ();
4159 switch (dialog.run ()) {
4161 /* keep this and all remaining ones */
4166 /* delete this and all others */
4170 case RESPONSE_ACCEPT:
4171 /* delete the playlist */
4175 case RESPONSE_REJECT:
4176 /* keep the playlist */
4188 Editor::audio_region_selection_covers (framepos_t where)
4190 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4191 if ((*a)->region()->covers (where)) {
4200 Editor::prepare_for_cleanup ()
4202 cut_buffer->clear_regions ();
4203 cut_buffer->clear_playlists ();
4205 selection->clear_regions ();
4206 selection->clear_playlists ();
4208 _regions->suspend_redisplay ();
4212 Editor::finish_cleanup ()
4214 _regions->resume_redisplay ();
4218 Editor::transport_loop_location()
4221 return _session->locations()->auto_loop_location();
4228 Editor::transport_punch_location()
4231 return _session->locations()->auto_punch_location();
4238 Editor::control_layout_scroll (GdkEventScroll* ev)
4240 /* Just forward to the normal canvas scroll method. The coordinate
4241 systems are different but since the canvas is always larger than the
4242 track headers, and aligned with the trackview area, this will work.
4244 In the not too distant future this layout is going away anyway and
4245 headers will be on the canvas.
4247 return canvas_scroll_event (ev, false);
4251 Editor::session_state_saved (string)
4254 _snapshots->redisplay ();
4258 Editor::maximise_editing_space ()
4264 Gtk::Window* toplevel = current_toplevel();
4267 toplevel->fullscreen ();
4273 Editor::restore_editing_space ()
4279 Gtk::Window* toplevel = current_toplevel();
4282 toplevel->unfullscreen();
4288 * Make new playlists for a given track and also any others that belong
4289 * to the same active route group with the `select' property.
4294 Editor::new_playlists (TimeAxisView* v)
4296 begin_reversible_command (_("new playlists"));
4297 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4298 _session->playlists->get (playlists);
4299 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4300 commit_reversible_command ();
4304 * Use a copy of the current playlist for a given track and also any others that belong
4305 * to the same active route group with the `select' property.
4310 Editor::copy_playlists (TimeAxisView* v)
4312 begin_reversible_command (_("copy playlists"));
4313 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4314 _session->playlists->get (playlists);
4315 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4316 commit_reversible_command ();
4319 /** Clear the current playlist for a given track and also any others that belong
4320 * to the same active route group with the `select' property.
4325 Editor::clear_playlists (TimeAxisView* v)
4327 begin_reversible_command (_("clear playlists"));
4328 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4329 _session->playlists->get (playlists);
4330 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4331 commit_reversible_command ();
4335 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4337 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4341 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4343 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4347 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4349 atv.clear_playlist ();
4353 Editor::get_y_origin () const
4355 return vertical_adjustment.get_value ();
4358 /** Queue up a change to the viewport x origin.
4359 * @param frame New x origin.
4362 Editor::reset_x_origin (framepos_t frame)
4364 pending_visual_change.add (VisualChange::TimeOrigin);
4365 pending_visual_change.time_origin = frame;
4366 ensure_visual_change_idle_handler ();
4370 Editor::reset_y_origin (double y)
4372 pending_visual_change.add (VisualChange::YOrigin);
4373 pending_visual_change.y_origin = y;
4374 ensure_visual_change_idle_handler ();
4378 Editor::reset_zoom (framecnt_t spp)
4380 if (spp == samples_per_pixel) {
4384 pending_visual_change.add (VisualChange::ZoomLevel);
4385 pending_visual_change.samples_per_pixel = spp;
4386 ensure_visual_change_idle_handler ();
4390 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4392 reset_x_origin (frame);
4395 if (!no_save_visual) {
4396 undo_visual_stack.push_back (current_visual_state(false));
4400 Editor::VisualState::VisualState (bool with_tracks)
4401 : gui_state (with_tracks ? new GUIObjectState : 0)
4405 Editor::VisualState::~VisualState ()
4410 Editor::VisualState*
4411 Editor::current_visual_state (bool with_tracks)
4413 VisualState* vs = new VisualState (with_tracks);
4414 vs->y_position = vertical_adjustment.get_value();
4415 vs->samples_per_pixel = samples_per_pixel;
4416 vs->leftmost_frame = leftmost_frame;
4417 vs->zoom_focus = zoom_focus;
4420 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4427 Editor::undo_visual_state ()
4429 if (undo_visual_stack.empty()) {
4433 VisualState* vs = undo_visual_stack.back();
4434 undo_visual_stack.pop_back();
4437 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4440 use_visual_state (*vs);
4445 Editor::redo_visual_state ()
4447 if (redo_visual_stack.empty()) {
4451 VisualState* vs = redo_visual_stack.back();
4452 redo_visual_stack.pop_back();
4454 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4455 // why do we check here?
4456 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4459 use_visual_state (*vs);
4464 Editor::swap_visual_state ()
4466 if (undo_visual_stack.empty()) {
4467 redo_visual_state ();
4469 undo_visual_state ();
4474 Editor::use_visual_state (VisualState& vs)
4476 PBD::Unwinder<bool> nsv (no_save_visual, true);
4477 DisplaySuspender ds;
4479 vertical_adjustment.set_value (vs.y_position);
4481 set_zoom_focus (vs.zoom_focus);
4482 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4485 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4487 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4488 (*i)->clear_property_cache();
4489 (*i)->reset_visual_state ();
4493 _routes->update_visibility ();
4496 /** This is the core function that controls the zoom level of the canvas. It is called
4497 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4498 * @param spp new number of samples per pixel
4501 Editor::set_samples_per_pixel (framecnt_t spp)
4507 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4508 const framecnt_t lots_of_pixels = 4000;
4510 /* if the zoom level is greater than what you'd get trying to display 3
4511 * days of audio on a really big screen, then it's too big.
4514 if (spp * lots_of_pixels > three_days) {
4518 samples_per_pixel = spp;
4521 tempo_lines->tempo_map_changed();
4524 bool const showing_time_selection = selection->time.length() > 0;
4526 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4527 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4528 (*i)->reshow_selection (selection->time);
4532 ZoomChanged (); /* EMIT_SIGNAL */
4534 ArdourCanvas::GtkCanvasViewport* c;
4536 c = get_track_canvas();
4538 c->canvas()->zoomed ();
4541 if (playhead_cursor) {
4542 playhead_cursor->set_position (playhead_cursor->current_frame ());
4545 refresh_location_display();
4546 _summary->set_overlays_dirty ();
4548 update_marker_labels ();
4554 Editor::playhead_cursor_sample () const
4556 return playhead_cursor->current_frame();
4560 Editor::queue_visual_videotimeline_update ()
4563 * pending_visual_change.add (VisualChange::VideoTimeline);
4564 * or maybe even more specific: which videotimeline-image
4565 * currently it calls update_video_timeline() to update
4566 * _all outdated_ images on the video-timeline.
4567 * see 'exposeimg()' in video_image_frame.cc
4569 ensure_visual_change_idle_handler ();
4573 Editor::ensure_visual_change_idle_handler ()
4575 if (pending_visual_change.idle_handler_id < 0) {
4576 // see comment in add_to_idle_resize above.
4577 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4578 pending_visual_change.being_handled = false;
4583 Editor::_idle_visual_changer (void* arg)
4585 return static_cast<Editor*>(arg)->idle_visual_changer ();
4589 Editor::idle_visual_changer ()
4591 /* set_horizontal_position() below (and maybe other calls) call
4592 gtk_main_iteration(), so it's possible that a signal will be handled
4593 half-way through this method. If this signal wants an
4594 idle_visual_changer we must schedule another one after this one, so
4595 mark the idle_handler_id as -1 here to allow that. Also make a note
4596 that we are doing the visual change, so that changes in response to
4597 super-rapid-screen-update can be dropped if we are still processing
4601 pending_visual_change.idle_handler_id = -1;
4602 pending_visual_change.being_handled = true;
4604 VisualChange vc = pending_visual_change;
4606 pending_visual_change.pending = (VisualChange::Type) 0;
4608 visual_changer (vc);
4610 pending_visual_change.being_handled = false;
4612 return 0; /* this is always a one-shot call */
4616 Editor::visual_changer (const VisualChange& vc)
4618 double const last_time_origin = horizontal_position ();
4620 if (vc.pending & VisualChange::ZoomLevel) {
4621 set_samples_per_pixel (vc.samples_per_pixel);
4623 compute_fixed_ruler_scale ();
4625 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4626 update_tempo_based_rulers ();
4628 update_video_timeline();
4631 if (vc.pending & VisualChange::TimeOrigin) {
4632 set_horizontal_position (sample_to_pixel_unrounded (vc.time_origin));
4635 if (vc.pending & VisualChange::YOrigin) {
4636 vertical_adjustment.set_value (vc.y_origin);
4639 if (last_time_origin == horizontal_position ()) {
4640 /* changed signal not emitted */
4641 update_fixed_rulers ();
4642 redisplay_tempo (true);
4645 if (!(vc.pending & VisualChange::ZoomLevel)) {
4646 update_video_timeline();
4649 _summary->set_overlays_dirty ();
4652 struct EditorOrderTimeAxisSorter {
4653 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4654 return a->order () < b->order ();
4659 Editor::sort_track_selection (TrackViewList& sel)
4661 EditorOrderTimeAxisSorter cmp;
4666 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4669 framepos_t where = 0;
4670 EditPoint ep = _edit_point;
4672 if (Profile->get_mixbus()) {
4673 if (ep == EditAtSelectedMarker) {
4674 ep = EditAtPlayhead;
4678 if (from_outside_canvas && (ep == EditAtMouse)) {
4679 ep = EditAtPlayhead;
4680 } else if (from_context_menu && (ep == EditAtMouse)) {
4681 return canvas_event_sample (&context_click_event, 0, 0);
4684 if (entered_marker) {
4685 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4686 return entered_marker->position();
4689 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4690 ep = EditAtSelectedMarker;
4693 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4694 ep = EditAtPlayhead;
4697 MusicFrame snap_mf (0, 0);
4700 case EditAtPlayhead:
4701 if (_dragging_playhead && _control_scroll_target) {
4702 where = *_control_scroll_target;
4704 where = _session->audible_frame();
4706 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4709 case EditAtSelectedMarker:
4710 if (!selection->markers.empty()) {
4712 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4715 where = loc->start();
4719 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4727 if (!mouse_frame (where, ignored)) {
4728 /* XXX not right but what can we do ? */
4731 snap_mf.frame = where;
4733 where = snap_mf.frame;
4734 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4742 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4744 if (!_session) return;
4746 begin_reversible_command (cmd);
4750 if ((tll = transport_loop_location()) == 0) {
4751 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4752 XMLNode &before = _session->locations()->get_state();
4753 _session->locations()->add (loc, true);
4754 _session->set_auto_loop_location (loc);
4755 XMLNode &after = _session->locations()->get_state();
4756 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4758 XMLNode &before = tll->get_state();
4759 tll->set_hidden (false, this);
4760 tll->set (start, end);
4761 XMLNode &after = tll->get_state();
4762 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4765 commit_reversible_command ();
4769 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4771 if (!_session) return;
4773 begin_reversible_command (cmd);
4777 if ((tpl = transport_punch_location()) == 0) {
4778 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4779 XMLNode &before = _session->locations()->get_state();
4780 _session->locations()->add (loc, true);
4781 _session->set_auto_punch_location (loc);
4782 XMLNode &after = _session->locations()->get_state();
4783 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4785 XMLNode &before = tpl->get_state();
4786 tpl->set_hidden (false, this);
4787 tpl->set (start, end);
4788 XMLNode &after = tpl->get_state();
4789 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4792 commit_reversible_command ();
4795 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4796 * @param rs List to which found regions are added.
4797 * @param where Time to look at.
4798 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4801 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4803 const TrackViewList* tracks;
4806 tracks = &track_views;
4811 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4813 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4816 boost::shared_ptr<Track> tr;
4817 boost::shared_ptr<Playlist> pl;
4819 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4821 boost::shared_ptr<RegionList> regions = pl->regions_at (
4822 (framepos_t) floor ( (double) where * tr->speed()));
4824 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4825 RegionView* rv = rtv->view()->find_view (*i);
4836 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4838 const TrackViewList* tracks;
4841 tracks = &track_views;
4846 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4847 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4849 boost::shared_ptr<Track> tr;
4850 boost::shared_ptr<Playlist> pl;
4852 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4854 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4855 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4857 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4859 RegionView* rv = rtv->view()->find_view (*i);
4870 /** Get regions using the following method:
4872 * Make a region list using:
4873 * (a) any selected regions
4874 * (b) the intersection of any selected tracks and the edit point(*)
4875 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4877 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4879 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4883 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4885 RegionSelection regions;
4887 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4888 regions.add (entered_regionview);
4890 regions = selection->regions;
4893 if ( regions.empty() ) {
4894 TrackViewList tracks = selection->tracks;
4896 if (!tracks.empty()) {
4897 /* no region selected or entered, but some selected tracks:
4898 * act on all regions on the selected tracks at the edit point
4900 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4901 get_regions_at(regions, where, tracks);
4908 /** Get regions using the following method:
4910 * Make a region list using:
4911 * (a) any selected regions
4912 * (b) the intersection of any selected tracks and the edit point(*)
4913 * (c) if neither exists, then whatever region is under the mouse
4915 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4917 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4920 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4922 RegionSelection regions;
4924 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4925 regions.add (entered_regionview);
4927 regions = selection->regions;
4930 if ( regions.empty() ) {
4931 TrackViewList tracks = selection->tracks;
4933 if (!tracks.empty()) {
4934 /* no region selected or entered, but some selected tracks:
4935 * act on all regions on the selected tracks at the edit point
4937 get_regions_at(regions, pos, tracks);
4944 /** Start with regions that are selected, or the entered regionview if none are selected.
4945 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4946 * of the regions that we started with.
4950 Editor::get_regions_from_selection_and_entered () const
4952 RegionSelection regions = selection->regions;
4954 if (regions.empty() && entered_regionview) {
4955 regions.add (entered_regionview);
4962 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4964 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4965 RouteTimeAxisView* rtav;
4967 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4968 boost::shared_ptr<Playlist> pl;
4969 std::vector<boost::shared_ptr<Region> > results;
4970 boost::shared_ptr<Track> tr;
4972 if ((tr = rtav->track()) == 0) {
4977 if ((pl = (tr->playlist())) != 0) {
4978 boost::shared_ptr<Region> r = pl->region_by_id (id);
4980 RegionView* rv = rtav->view()->find_view (r);
4982 regions.push_back (rv);
4991 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4994 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4995 MidiTimeAxisView* mtav;
4997 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4999 mtav->get_per_region_note_selection (selection);
5006 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5008 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5010 RouteTimeAxisView* tatv;
5012 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5014 boost::shared_ptr<Playlist> pl;
5015 vector<boost::shared_ptr<Region> > results;
5017 boost::shared_ptr<Track> tr;
5019 if ((tr = tatv->track()) == 0) {
5024 if ((pl = (tr->playlist())) != 0) {
5025 if (src_comparison) {
5026 pl->get_source_equivalent_regions (region, results);
5028 pl->get_region_list_equivalent_regions (region, results);
5032 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5033 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5034 regions.push_back (marv);
5043 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5045 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5046 RouteTimeAxisView* tatv;
5047 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5048 if (!tatv->track()) {
5051 RegionView* marv = tatv->view()->find_view (region);
5061 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5063 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5064 RouteTimeAxisView* rtav;
5065 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5066 if (rtav->route() == route) {
5075 Editor::show_rhythm_ferret ()
5077 if (rhythm_ferret == 0) {
5078 rhythm_ferret = new RhythmFerret(*this);
5081 rhythm_ferret->set_session (_session);
5082 rhythm_ferret->show ();
5083 rhythm_ferret->present ();
5087 Editor::first_idle ()
5089 MessageDialog* dialog = 0;
5091 if (track_views.size() > 1) {
5092 Timers::TimerSuspender t;
5093 dialog = new MessageDialog (
5094 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5098 ARDOUR_UI::instance()->flush_pending (60);
5101 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5105 /* now that all regionviews should exist, setup region selection */
5109 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5110 /* this is cumulative: rs is NOT cleared each time */
5111 get_regionviews_by_id (*pr, rs);
5114 selection->set (rs);
5116 // first idle adds route children (automation tracks), so we need to redisplay here
5117 _routes->redisplay ();
5121 if (_session->undo_depth() == 0) {
5122 undo_action->set_sensitive(false);
5124 redo_action->set_sensitive(false);
5125 begin_selection_op_history ();
5131 Editor::_idle_resize (gpointer arg)
5133 return ((Editor*)arg)->idle_resize ();
5137 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5139 if (resize_idle_id < 0) {
5140 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5141 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5142 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5144 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5145 _pending_resize_amount = 0;
5148 /* make a note of the smallest resulting height, so that we can clamp the
5149 lower limit at TimeAxisView::hSmall */
5151 int32_t min_resulting = INT32_MAX;
5153 _pending_resize_amount += h;
5154 _pending_resize_view = view;
5156 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5158 if (selection->tracks.contains (_pending_resize_view)) {
5159 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5160 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5164 if (min_resulting < 0) {
5169 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5170 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5174 /** Handle pending resizing of tracks */
5176 Editor::idle_resize ()
5178 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5180 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5181 selection->tracks.contains (_pending_resize_view)) {
5183 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5184 if (*i != _pending_resize_view) {
5185 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5190 _pending_resize_amount = 0;
5191 _group_tabs->set_dirty ();
5192 resize_idle_id = -1;
5200 ENSURE_GUI_THREAD (*this, &Editor::located);
5203 playhead_cursor->set_position (_session->audible_frame ());
5204 if (_follow_playhead && !_pending_initial_locate) {
5205 reset_x_origin_to_follow_playhead ();
5209 _pending_locate_request = false;
5210 _pending_initial_locate = false;
5211 _last_update_time = 0;
5215 Editor::region_view_added (RegionView * rv)
5217 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5219 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5220 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5221 if (rv->region()->id () == (*rnote).first) {
5222 mrv->select_notes ((*rnote).second);
5223 selection->pending_midi_note_selection.erase(rnote);
5229 _summary->set_background_dirty ();
5233 Editor::region_view_removed ()
5235 _summary->set_background_dirty ();
5239 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5241 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5242 if ((*j)->stripable() == s) {
5251 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5253 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5254 if ((*j)->control() == c) {
5258 TimeAxisView::Children kids = (*j)->get_child_list ();
5260 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5261 if ((*k)->control() == c) {
5271 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5275 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5276 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5286 Editor::suspend_route_redisplay ()
5289 _routes->suspend_redisplay();
5294 Editor::resume_route_redisplay ()
5297 _routes->redisplay(); // queue redisplay
5298 _routes->resume_redisplay();
5303 Editor::add_vcas (VCAList& vlist)
5307 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5308 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5311 add_stripables (sl);
5315 Editor::add_routes (RouteList& rlist)
5319 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5323 add_stripables (sl);
5327 Editor::add_stripables (StripableList& sl)
5329 list<TimeAxisView*> new_views;
5330 boost::shared_ptr<VCA> v;
5331 boost::shared_ptr<Route> r;
5332 TrackViewList new_selection;
5333 bool from_scratch = (track_views.size() == 0);
5335 sl.sort (StripablePresentationInfoSorter());
5337 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5339 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5341 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5343 new_views.push_back (vtv);
5345 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5347 if (r->is_auditioner() || r->is_monitor()) {
5351 RouteTimeAxisView* rtv;
5352 DataType dt = r->input()->default_type();
5354 if (dt == ARDOUR::DataType::AUDIO) {
5355 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5357 } else if (dt == ARDOUR::DataType::MIDI) {
5358 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5361 throw unknown_type();
5364 new_views.push_back (rtv);
5365 track_views.push_back (rtv);
5366 new_selection.push_back (rtv);
5368 rtv->effective_gain_display ();
5370 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5371 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5375 if (new_views.size() > 0) {
5376 _routes->time_axis_views_added (new_views);
5377 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5380 /* note: !new_selection.empty() means that we got some routes rather
5384 if (!from_scratch && !new_selection.empty()) {
5385 selection->set (new_selection);
5386 begin_selection_op_history();
5389 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5390 show_editor_mixer (true);
5393 editor_list_button.set_sensitive (true);
5397 Editor::timeaxisview_deleted (TimeAxisView *tv)
5399 if (tv == entered_track) {
5403 if (_session && _session->deletion_in_progress()) {
5404 /* the situation is under control */
5408 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5410 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5412 _routes->route_removed (tv);
5414 TimeAxisView::Children c = tv->get_child_list ();
5415 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5416 if (entered_track == i->get()) {
5421 /* remove it from the list of track views */
5423 TrackViewList::iterator i;
5425 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5426 i = track_views.erase (i);
5429 /* update whatever the current mixer strip is displaying, if revelant */
5431 boost::shared_ptr<Route> route;
5434 route = rtav->route ();
5437 if (current_mixer_strip && current_mixer_strip->route() == route) {
5439 TimeAxisView* next_tv;
5441 if (track_views.empty()) {
5443 } else if (i == track_views.end()) {
5444 next_tv = track_views.front();
5449 // skip VCAs (cannot be selected, n/a in editor-mixer)
5450 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5451 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5452 next_tv = track_views.front();
5454 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5455 /* just in case: no master, only a VCA remains */
5461 set_selected_mixer_strip (*next_tv);
5463 /* make the editor mixer strip go away setting the
5464 * button to inactive (which also unticks the menu option)
5467 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5473 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5478 if (apply_to_selection) {
5479 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5481 TrackSelection::iterator j = i;
5484 hide_track_in_display (*i, false);
5489 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5491 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5492 // this will hide the mixer strip
5493 set_selected_mixer_strip (*tv);
5496 _routes->hide_track_in_display (*tv);
5501 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5506 _routes->show_track_in_display (*tv);
5507 if (move_into_view) {
5508 ensure_time_axis_view_is_visible (*tv, false);
5513 Editor::sync_track_view_list_and_routes ()
5515 track_views = TrackViewList (_routes->views ());
5517 _summary->set_background_dirty();
5518 _group_tabs->set_dirty ();
5520 return false; // do not call again (until needed)
5524 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5526 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5531 /** Find a RouteTimeAxisView by the ID of its route */
5533 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5535 RouteTimeAxisView* v;
5537 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5538 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5539 if(v->route()->id() == id) {
5549 Editor::fit_route_group (RouteGroup *g)
5551 TrackViewList ts = axis_views_from_routes (g->route_list ());
5556 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5558 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5561 _session->cancel_audition ();
5565 if (_session->is_auditioning()) {
5566 _session->cancel_audition ();
5567 if (r == last_audition_region) {
5572 _session->audition_region (r);
5573 last_audition_region = r;
5578 Editor::hide_a_region (boost::shared_ptr<Region> r)
5580 r->set_hidden (true);
5584 Editor::show_a_region (boost::shared_ptr<Region> r)
5586 r->set_hidden (false);
5590 Editor::audition_region_from_region_list ()
5592 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5596 Editor::hide_region_from_region_list ()
5598 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5602 Editor::show_region_in_region_list ()
5604 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5608 Editor::step_edit_status_change (bool yn)
5611 start_step_editing ();
5613 stop_step_editing ();
5618 Editor::start_step_editing ()
5620 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5624 Editor::stop_step_editing ()
5626 step_edit_connection.disconnect ();
5630 Editor::check_step_edit ()
5632 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5633 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5635 mtv->check_step_edit ();
5639 return true; // do it again, till we stop
5643 Editor::scroll_press (Direction dir)
5645 ++_scroll_callbacks;
5647 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5648 /* delay the first auto-repeat */
5654 scroll_backward (1);
5662 scroll_up_one_track ();
5666 scroll_down_one_track ();
5670 /* do hacky auto-repeat */
5671 if (!_scroll_connection.connected ()) {
5673 _scroll_connection = Glib::signal_timeout().connect (
5674 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5677 _scroll_callbacks = 0;
5684 Editor::scroll_release ()
5686 _scroll_connection.disconnect ();
5689 /** Queue a change for the Editor viewport x origin to follow the playhead */
5691 Editor::reset_x_origin_to_follow_playhead ()
5693 framepos_t const frame = playhead_cursor->current_frame ();
5695 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5697 if (_session->transport_speed() < 0) {
5699 if (frame > (current_page_samples() / 2)) {
5700 center_screen (frame-(current_page_samples()/2));
5702 center_screen (current_page_samples()/2);
5709 if (frame < leftmost_frame) {
5711 if (_session->transport_rolling()) {
5712 /* rolling; end up with the playhead at the right of the page */
5713 l = frame - current_page_samples ();
5715 /* not rolling: end up with the playhead 1/4 of the way along the page */
5716 l = frame - current_page_samples() / 4;
5720 if (_session->transport_rolling()) {
5721 /* rolling: end up with the playhead on the left of the page */
5724 /* not rolling: end up with the playhead 3/4 of the way along the page */
5725 l = frame - 3 * current_page_samples() / 4;
5733 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5739 Editor::super_rapid_screen_update ()
5741 if (!_session || !_session->engine().running()) {
5745 /* METERING / MIXER STRIPS */
5747 /* update track meters, if required */
5748 if (contents().is_mapped() && meters_running) {
5749 RouteTimeAxisView* rtv;
5750 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5751 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5752 rtv->fast_update ();
5757 /* and any current mixer strip */
5758 if (current_mixer_strip) {
5759 current_mixer_strip->fast_update ();
5762 /* PLAYHEAD AND VIEWPORT */
5764 /* There are a few reasons why we might not update the playhead / viewport stuff:
5766 * 1. we don't update things when there's a pending locate request, otherwise
5767 * when the editor requests a locate there is a chance that this method
5768 * will move the playhead before the locate request is processed, causing
5770 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5771 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5773 if (_pending_locate_request || !_session->transport_rolling ()) {
5774 _last_update_time = 0;
5778 if (_dragging_playhead) {
5779 _last_update_time = 0;
5783 bool latent_locate = false;
5784 framepos_t frame = _session->audible_frame (&latent_locate);
5785 const int64_t now = g_get_monotonic_time ();
5788 if (_last_update_time > 0) {
5789 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
5790 framepos_t guess = playhead_cursor->current_frame () + rint (ds);
5791 err = frame - guess;
5793 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5794 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5797 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5799 err, _err_screen_engine);
5804 _err_screen_engine = 0;
5807 if (err > 8192 || latent_locate) {
5808 // in case of x-runs or freewheeling
5809 _last_update_time = 0;
5811 _last_update_time = now;
5814 if (playhead_cursor->current_frame () == frame) {
5818 playhead_cursor->set_position (frame);
5820 if (_session->requested_return_frame() >= 0) {
5821 _last_update_time = 0;
5825 if (!_follow_playhead || pending_visual_change.being_handled) {
5826 /* We only do this if we aren't already
5827 * handling a visual change (ie if
5828 * pending_visual_change.being_handled is
5829 * false) so that these requests don't stack
5830 * up there are too many of them to handle in
5836 if (!_stationary_playhead) {
5837 reset_x_origin_to_follow_playhead ();
5839 framepos_t const frame = playhead_cursor->current_frame ();
5840 double target = ((double)frame - (double)current_page_samples() / 2.0);
5841 if (target <= 0.0) {
5844 // compare to EditorCursor::set_position()
5845 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5846 double const new_pos = sample_to_pixel_unrounded (target);
5847 if (rint (new_pos) != rint (old_pos)) {
5848 reset_x_origin (pixel_to_sample (new_pos));
5855 Editor::session_going_away ()
5857 _have_idled = false;
5859 _session_connections.drop_connections ();
5861 super_rapid_screen_update_connection.disconnect ();
5863 selection->clear ();
5864 cut_buffer->clear ();
5866 clicked_regionview = 0;
5867 clicked_axisview = 0;
5868 clicked_routeview = 0;
5869 entered_regionview = 0;
5871 _last_update_time = 0;
5874 playhead_cursor->hide ();
5876 /* rip everything out of the list displays */
5880 _route_groups->clear ();
5882 /* do this first so that deleting a track doesn't reset cms to null
5883 and thus cause a leak.
5886 if (current_mixer_strip) {
5887 if (current_mixer_strip->get_parent() != 0) {
5888 global_hpacker.remove (*current_mixer_strip);
5890 delete current_mixer_strip;
5891 current_mixer_strip = 0;
5894 /* delete all trackviews */
5896 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5899 track_views.clear ();
5901 nudge_clock->set_session (0);
5903 editor_list_button.set_active(false);
5904 editor_list_button.set_sensitive(false);
5906 /* clear tempo/meter rulers */
5907 remove_metric_marks ();
5909 clear_marker_display ();
5911 stop_step_editing ();
5915 /* get rid of any existing editor mixer strip */
5917 WindowTitle title(Glib::get_application_name());
5918 title += _("Editor");
5920 own_window()->set_title (title.get_string());
5923 SessionHandlePtr::session_going_away ();
5927 Editor::trigger_script (int i)
5929 LuaInstance::instance()-> call_action (i);
5933 Editor::show_editor_list (bool yn)
5936 _editor_list_vbox.show ();
5938 _editor_list_vbox.hide ();
5943 Editor::change_region_layering_order (bool from_context_menu)
5945 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5947 if (!clicked_routeview) {
5948 if (layering_order_editor) {
5949 layering_order_editor->hide ();
5954 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5960 boost::shared_ptr<Playlist> pl = track->playlist();
5966 if (layering_order_editor == 0) {
5967 layering_order_editor = new RegionLayeringOrderEditor (*this);
5970 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5971 layering_order_editor->maybe_present ();
5975 Editor::update_region_layering_order_editor ()
5977 if (layering_order_editor && layering_order_editor->is_visible ()) {
5978 change_region_layering_order (true);
5983 Editor::setup_fade_images ()
5985 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5986 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5987 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5988 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5989 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5991 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5992 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5993 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5994 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5995 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5999 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6001 Editor::action_menu_item (std::string const & name)
6003 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6006 return *manage (a->create_menu_item ());
6010 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6012 EventBox* b = manage (new EventBox);
6013 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6014 Label* l = manage (new Label (name));
6018 _the_notebook.append_page (widget, *b);
6022 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6024 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6025 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6028 if (ev->type == GDK_2BUTTON_PRESS) {
6030 /* double-click on a notebook tab shrinks or expands the notebook */
6032 if (_notebook_shrunk) {
6033 if (pre_notebook_shrink_pane_width) {
6034 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6036 _notebook_shrunk = false;
6038 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6040 /* this expands the LHS of the edit pane to cover the notebook
6041 PAGE but leaves the tabs visible.
6043 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6044 _notebook_shrunk = true;
6052 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6054 using namespace Menu_Helpers;
6056 MenuList& items = _control_point_context_menu.items ();
6059 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6060 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6061 if (!can_remove_control_point (item)) {
6062 items.back().set_sensitive (false);
6065 _control_point_context_menu.popup (event->button.button, event->button.time);
6069 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6071 using namespace Menu_Helpers;
6073 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6078 /* We need to get the selection here and pass it to the operations, since
6079 popping up the menu will cause a region leave event which clears
6080 entered_regionview. */
6082 MidiRegionView& mrv = note->region_view();
6083 const RegionSelection rs = get_regions_from_selection_and_entered ();
6084 const uint32_t sel_size = mrv.selection_size ();
6086 MenuList& items = _note_context_menu.items();
6090 items.push_back(MenuElem(_("Delete"),
6091 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6094 items.push_back(MenuElem(_("Edit..."),
6095 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6096 if (sel_size != 1) {
6097 items.back().set_sensitive (false);
6100 items.push_back(MenuElem(_("Transpose..."),
6101 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6104 items.push_back(MenuElem(_("Legatize"),
6105 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6107 items.back().set_sensitive (false);
6110 items.push_back(MenuElem(_("Quantize..."),
6111 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6113 items.push_back(MenuElem(_("Remove Overlap"),
6114 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6116 items.back().set_sensitive (false);
6119 items.push_back(MenuElem(_("Transform..."),
6120 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6122 _note_context_menu.popup (event->button.button, event->button.time);
6126 Editor::zoom_vertical_modifier_released()
6128 _stepping_axis_view = 0;
6132 Editor::ui_parameter_changed (string parameter)
6134 if (parameter == "icon-set") {
6135 while (!_cursor_stack.empty()) {
6136 _cursor_stack.pop_back();
6138 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6139 _cursor_stack.push_back(_cursors->grabber);
6140 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6141 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6143 } else if (parameter == "draggable-playhead") {
6144 if (_verbose_cursor) {
6145 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6151 Editor::use_own_window (bool and_fill_it)
6153 bool new_window = !own_window();
6155 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6157 if (win && new_window) {
6158 win->set_name ("EditorWindow");
6160 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6162 // win->signal_realize().connect (*this, &Editor::on_realize);
6163 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6164 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6165 win->set_data ("ardour-bindings", bindings);
6170 DisplaySuspender ds;
6171 contents().show_all ();
6173 /* XXX: this is a bit unfortunate; it would probably
6174 be nicer if we could just call show () above rather
6175 than needing the show_all ()
6178 /* re-hide stuff if necessary */
6179 editor_list_button_toggled ();
6180 parameter_changed ("show-summary");
6181 parameter_changed ("show-group-tabs");
6182 parameter_changed ("show-zoom-tools");
6184 /* now reset all audio_time_axis heights, because widgets might need
6190 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6191 tv = (static_cast<TimeAxisView*>(*i));
6192 tv->reset_height ();
6195 if (current_mixer_strip) {
6196 current_mixer_strip->hide_things ();
6197 current_mixer_strip->parameter_changed ("mixer-element-visibility");