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, true))
394 , cut_buffer (new Selection (this, false))
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);
741 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
742 /* initial allocation is 90% to canvas, 10% to notebook */
745 edit_pane.set_divider (0, fract);
747 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
748 /* initial allocation is 90% to canvas, 10% to summary */
751 editor_summary_pane.set_divider (0, fract);
753 global_vpacker.set_spacing (2);
754 global_vpacker.set_border_width (0);
756 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
758 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
759 ebox->set_name("EditorWindow");
760 ebox->add (toolbar_hbox);
762 Gtk::EventBox* epane_box = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
763 epane_box->set_name("EditorWindow");
764 epane_box->add (edit_pane);
766 Gtk::EventBox* epane_box2 = manage (new Gtkmm2ext::EventBoxExt); //a themeable box
767 epane_box2->set_name("EditorWindow");
768 epane_box2->add (global_vpacker);
770 global_vpacker.pack_start (*ebox, false, false);
771 global_vpacker.pack_start (*epane_box, true, true);
772 global_hpacker.pack_start (*epane_box2, true, true);
774 /* need to show the "contents" widget so that notebook will show if tab is switched to
777 global_hpacker.show ();
779 /* register actions now so that set_state() can find them and set toggles/checks etc */
786 _playlist_selector = new PlaylistSelector();
787 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
789 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
793 nudge_forward_button.set_name ("nudge button");
794 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
796 nudge_backward_button.set_name ("nudge button");
797 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
799 fade_context_menu.set_name ("ArdourContextMenu");
801 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
803 /* allow external control surfaces/protocols to do various things */
805 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
806 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
807 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
808 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
809 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
810 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
811 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
812 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
813 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
814 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
815 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
816 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
817 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
818 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
820 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
821 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
822 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
823 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
824 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
826 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
830 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
832 /* problematic: has to return a value and thus cannot be x-thread */
834 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
836 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
837 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
839 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
841 _ignore_region_action = false;
842 _last_region_menu_was_main = false;
843 _popup_region_menu_item = 0;
845 _show_marker_lines = false;
847 /* Button bindings */
849 button_bindings = new Bindings ("editor-mouse");
851 XMLNode* node = button_settings();
853 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
854 button_bindings->load_operation (**i);
860 /* grab current parameter state */
861 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
862 UIConfiguration::instance().map_parameters (pc);
864 setup_fade_images ();
871 delete button_bindings;
873 delete _route_groups;
874 delete _track_canvas_viewport;
877 delete _verbose_cursor;
878 delete quantize_dialog;
884 delete _playlist_selector;
885 delete _time_info_box;
890 LuaInstance::destroy_instance ();
892 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
895 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
898 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
904 Editor::button_settings () const
906 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
907 XMLNode* node = find_named_node (*settings, X_("Buttons"));
910 node = new XMLNode (X_("Buttons"));
917 Editor::get_smart_mode () const
919 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
923 Editor::catch_vanishing_regionview (RegionView *rv)
925 /* note: the selection will take care of the vanishing
926 audioregionview by itself.
929 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
933 if (clicked_regionview == rv) {
934 clicked_regionview = 0;
937 if (entered_regionview == rv) {
938 set_entered_regionview (0);
941 if (!_all_region_actions_sensitized) {
942 sensitize_all_region_actions (true);
947 Editor::set_entered_regionview (RegionView* rv)
949 if (rv == entered_regionview) {
953 if (entered_regionview) {
954 entered_regionview->exited ();
957 entered_regionview = rv;
959 if (entered_regionview != 0) {
960 entered_regionview->entered ();
963 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
964 /* This RegionView entry might have changed what region actions
965 are allowed, so sensitize them all in case a key is pressed.
967 sensitize_all_region_actions (true);
972 Editor::set_entered_track (TimeAxisView* tav)
975 entered_track->exited ();
981 entered_track->entered ();
986 Editor::instant_save ()
988 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
993 _session->add_instant_xml(get_state());
995 Config->add_instant_xml(get_state());
1000 Editor::control_vertical_zoom_in_all ()
1002 tav_zoom_smooth (false, true);
1006 Editor::control_vertical_zoom_out_all ()
1008 tav_zoom_smooth (true, true);
1012 Editor::control_vertical_zoom_in_selected ()
1014 tav_zoom_smooth (false, false);
1018 Editor::control_vertical_zoom_out_selected ()
1020 tav_zoom_smooth (true, false);
1024 Editor::control_view (uint32_t view)
1026 goto_visual_state (view);
1030 Editor::control_unselect ()
1032 selection->clear_tracks ();
1036 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1038 TimeAxisView* tav = time_axis_view_from_stripable (s);
1042 case Selection::Add:
1043 selection->add (tav);
1045 case Selection::Toggle:
1046 selection->toggle (tav);
1048 case Selection::Extend:
1050 case Selection::Set:
1051 selection->set (tav);
1055 selection->clear_tracks ();
1060 Editor::control_step_tracks_up ()
1062 scroll_tracks_up_line ();
1066 Editor::control_step_tracks_down ()
1068 scroll_tracks_down_line ();
1072 Editor::control_scroll (float fraction)
1074 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1080 double step = fraction * current_page_samples();
1083 _control_scroll_target is an optional<T>
1085 it acts like a pointer to an framepos_t, with
1086 a operator conversion to boolean to check
1087 that it has a value could possibly use
1088 playhead_cursor->current_frame to store the
1089 value and a boolean in the class to know
1090 when it's out of date
1093 if (!_control_scroll_target) {
1094 _control_scroll_target = _session->transport_frame();
1095 _dragging_playhead = true;
1098 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1099 *_control_scroll_target = 0;
1100 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1101 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1103 *_control_scroll_target += (framepos_t) trunc (step);
1106 /* move visuals, we'll catch up with it later */
1108 playhead_cursor->set_position (*_control_scroll_target);
1109 UpdateAllTransportClocks (*_control_scroll_target);
1111 if (*_control_scroll_target > (current_page_samples() / 2)) {
1112 /* try to center PH in window */
1113 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1119 Now we do a timeout to actually bring the session to the right place
1120 according to the playhead. This is to avoid reading disk buffers on every
1121 call to control_scroll, which is driven by ScrollTimeline and therefore
1122 probably by a control surface wheel which can generate lots of events.
1124 /* cancel the existing timeout */
1126 control_scroll_connection.disconnect ();
1128 /* add the next timeout */
1130 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1134 Editor::deferred_control_scroll (framepos_t /*target*/)
1136 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1137 // reset for next stream
1138 _control_scroll_target = boost::none;
1139 _dragging_playhead = false;
1144 Editor::access_action (std::string action_group, std::string action_item)
1150 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1153 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1161 Editor::on_realize ()
1165 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1166 start_lock_event_timing ();
1171 Editor::start_lock_event_timing ()
1173 /* check if we should lock the GUI every 30 seconds */
1175 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1179 Editor::generic_event_handler (GdkEvent* ev)
1182 case GDK_BUTTON_PRESS:
1183 case GDK_BUTTON_RELEASE:
1184 case GDK_MOTION_NOTIFY:
1186 case GDK_KEY_RELEASE:
1187 if (contents().is_mapped()) {
1188 gettimeofday (&last_event_time, 0);
1192 case GDK_LEAVE_NOTIFY:
1193 switch (ev->crossing.detail) {
1194 case GDK_NOTIFY_UNKNOWN:
1195 case GDK_NOTIFY_INFERIOR:
1196 case GDK_NOTIFY_ANCESTOR:
1198 case GDK_NOTIFY_VIRTUAL:
1199 case GDK_NOTIFY_NONLINEAR:
1200 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1201 /* leaving window, so reset focus, thus ending any and
1202 all text entry operations.
1204 ARDOUR_UI::instance()->reset_focus (&contents());
1217 Editor::lock_timeout_callback ()
1219 struct timeval now, delta;
1221 gettimeofday (&now, 0);
1223 timersub (&now, &last_event_time, &delta);
1225 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1227 /* don't call again. Returning false will effectively
1228 disconnect us from the timer callback.
1230 unlock() will call start_lock_event_timing() to get things
1240 Editor::map_position_change (framepos_t frame)
1242 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1244 if (_session == 0) {
1248 if (_follow_playhead) {
1249 center_screen (frame);
1252 playhead_cursor->set_position (frame);
1256 Editor::center_screen (framepos_t frame)
1258 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1260 /* if we're off the page, then scroll.
1263 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1264 center_screen_internal (frame, page);
1269 Editor::center_screen_internal (framepos_t frame, float page)
1274 frame -= (framepos_t) page;
1279 reset_x_origin (frame);
1284 Editor::update_title ()
1286 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1288 if (!own_window()) {
1293 bool dirty = _session->dirty();
1295 string session_name;
1297 if (_session->snap_name() != _session->name()) {
1298 session_name = _session->snap_name();
1300 session_name = _session->name();
1304 session_name = "*" + session_name;
1307 WindowTitle title(session_name);
1308 title += S_("Window|Editor");
1309 title += Glib::get_application_name();
1310 own_window()->set_title (title.get_string());
1312 /* ::session_going_away() will have taken care of it */
1317 Editor::set_session (Session *t)
1319 SessionHandlePtr::set_session (t);
1325 _playlist_selector->set_session (_session);
1326 nudge_clock->set_session (_session);
1327 _summary->set_session (_session);
1328 _group_tabs->set_session (_session);
1329 _route_groups->set_session (_session);
1330 _regions->set_session (_session);
1331 _snapshots->set_session (_session);
1332 _routes->set_session (_session);
1333 _locations->set_session (_session);
1334 _time_info_box->set_session (_session);
1336 if (rhythm_ferret) {
1337 rhythm_ferret->set_session (_session);
1340 if (analysis_window) {
1341 analysis_window->set_session (_session);
1345 sfbrowser->set_session (_session);
1348 compute_fixed_ruler_scale ();
1350 /* Make sure we have auto loop and auto punch ranges */
1352 Location* loc = _session->locations()->auto_loop_location();
1354 loc->set_name (_("Loop"));
1357 loc = _session->locations()->auto_punch_location();
1360 loc->set_name (_("Punch"));
1363 refresh_location_display ();
1365 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1366 the selected Marker; this needs the LocationMarker list to be available.
1368 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1369 set_state (*node, Stateful::loading_state_version);
1371 /* catch up on selection state, etc. */
1374 sc.add (Properties::selected);
1375 presentation_info_changed (sc);
1377 /* catch up with the playhead */
1379 _session->request_locate (playhead_cursor->current_frame ());
1380 _pending_initial_locate = true;
1384 /* These signals can all be emitted by a non-GUI thread. Therefore the
1385 handlers for them must not attempt to directly interact with the GUI,
1386 but use PBD::Signal<T>::connect() which accepts an event loop
1387 ("context") where the handler will be asked to run.
1390 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1391 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1392 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1393 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1394 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1395 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1396 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1397 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1398 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1399 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1400 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1401 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1402 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1403 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1404 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1405 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1407 playhead_cursor->show ();
1409 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1410 Config->map_parameters (pc);
1411 _session->config.map_parameters (pc);
1413 restore_ruler_visibility ();
1414 //tempo_map_changed (PropertyChange (0));
1415 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1417 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1418 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1421 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1422 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1425 switch (_snap_type) {
1426 case SnapToRegionStart:
1427 case SnapToRegionEnd:
1428 case SnapToRegionSync:
1429 case SnapToRegionBoundary:
1430 build_region_boundary_cache ();
1437 /* register for undo history */
1438 _session->register_with_memento_command_factory(id(), this);
1439 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1441 LuaInstance::instance()->set_session(_session);
1443 start_updating_meters ();
1447 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1449 using namespace Menu_Helpers;
1451 void (Editor::*emf)(FadeShape);
1452 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1455 images = &_xfade_in_images;
1456 emf = &Editor::set_fade_in_shape;
1458 images = &_xfade_out_images;
1459 emf = &Editor::set_fade_out_shape;
1464 _("Linear (for highly correlated material)"),
1465 *(*images)[FadeLinear],
1466 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1470 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1474 _("Constant power"),
1475 *(*images)[FadeConstantPower],
1476 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1479 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1484 *(*images)[FadeSymmetric],
1485 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *(*images)[FadeSlow],
1495 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1498 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1503 *(*images)[FadeFast],
1504 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1507 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 /** Pop up a context menu for when the user clicks on a start crossfade */
1512 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1514 using namespace Menu_Helpers;
1515 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1520 MenuList& items (xfade_in_context_menu.items());
1523 if (arv->audio_region()->fade_in_active()) {
1524 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1526 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1529 items.push_back (SeparatorElem());
1530 fill_xfade_menu (items, true);
1532 xfade_in_context_menu.popup (button, time);
1535 /** Pop up a context menu for when the user clicks on an end crossfade */
1537 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1539 using namespace Menu_Helpers;
1540 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1545 MenuList& items (xfade_out_context_menu.items());
1548 if (arv->audio_region()->fade_out_active()) {
1549 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1551 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1554 items.push_back (SeparatorElem());
1555 fill_xfade_menu (items, false);
1557 xfade_out_context_menu.popup (button, time);
1561 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1563 using namespace Menu_Helpers;
1564 Menu* (Editor::*build_menu_function)();
1567 switch (item_type) {
1569 case RegionViewName:
1570 case RegionViewNameHighlight:
1571 case LeftFrameHandle:
1572 case RightFrameHandle:
1573 if (with_selection) {
1574 build_menu_function = &Editor::build_track_selection_context_menu;
1576 build_menu_function = &Editor::build_track_region_context_menu;
1581 if (with_selection) {
1582 build_menu_function = &Editor::build_track_selection_context_menu;
1584 build_menu_function = &Editor::build_track_context_menu;
1589 if (clicked_routeview->track()) {
1590 build_menu_function = &Editor::build_track_context_menu;
1592 build_menu_function = &Editor::build_track_bus_context_menu;
1597 /* probably shouldn't happen but if it does, we don't care */
1601 menu = (this->*build_menu_function)();
1602 menu->set_name ("ArdourContextMenu");
1604 /* now handle specific situations */
1606 switch (item_type) {
1608 case RegionViewName:
1609 case RegionViewNameHighlight:
1610 case LeftFrameHandle:
1611 case RightFrameHandle:
1612 if (!with_selection) {
1613 if (region_edit_menu_split_item) {
1614 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1615 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1617 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1620 if (region_edit_menu_split_multichannel_item) {
1621 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1622 region_edit_menu_split_multichannel_item->set_sensitive (true);
1624 region_edit_menu_split_multichannel_item->set_sensitive (false);
1637 /* probably shouldn't happen but if it does, we don't care */
1641 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1643 /* Bounce to disk */
1645 using namespace Menu_Helpers;
1646 MenuList& edit_items = menu->items();
1648 edit_items.push_back (SeparatorElem());
1650 switch (clicked_routeview->audio_track()->freeze_state()) {
1651 case AudioTrack::NoFreeze:
1652 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1655 case AudioTrack::Frozen:
1656 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1659 case AudioTrack::UnFrozen:
1660 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1666 if (item_type == StreamItem && clicked_routeview) {
1667 clicked_routeview->build_underlay_menu(menu);
1670 /* When the region menu is opened, we setup the actions so that they look right
1673 sensitize_the_right_region_actions (false);
1674 _last_region_menu_was_main = false;
1676 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1677 menu->popup (button, time);
1681 Editor::build_track_context_menu ()
1683 using namespace Menu_Helpers;
1685 MenuList& edit_items = track_context_menu.items();
1688 add_dstream_context_items (edit_items);
1689 return &track_context_menu;
1693 Editor::build_track_bus_context_menu ()
1695 using namespace Menu_Helpers;
1697 MenuList& edit_items = track_context_menu.items();
1700 add_bus_context_items (edit_items);
1701 return &track_context_menu;
1705 Editor::build_track_region_context_menu ()
1707 using namespace Menu_Helpers;
1708 MenuList& edit_items = track_region_context_menu.items();
1711 /* we've just cleared the track region context menu, so the menu that these
1712 two items were on will have disappeared; stop them dangling.
1714 region_edit_menu_split_item = 0;
1715 region_edit_menu_split_multichannel_item = 0;
1717 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1720 boost::shared_ptr<Track> tr;
1721 boost::shared_ptr<Playlist> pl;
1723 if ((tr = rtv->track())) {
1724 add_region_context_items (edit_items, tr);
1728 add_dstream_context_items (edit_items);
1730 return &track_region_context_menu;
1734 Editor::loudness_analyze_region_selection ()
1739 Selection& s (PublicEditor::instance ().get_selection ());
1740 RegionSelection ars = s.regions;
1741 ARDOUR::AnalysisGraph ag (_session);
1742 framecnt_t total_work = 0;
1744 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1745 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1749 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1752 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1753 total_work += arv->region ()->length ();
1756 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1758 ag.set_total_frames (total_work);
1759 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1762 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1763 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1767 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1771 ag.analyze_region (ar);
1774 if (!ag.canceled ()) {
1775 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1781 Editor::loudness_analyze_range_selection ()
1786 Selection& s (PublicEditor::instance ().get_selection ());
1787 TimeSelection ts = s.time;
1788 ARDOUR::AnalysisGraph ag (_session);
1789 framecnt_t total_work = 0;
1791 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1792 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1796 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1800 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1801 total_work += j->length ();
1805 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1807 ag.set_total_frames (total_work);
1808 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1811 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1812 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1816 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1820 ag.analyze_range (rui->route (), pl, ts);
1823 if (!ag.canceled ()) {
1824 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1830 Editor::spectral_analyze_region_selection ()
1832 if (analysis_window == 0) {
1833 analysis_window = new AnalysisWindow();
1836 analysis_window->set_session(_session);
1838 analysis_window->show_all();
1841 analysis_window->set_regionmode();
1842 analysis_window->analyze();
1844 analysis_window->present();
1848 Editor::spectral_analyze_range_selection()
1850 if (analysis_window == 0) {
1851 analysis_window = new AnalysisWindow();
1854 analysis_window->set_session(_session);
1856 analysis_window->show_all();
1859 analysis_window->set_rangemode();
1860 analysis_window->analyze();
1862 analysis_window->present();
1866 Editor::build_track_selection_context_menu ()
1868 using namespace Menu_Helpers;
1869 MenuList& edit_items = track_selection_context_menu.items();
1870 edit_items.clear ();
1872 add_selection_context_items (edit_items);
1873 // edit_items.push_back (SeparatorElem());
1874 // add_dstream_context_items (edit_items);
1876 return &track_selection_context_menu;
1880 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1882 using namespace Menu_Helpers;
1884 /* OK, stick the region submenu at the top of the list, and then add
1888 RegionSelection rs = get_regions_from_selection_and_entered ();
1890 string::size_type pos = 0;
1891 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1893 /* we have to hack up the region name because "_" has a special
1894 meaning for menu titles.
1897 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1898 menu_item_name.replace (pos, 1, "__");
1902 if (_popup_region_menu_item == 0) {
1903 _popup_region_menu_item = new MenuItem (menu_item_name);
1904 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1905 _popup_region_menu_item->show ();
1907 _popup_region_menu_item->set_label (menu_item_name);
1910 /* No layering allowed in later is higher layering model */
1911 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1912 if (act && Config->get_layer_model() == LaterHigher) {
1913 act->set_sensitive (false);
1915 act->set_sensitive (true);
1918 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1920 edit_items.push_back (*_popup_region_menu_item);
1921 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1922 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1924 edit_items.push_back (SeparatorElem());
1927 /** Add context menu items relevant to selection ranges.
1928 * @param edit_items List to add the items to.
1931 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1933 using namespace Menu_Helpers;
1935 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1936 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1938 edit_items.push_back (SeparatorElem());
1939 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1941 edit_items.push_back (SeparatorElem());
1942 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1943 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1945 edit_items.push_back (SeparatorElem());
1947 edit_items.push_back (
1949 _("Move Range Start to Previous Region Boundary"),
1950 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1954 edit_items.push_back (
1956 _("Move Range Start to Next Region Boundary"),
1957 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1961 edit_items.push_back (
1963 _("Move Range End to Previous Region Boundary"),
1964 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1968 edit_items.push_back (
1970 _("Move Range End to Next Region Boundary"),
1971 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1977 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1979 edit_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1984 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1985 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1987 edit_items.push_back (SeparatorElem());
1988 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1990 edit_items.push_back (SeparatorElem());
1991 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1992 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1994 edit_items.push_back (SeparatorElem());
1995 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1996 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1997 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1998 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1999 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
2000 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
2001 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2007 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2009 using namespace Menu_Helpers;
2013 Menu *play_menu = manage (new Menu);
2014 MenuList& play_items = play_menu->items();
2015 play_menu->set_name ("ArdourContextMenu");
2017 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2018 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2019 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2020 play_items.push_back (SeparatorElem());
2021 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2023 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2027 Menu *select_menu = manage (new Menu);
2028 MenuList& select_items = select_menu->items();
2029 select_menu->set_name ("ArdourContextMenu");
2031 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2032 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2033 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2034 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2035 select_items.push_back (SeparatorElem());
2036 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2037 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2038 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2039 select_items.push_back (SeparatorElem());
2040 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2041 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2042 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2043 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2044 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2045 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2046 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2048 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2052 Menu *cutnpaste_menu = manage (new Menu);
2053 MenuList& cutnpaste_items = cutnpaste_menu->items();
2054 cutnpaste_menu->set_name ("ArdourContextMenu");
2056 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2057 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2058 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2060 cutnpaste_items.push_back (SeparatorElem());
2062 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2063 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2065 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2067 /* Adding new material */
2069 edit_items.push_back (SeparatorElem());
2070 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2071 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2075 Menu *nudge_menu = manage (new Menu());
2076 MenuList& nudge_items = nudge_menu->items();
2077 nudge_menu->set_name ("ArdourContextMenu");
2079 edit_items.push_back (SeparatorElem());
2080 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2081 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2082 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2083 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2085 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2089 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2091 using namespace Menu_Helpers;
2095 Menu *play_menu = manage (new Menu);
2096 MenuList& play_items = play_menu->items();
2097 play_menu->set_name ("ArdourContextMenu");
2099 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2100 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2101 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2105 Menu *select_menu = manage (new Menu);
2106 MenuList& select_items = select_menu->items();
2107 select_menu->set_name ("ArdourContextMenu");
2109 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2110 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2111 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2112 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2113 select_items.push_back (SeparatorElem());
2114 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2115 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2116 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2117 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2119 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2123 Menu *cutnpaste_menu = manage (new Menu);
2124 MenuList& cutnpaste_items = cutnpaste_menu->items();
2125 cutnpaste_menu->set_name ("ArdourContextMenu");
2127 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2128 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2129 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2131 Menu *nudge_menu = manage (new Menu());
2132 MenuList& nudge_items = nudge_menu->items();
2133 nudge_menu->set_name ("ArdourContextMenu");
2135 edit_items.push_back (SeparatorElem());
2136 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2137 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2138 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2139 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2141 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2145 Editor::snap_type() const
2151 Editor::snap_musical() const
2153 switch (_snap_type) {
2154 case SnapToBeatDiv128:
2155 case SnapToBeatDiv64:
2156 case SnapToBeatDiv32:
2157 case SnapToBeatDiv28:
2158 case SnapToBeatDiv24:
2159 case SnapToBeatDiv20:
2160 case SnapToBeatDiv16:
2161 case SnapToBeatDiv14:
2162 case SnapToBeatDiv12:
2163 case SnapToBeatDiv10:
2164 case SnapToBeatDiv8:
2165 case SnapToBeatDiv7:
2166 case SnapToBeatDiv6:
2167 case SnapToBeatDiv5:
2168 case SnapToBeatDiv4:
2169 case SnapToBeatDiv3:
2170 case SnapToBeatDiv2:
2182 Editor::snap_mode() const
2188 Editor::set_snap_to (SnapType st)
2190 unsigned int snap_ind = (unsigned int)st;
2192 if (internal_editing()) {
2193 internal_snap_type = st;
2195 pre_internal_snap_type = st;
2200 if (snap_ind > snap_type_strings.size() - 1) {
2202 _snap_type = (SnapType)snap_ind;
2205 string str = snap_type_strings[snap_ind];
2207 if (str != snap_type_selector.get_text()) {
2208 snap_type_selector.set_text (str);
2213 switch (_snap_type) {
2214 case SnapToBeatDiv128:
2215 case SnapToBeatDiv64:
2216 case SnapToBeatDiv32:
2217 case SnapToBeatDiv28:
2218 case SnapToBeatDiv24:
2219 case SnapToBeatDiv20:
2220 case SnapToBeatDiv16:
2221 case SnapToBeatDiv14:
2222 case SnapToBeatDiv12:
2223 case SnapToBeatDiv10:
2224 case SnapToBeatDiv8:
2225 case SnapToBeatDiv7:
2226 case SnapToBeatDiv6:
2227 case SnapToBeatDiv5:
2228 case SnapToBeatDiv4:
2229 case SnapToBeatDiv3:
2230 case SnapToBeatDiv2: {
2231 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples());
2232 update_tempo_based_rulers ();
2236 case SnapToRegionStart:
2237 case SnapToRegionEnd:
2238 case SnapToRegionSync:
2239 case SnapToRegionBoundary:
2240 build_region_boundary_cache ();
2248 redisplay_tempo (false);
2250 SnapChanged (); /* EMIT SIGNAL */
2254 Editor::set_snap_mode (SnapMode mode)
2256 string str = snap_mode_strings[(int)mode];
2258 if (internal_editing()) {
2259 internal_snap_mode = mode;
2261 pre_internal_snap_mode = mode;
2266 if (str != snap_mode_selector.get_text ()) {
2267 snap_mode_selector.set_text (str);
2274 Editor::set_edit_point_preference (EditPoint ep, bool force)
2276 bool changed = (_edit_point != ep);
2279 if (Profile->get_mixbus())
2280 if (ep == EditAtSelectedMarker)
2281 ep = EditAtPlayhead;
2283 string str = edit_point_strings[(int)ep];
2284 if (str != edit_point_selector.get_text ()) {
2285 edit_point_selector.set_text (str);
2288 update_all_enter_cursors();
2290 if (!force && !changed) {
2294 const char* action=NULL;
2296 switch (_edit_point) {
2297 case EditAtPlayhead:
2298 action = "edit-at-playhead";
2300 case EditAtSelectedMarker:
2301 action = "edit-at-marker";
2304 action = "edit-at-mouse";
2308 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2310 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2314 bool in_track_canvas;
2316 if (!mouse_frame (foo, in_track_canvas)) {
2317 in_track_canvas = false;
2320 reset_canvas_action_sensitivity (in_track_canvas);
2321 sensitize_the_right_region_actions (false);
2327 Editor::set_state (const XMLNode& node, int version)
2330 PBD::Unwinder<bool> nsi (no_save_instant, true);
2333 Tabbable::set_state (node, version);
2336 if (_session && node.get_property ("playhead", ph_pos)) {
2338 playhead_cursor->set_position (ph_pos);
2340 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2341 playhead_cursor->set_position (0);
2344 playhead_cursor->set_position (0);
2347 node.get_property ("mixer-width", editor_mixer_strip_width);
2349 node.get_property ("zoom-focus", zoom_focus);
2350 zoom_focus_selection_done (zoom_focus);
2353 if (node.get_property ("zoom", z)) {
2354 /* older versions of ardour used floating point samples_per_pixel */
2355 reset_zoom (llrintf (z));
2357 reset_zoom (samples_per_pixel);
2361 if (node.get_property ("visible-track-count", cnt)) {
2362 set_visible_track_count (cnt);
2366 if (!node.get_property ("snap-to", snap_type)) {
2367 snap_type = _snap_type;
2369 set_snap_to (snap_type);
2372 if (node.get_property ("snap-mode", sm)) {
2373 snap_mode_selection_done(sm);
2374 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2375 * snap_mode_selection_done() will only mark an already active item as active
2376 * which does not trigger set_text().
2380 set_snap_mode (_snap_mode);
2383 node.get_property ("internal-snap-to", internal_snap_type);
2384 node.get_property ("internal-snap-mode", internal_snap_mode);
2385 node.get_property ("pre-internal-snap-to", pre_internal_snap_type);
2386 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2389 if (node.get_property ("mouse-mode", mm_str)) {
2390 MouseMode m = str2mousemode(mm_str);
2391 set_mouse_mode (m, true);
2393 set_mouse_mode (MouseObject, true);
2397 if (node.get_property ("left-frame", lf_pos)) {
2401 reset_x_origin (lf_pos);
2405 if (node.get_property ("y-origin", y_origin)) {
2406 reset_y_origin (y_origin);
2409 if (node.get_property ("join-object-range", yn)) {
2410 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2412 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2413 tact->set_active (!yn);
2414 tact->set_active (yn);
2416 set_mouse_mode(mouse_mode, true);
2420 if (node.get_property ("edit-point", ep)) {
2421 set_edit_point_preference (ep, true);
2423 set_edit_point_preference (_edit_point);
2426 node.get_property ("show-measures", _show_measures);
2428 if (node.get_property ("follow-playhead", yn)) {
2429 set_follow_playhead (yn);
2432 if (node.get_property ("stationary-playhead", yn)) {
2433 set_stationary_playhead (yn);
2436 RegionListSortType sort_type;
2437 if (node.get_property ("region-list-sort-type", sort_type)) {
2438 _regions->reset_sort_type (sort_type, true);
2441 if (node.get_property ("show-editor-mixer", yn)) {
2443 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2446 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2448 /* do it twice to force the change */
2450 tact->set_active (!yn);
2451 tact->set_active (yn);
2454 if (node.get_property ("show-editor-list", yn)) {
2456 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2459 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2461 /* do it twice to force the change */
2463 tact->set_active (!yn);
2464 tact->set_active (yn);
2468 if (node.get_property (X_("editor-list-page"), el_page)) {
2469 _the_notebook.set_current_page (el_page);
2472 if (node.get_property (X_("show-marker-lines"), yn)) {
2473 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2475 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2477 tact->set_active (!yn);
2478 tact->set_active (yn);
2481 XMLNodeList children = node.children ();
2482 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2483 selection->set_state (**i, Stateful::current_state_version);
2484 _regions->set_state (**i);
2485 _locations->set_state (**i);
2488 if (node.get_property ("maximised", yn)) {
2489 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2491 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2492 bool fs = tact && tact->get_active();
2494 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2498 framepos_t nudge_clock_value;
2499 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2500 nudge_clock->set (nudge_clock_value);
2502 nudge_clock->set_mode (AudioClock::Timecode);
2503 nudge_clock->set (_session->frame_rate() * 5, true);
2508 * Not all properties may have been in XML, but
2509 * those that are linked to a private variable may need changing
2513 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2515 yn = _show_measures;
2516 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2517 /* do it twice to force the change */
2518 tact->set_active (!yn);
2519 tact->set_active (yn);
2522 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2523 yn = _follow_playhead;
2525 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2526 if (tact->get_active() != yn) {
2527 tact->set_active (yn);
2531 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2532 yn = _stationary_playhead;
2534 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2535 if (tact->get_active() != yn) {
2536 tact->set_active (yn);
2541 return LuaInstance::instance()->set_state(node);
2545 Editor::get_state ()
2547 XMLNode* node = new XMLNode (X_("Editor"));
2549 node->set_property ("id", id().to_s ());
2551 node->add_child_nocopy (Tabbable::get_state());
2553 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2554 node->set_property("notebook-shrunk", _notebook_shrunk);
2555 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2557 maybe_add_mixer_strip_width (*node);
2559 node->set_property ("zoom-focus", zoom_focus);
2561 node->set_property ("zoom", samples_per_pixel);
2562 node->set_property ("snap-to", _snap_type);
2563 node->set_property ("snap-mode", _snap_mode);
2564 node->set_property ("internal-snap-to", internal_snap_type);
2565 node->set_property ("internal-snap-mode", internal_snap_mode);
2566 node->set_property ("pre-internal-snap-to", pre_internal_snap_type);
2567 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2568 node->set_property ("edit-point", _edit_point);
2569 node->set_property ("visible-track-count", _visible_track_count);
2571 node->set_property ("playhead", playhead_cursor->current_frame ());
2572 node->set_property ("left-frame", leftmost_frame);
2573 node->set_property ("y-origin", vertical_adjustment.get_value ());
2575 node->set_property ("show-measures", _show_measures);
2576 node->set_property ("maximised", _maximised);
2577 node->set_property ("follow-playhead", _follow_playhead);
2578 node->set_property ("stationary-playhead", _stationary_playhead);
2579 node->set_property ("region-list-sort-type", _regions->sort_type ());
2580 node->set_property ("mouse-mode", mouse_mode);
2581 node->set_property ("join-object-range", smart_mode_action->get_active ());
2583 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2585 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2586 node->set_property (X_("show-editor-mixer"), tact->get_active());
2589 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2591 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2592 node->set_property (X_("show-editor-list"), tact->get_active());
2595 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2597 if (button_bindings) {
2598 XMLNode* bb = new XMLNode (X_("Buttons"));
2599 button_bindings->save (*bb);
2600 node->add_child_nocopy (*bb);
2603 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2605 node->add_child_nocopy (selection->get_state ());
2606 node->add_child_nocopy (_regions->get_state ());
2608 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2610 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2611 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2612 node->add_child_nocopy (_locations->get_state ());
2617 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2618 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2620 * @return pair: TimeAxisView that y is over, layer index.
2622 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2623 * in stacked or expanded region display mode, otherwise 0.
2625 std::pair<TimeAxisView *, double>
2626 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2628 if (!trackview_relative_offset) {
2629 y -= _trackview_group->canvas_origin().y;
2633 return std::make_pair ( (TimeAxisView *) 0, 0);
2636 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2638 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2645 return std::make_pair ( (TimeAxisView *) 0, 0);
2648 /** Snap a position to the grid, if appropriate, taking into account current
2649 * grid settings and also the state of any snap modifier keys that may be pressed.
2650 * @param start Position to snap.
2651 * @param event Event to get current key modifier information from, or 0.
2654 Editor::snap_to_with_modifier (MusicFrame& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2656 if (!_session || !event) {
2660 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2661 if (_snap_mode == SnapOff) {
2662 snap_to_internal (start, direction, for_mark);
2664 start.set (start.frame, 0);
2667 if (_snap_mode != SnapOff) {
2668 snap_to_internal (start, direction, for_mark);
2669 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2670 /* SnapOff, but we pressed the snap_delta modifier */
2671 snap_to_internal (start, direction, for_mark);
2673 start.set (start.frame, 0);
2679 Editor::snap_to (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2681 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2682 start.set (start.frame, 0);
2686 snap_to_internal (start, direction, for_mark, ensure_snap);
2690 Editor::timecode_snap_to_internal (MusicFrame& pos, RoundMode direction, bool /*for_mark*/)
2692 framepos_t start = pos.frame;
2693 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2694 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2696 switch (_snap_type) {
2697 case SnapToTimecodeFrame:
2698 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2699 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2700 /* start is already on a whole timecode frame, do nothing */
2701 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2702 start = (framepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2704 start = (framepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2708 case SnapToTimecodeSeconds:
2709 if (_session->config.get_timecode_offset_negative()) {
2710 start += _session->config.get_timecode_offset ();
2712 start -= _session->config.get_timecode_offset ();
2714 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2715 (start % one_timecode_second == 0)) {
2716 /* start is already on a whole second, do nothing */
2717 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2718 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2720 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2723 if (_session->config.get_timecode_offset_negative()) {
2724 start -= _session->config.get_timecode_offset ();
2726 start += _session->config.get_timecode_offset ();
2730 case SnapToTimecodeMinutes:
2731 if (_session->config.get_timecode_offset_negative()) {
2732 start += _session->config.get_timecode_offset ();
2734 start -= _session->config.get_timecode_offset ();
2736 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2737 (start % one_timecode_minute == 0)) {
2738 /* start is already on a whole minute, do nothing */
2739 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2740 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2742 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2744 if (_session->config.get_timecode_offset_negative()) {
2745 start -= _session->config.get_timecode_offset ();
2747 start += _session->config.get_timecode_offset ();
2751 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2752 abort(); /*NOTREACHED*/
2759 Editor::snap_to_internal (MusicFrame& start, RoundMode direction, bool for_mark, bool ensure_snap)
2761 const framepos_t one_second = _session->frame_rate();
2762 const framepos_t one_minute = _session->frame_rate() * 60;
2763 framepos_t presnap = start.frame;
2767 switch (_snap_type) {
2768 case SnapToTimecodeFrame:
2769 case SnapToTimecodeSeconds:
2770 case SnapToTimecodeMinutes:
2771 return timecode_snap_to_internal (start, direction, for_mark);
2774 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2775 start.frame % (one_second/75) == 0) {
2776 /* start is already on a whole CD frame, do nothing */
2777 } else if (((direction == 0) && (start.frame % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2778 start.frame = (framepos_t) ceil ((double) start.frame / (one_second / 75)) * (one_second / 75);
2780 start.frame = (framepos_t) floor ((double) start.frame / (one_second / 75)) * (one_second / 75);
2783 start.set (start.frame, 0);
2788 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2789 start.frame % one_second == 0) {
2790 /* start is already on a whole second, do nothing */
2791 } else if (((direction == 0) && (start.frame % one_second > one_second / 2)) || (direction > 0)) {
2792 start.frame = (framepos_t) ceil ((double) start.frame / one_second) * one_second;
2794 start.frame = (framepos_t) floor ((double) start.frame / one_second) * one_second;
2797 start.set (start.frame, 0);
2802 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2803 start.frame % one_minute == 0) {
2804 /* start is already on a whole minute, do nothing */
2805 } else if (((direction == 0) && (start.frame % one_minute > one_minute / 2)) || (direction > 0)) {
2806 start.frame = (framepos_t) ceil ((double) start.frame / one_minute) * one_minute;
2808 start.frame = (framepos_t) floor ((double) start.frame / one_minute) * one_minute;
2811 start.set (start.frame, 0);
2816 start = _session->tempo_map().round_to_bar (start.frame, direction);
2820 start = _session->tempo_map().round_to_beat (start.frame, direction);
2823 case SnapToBeatDiv128:
2824 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 128, direction);
2826 case SnapToBeatDiv64:
2827 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 64, direction);
2829 case SnapToBeatDiv32:
2830 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 32, direction);
2832 case SnapToBeatDiv28:
2833 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 28, direction);
2835 case SnapToBeatDiv24:
2836 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 24, direction);
2838 case SnapToBeatDiv20:
2839 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 20, direction);
2841 case SnapToBeatDiv16:
2842 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 16, direction);
2844 case SnapToBeatDiv14:
2845 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 14, direction);
2847 case SnapToBeatDiv12:
2848 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 12, direction);
2850 case SnapToBeatDiv10:
2851 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 10, direction);
2853 case SnapToBeatDiv8:
2854 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 8, direction);
2856 case SnapToBeatDiv7:
2857 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 7, direction);
2859 case SnapToBeatDiv6:
2860 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 6, direction);
2862 case SnapToBeatDiv5:
2863 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 5, direction);
2865 case SnapToBeatDiv4:
2866 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 4, direction);
2868 case SnapToBeatDiv3:
2869 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 3, direction);
2871 case SnapToBeatDiv2:
2872 start = _session->tempo_map().round_to_quarter_note_subdivision (start.frame, 2, direction);
2880 _session->locations()->marks_either_side (start.frame, before, after);
2882 if (before == max_framepos && after == max_framepos) {
2883 /* No marks to snap to, so just don't snap */
2885 } else if (before == max_framepos) {
2886 start.frame = after;
2887 } else if (after == max_framepos) {
2888 start.frame = before;
2889 } else if (before != max_framepos && after != max_framepos) {
2890 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2891 start.frame = after;
2892 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2893 start.frame = before;
2894 else if (direction == 0 ) {
2895 if ((start.frame - before) < (after - start.frame)) {
2896 start.frame = before;
2898 start.frame = after;
2903 start.set (start.frame, 0);
2907 case SnapToRegionStart:
2908 case SnapToRegionEnd:
2909 case SnapToRegionSync:
2910 case SnapToRegionBoundary:
2911 if (!region_boundary_cache.empty()) {
2913 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2914 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2916 if (direction > 0) {
2917 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2919 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start.frame);
2922 if (next != region_boundary_cache.begin ()) {
2927 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2928 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2930 if (start.frame > (p + n) / 2) {
2937 start.set (start.frame, 0);
2942 switch (_snap_mode) {
2952 if (presnap > start.frame) {
2953 if (presnap > (start.frame + pixel_to_sample(snap_threshold))) {
2954 start.set (presnap, 0);
2957 } else if (presnap < start.frame) {
2958 if (presnap < (start.frame - pixel_to_sample(snap_threshold))) {
2959 start.set (presnap, 0);
2964 /* handled at entry */
2971 Editor::setup_toolbar ()
2973 HBox* mode_box = manage(new HBox);
2974 mode_box->set_border_width (2);
2975 mode_box->set_spacing(2);
2977 HBox* mouse_mode_box = manage (new HBox);
2978 HBox* mouse_mode_hbox = manage (new HBox);
2979 VBox* mouse_mode_vbox = manage (new VBox);
2980 Alignment* mouse_mode_align = manage (new Alignment);
2982 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2983 mouse_mode_size_group->add_widget (smart_mode_button);
2984 mouse_mode_size_group->add_widget (mouse_move_button);
2985 mouse_mode_size_group->add_widget (mouse_cut_button);
2986 mouse_mode_size_group->add_widget (mouse_select_button);
2987 mouse_mode_size_group->add_widget (mouse_timefx_button);
2988 mouse_mode_size_group->add_widget (mouse_audition_button);
2989 mouse_mode_size_group->add_widget (mouse_draw_button);
2990 mouse_mode_size_group->add_widget (mouse_content_button);
2992 if (!Profile->get_mixbus()) {
2993 mouse_mode_size_group->add_widget (zoom_in_button);
2994 mouse_mode_size_group->add_widget (zoom_out_button);
2995 mouse_mode_size_group->add_widget (zoom_out_full_button);
2996 mouse_mode_size_group->add_widget (zoom_focus_selector);
2997 mouse_mode_size_group->add_widget (tav_shrink_button);
2998 mouse_mode_size_group->add_widget (tav_expand_button);
3000 mouse_mode_size_group->add_widget (zoom_preset_selector);
3001 mouse_mode_size_group->add_widget (visible_tracks_selector);
3004 mouse_mode_size_group->add_widget (snap_type_selector);
3005 mouse_mode_size_group->add_widget (snap_mode_selector);
3007 mouse_mode_size_group->add_widget (edit_point_selector);
3008 mouse_mode_size_group->add_widget (edit_mode_selector);
3010 mouse_mode_size_group->add_widget (*nudge_clock);
3011 mouse_mode_size_group->add_widget (nudge_forward_button);
3012 mouse_mode_size_group->add_widget (nudge_backward_button);
3014 mouse_mode_hbox->set_spacing (2);
3016 if (!ARDOUR::Profile->get_trx()) {
3017 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3020 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3021 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3023 if (!ARDOUR::Profile->get_mixbus()) {
3024 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3027 if (!ARDOUR::Profile->get_trx()) {
3028 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3029 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3030 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3031 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3034 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3036 mouse_mode_align->add (*mouse_mode_vbox);
3037 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3039 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3041 edit_mode_selector.set_name ("mouse mode button");
3043 if (!ARDOUR::Profile->get_trx()) {
3044 mode_box->pack_start (edit_mode_selector, false, false);
3047 mode_box->pack_start (*mouse_mode_box, false, false);
3051 _zoom_box.set_spacing (2);
3052 _zoom_box.set_border_width (2);
3056 zoom_preset_selector.set_name ("zoom button");
3057 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3059 zoom_in_button.set_name ("zoom button");
3060 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3061 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3062 zoom_in_button.set_related_action (act);
3064 zoom_out_button.set_name ("zoom button");
3065 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3066 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3067 zoom_out_button.set_related_action (act);
3069 zoom_out_full_button.set_name ("zoom button");
3070 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3071 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3072 zoom_out_full_button.set_related_action (act);
3074 zoom_focus_selector.set_name ("zoom button");
3076 if (ARDOUR::Profile->get_mixbus()) {
3077 _zoom_box.pack_start (zoom_preset_selector, false, false);
3078 } else if (ARDOUR::Profile->get_trx()) {
3079 mode_box->pack_start (zoom_out_button, false, false);
3080 mode_box->pack_start (zoom_in_button, false, false);
3082 _zoom_box.pack_start (zoom_out_button, false, false);
3083 _zoom_box.pack_start (zoom_in_button, false, false);
3084 _zoom_box.pack_start (zoom_out_full_button, false, false);
3085 _zoom_box.pack_start (zoom_focus_selector, false, false);
3088 /* Track zoom buttons */
3089 _track_box.set_spacing (2);
3090 _track_box.set_border_width (2);
3092 visible_tracks_selector.set_name ("zoom button");
3093 if (Profile->get_mixbus()) {
3094 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3096 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3099 tav_expand_button.set_name ("zoom button");
3100 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3101 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3102 tav_expand_button.set_related_action (act);
3104 tav_shrink_button.set_name ("zoom button");
3105 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3106 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3107 tav_shrink_button.set_related_action (act);
3109 if (ARDOUR::Profile->get_mixbus()) {
3110 _track_box.pack_start (visible_tracks_selector);
3111 } else if (ARDOUR::Profile->get_trx()) {
3112 _track_box.pack_start (tav_shrink_button);
3113 _track_box.pack_start (tav_expand_button);
3115 _track_box.pack_start (visible_tracks_selector);
3116 _track_box.pack_start (tav_shrink_button);
3117 _track_box.pack_start (tav_expand_button);
3120 snap_box.set_spacing (2);
3121 snap_box.set_border_width (2);
3123 snap_type_selector.set_name ("mouse mode button");
3125 snap_mode_selector.set_name ("mouse mode button");
3127 edit_point_selector.set_name ("mouse mode button");
3129 snap_box.pack_start (snap_mode_selector, false, false);
3130 snap_box.pack_start (snap_type_selector, false, false);
3133 HBox *ep_box = manage (new HBox);
3134 ep_box->set_spacing (2);
3135 ep_box->set_border_width (2);
3137 ep_box->pack_start (edit_point_selector, false, false);
3141 HBox *nudge_box = manage (new HBox);
3142 nudge_box->set_spacing (2);
3143 nudge_box->set_border_width (2);
3145 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3146 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3148 nudge_box->pack_start (nudge_backward_button, false, false);
3149 nudge_box->pack_start (nudge_forward_button, false, false);
3150 nudge_box->pack_start (*nudge_clock, false, false);
3153 /* Pack everything in... */
3155 toolbar_hbox.set_spacing (2);
3156 toolbar_hbox.set_border_width (2);
3158 toolbar_hbox.pack_start (*mode_box, false, false);
3160 if (!ARDOUR::Profile->get_trx()) {
3162 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3164 toolbar_hbox.pack_start (_zoom_box, false, false);
3166 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3168 toolbar_hbox.pack_start (_track_box, false, false);
3170 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3172 toolbar_hbox.pack_start (snap_box, false, false);
3174 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3176 toolbar_hbox.pack_start (*ep_box, false, false);
3178 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3180 toolbar_hbox.pack_start (*nudge_box, false, false);
3183 toolbar_hbox.show_all ();
3187 Editor::build_edit_point_menu ()
3189 using namespace Menu_Helpers;
3191 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3192 if(!Profile->get_mixbus())
3193 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3194 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3196 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3200 Editor::build_edit_mode_menu ()
3202 using namespace Menu_Helpers;
3204 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3205 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3206 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3207 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3209 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3213 Editor::build_snap_mode_menu ()
3215 using namespace Menu_Helpers;
3217 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3218 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3219 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3221 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3225 Editor::build_snap_type_menu ()
3227 using namespace Menu_Helpers;
3229 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3230 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3231 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3232 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3233 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3234 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3235 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3236 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3237 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3238 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3239 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3240 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3241 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3242 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3243 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3244 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3245 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3246 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3247 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3248 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3249 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3250 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3251 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3252 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3253 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3254 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3255 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3256 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3257 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3258 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3260 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3265 Editor::setup_tooltips ()
3267 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3268 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3269 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3270 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3271 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3272 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3273 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3274 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3275 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3276 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3277 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3278 set_tooltip (zoom_in_button, _("Zoom In"));
3279 set_tooltip (zoom_out_button, _("Zoom Out"));
3280 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3281 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3282 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3283 set_tooltip (tav_expand_button, _("Expand Tracks"));
3284 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3285 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3286 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3287 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3288 set_tooltip (edit_point_selector, _("Edit Point"));
3289 set_tooltip (edit_mode_selector, _("Edit Mode"));
3290 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3294 Editor::convert_drop_to_paths (
3295 vector<string>& paths,
3296 const RefPtr<Gdk::DragContext>& /*context*/,
3299 const SelectionData& data,
3303 if (_session == 0) {
3307 vector<string> uris = data.get_uris();
3311 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3312 are actually URI lists. So do it by hand.
3315 if (data.get_target() != "text/plain") {
3319 /* Parse the "uri-list" format that Nautilus provides,
3320 where each pathname is delimited by \r\n.
3322 THERE MAY BE NO NULL TERMINATING CHAR!!!
3325 string txt = data.get_text();
3329 p = (char *) malloc (txt.length() + 1);
3330 txt.copy (p, txt.length(), 0);
3331 p[txt.length()] = '\0';
3337 while (g_ascii_isspace (*p))
3341 while (*q && (*q != '\n') && (*q != '\r')) {
3348 while (q > p && g_ascii_isspace (*q))
3353 uris.push_back (string (p, q - p + 1));
3357 p = strchr (p, '\n');
3369 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3370 if ((*i).substr (0,7) == "file://") {
3371 paths.push_back (Glib::filename_from_uri (*i));
3379 Editor::new_tempo_section ()
3384 Editor::map_transport_state ()
3386 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3388 if (_session && _session->transport_stopped()) {
3389 have_pending_keyboard_selection = false;
3392 update_loop_range_view ();
3396 Editor::transport_looped ()
3398 /* reset Playhead position interpolation.
3399 * see Editor::super_rapid_screen_update
3401 _last_update_time = 0;
3407 Editor::begin_selection_op_history ()
3409 selection_op_cmd_depth = 0;
3410 selection_op_history_it = 0;
3412 while(!selection_op_history.empty()) {
3413 delete selection_op_history.front();
3414 selection_op_history.pop_front();
3417 selection_undo_action->set_sensitive (false);
3418 selection_redo_action->set_sensitive (false);
3419 selection_op_history.push_front (&_selection_memento->get_state ());
3423 Editor::begin_reversible_selection_op (string name)
3426 //cerr << name << endl;
3427 /* begin/commit pairs can be nested */
3428 selection_op_cmd_depth++;
3433 Editor::commit_reversible_selection_op ()
3436 if (selection_op_cmd_depth == 1) {
3438 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3440 The user has undone some selection ops and then made a new one,
3441 making anything earlier in the list invalid.
3444 list<XMLNode *>::iterator it = selection_op_history.begin();
3445 list<XMLNode *>::iterator e_it = it;
3446 advance (e_it, selection_op_history_it);
3448 for ( ; it != e_it; ++it) {
3451 selection_op_history.erase (selection_op_history.begin(), e_it);
3454 selection_op_history.push_front (&_selection_memento->get_state ());
3455 selection_op_history_it = 0;
3457 selection_undo_action->set_sensitive (true);
3458 selection_redo_action->set_sensitive (false);
3461 if (selection_op_cmd_depth > 0) {
3462 selection_op_cmd_depth--;
3468 Editor::undo_selection_op ()
3471 selection_op_history_it++;
3473 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3474 if (n == selection_op_history_it) {
3475 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3476 selection_redo_action->set_sensitive (true);
3480 /* is there an earlier entry? */
3481 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3482 selection_undo_action->set_sensitive (false);
3488 Editor::redo_selection_op ()
3491 if (selection_op_history_it > 0) {
3492 selection_op_history_it--;
3495 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3496 if (n == selection_op_history_it) {
3497 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3498 selection_undo_action->set_sensitive (true);
3503 if (selection_op_history_it == 0) {
3504 selection_redo_action->set_sensitive (false);
3510 Editor::begin_reversible_command (string name)
3513 before.push_back (&_selection_memento->get_state ());
3514 _session->begin_reversible_command (name);
3519 Editor::begin_reversible_command (GQuark q)
3522 before.push_back (&_selection_memento->get_state ());
3523 _session->begin_reversible_command (q);
3528 Editor::abort_reversible_command ()
3531 while(!before.empty()) {
3532 delete before.front();
3535 _session->abort_reversible_command ();
3540 Editor::commit_reversible_command ()
3543 if (before.size() == 1) {
3544 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3545 redo_action->set_sensitive(false);
3546 undo_action->set_sensitive(true);
3547 begin_selection_op_history ();
3550 if (before.empty()) {
3551 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3556 _session->commit_reversible_command ();
3561 Editor::history_changed ()
3565 if (undo_action && _session) {
3566 if (_session->undo_depth() == 0) {
3567 label = S_("Command|Undo");
3569 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3571 undo_action->property_label() = label;
3574 if (redo_action && _session) {
3575 if (_session->redo_depth() == 0) {
3577 redo_action->set_sensitive (false);
3579 label = string_compose(_("Redo (%1)"), _session->next_redo());
3580 redo_action->set_sensitive (true);
3582 redo_action->property_label() = label;
3587 Editor::duplicate_range (bool with_dialog)
3591 RegionSelection rs = get_regions_from_selection_and_entered ();
3593 if ( selection->time.length() == 0 && rs.empty()) {
3599 ArdourDialog win (_("Duplicate"));
3600 Label label (_("Number of duplications:"));
3601 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3602 SpinButton spinner (adjustment, 0.0, 1);
3605 win.get_vbox()->set_spacing (12);
3606 win.get_vbox()->pack_start (hbox);
3607 hbox.set_border_width (6);
3608 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3610 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3611 place, visually. so do this by hand.
3614 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3615 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3616 spinner.grab_focus();
3622 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3623 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3624 win.set_default_response (RESPONSE_ACCEPT);
3626 spinner.grab_focus ();
3628 switch (win.run ()) {
3629 case RESPONSE_ACCEPT:
3635 times = adjustment.get_value();
3638 if ((current_mouse_mode() == Editing::MouseRange)) {
3639 if (selection->time.length()) {
3640 duplicate_selection (times);
3642 } else if (get_smart_mode()) {
3643 if (selection->time.length()) {
3644 duplicate_selection (times);
3646 duplicate_some_regions (rs, times);
3648 duplicate_some_regions (rs, times);
3653 Editor::set_edit_mode (EditMode m)
3655 Config->set_edit_mode (m);
3659 Editor::cycle_edit_mode ()
3661 switch (Config->get_edit_mode()) {
3663 Config->set_edit_mode (Ripple);
3667 Config->set_edit_mode (Lock);
3670 Config->set_edit_mode (Slide);
3676 Editor::edit_mode_selection_done ( EditMode m )
3678 Config->set_edit_mode ( m );
3682 Editor::snap_type_selection_done (SnapType snaptype)
3684 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3686 ract->set_active ();
3691 Editor::snap_mode_selection_done (SnapMode mode)
3693 RefPtr<RadioAction> ract = snap_mode_action (mode);
3696 ract->set_active (true);
3701 Editor::cycle_edit_point (bool with_marker)
3703 if(Profile->get_mixbus())
3704 with_marker = false;
3706 switch (_edit_point) {
3708 set_edit_point_preference (EditAtPlayhead);
3710 case EditAtPlayhead:
3712 set_edit_point_preference (EditAtSelectedMarker);
3714 set_edit_point_preference (EditAtMouse);
3717 case EditAtSelectedMarker:
3718 set_edit_point_preference (EditAtMouse);
3724 Editor::edit_point_selection_done (EditPoint ep)
3726 set_edit_point_preference ( ep );
3730 Editor::build_zoom_focus_menu ()
3732 using namespace Menu_Helpers;
3734 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3735 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3736 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3737 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3738 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3739 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3741 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3745 Editor::zoom_focus_selection_done ( ZoomFocus f )
3747 RefPtr<RadioAction> ract = zoom_focus_action (f);
3749 ract->set_active ();
3754 Editor::build_track_count_menu ()
3756 using namespace Menu_Helpers;
3758 if (!Profile->get_mixbus()) {
3759 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3760 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3761 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3762 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3763 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3764 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3765 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3766 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3767 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3768 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3769 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3770 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3771 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3773 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3774 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3775 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3776 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3777 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3778 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3779 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3780 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3781 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3782 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3784 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3785 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3786 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3787 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3788 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3789 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3790 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3791 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3792 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3793 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3794 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3799 Editor::set_zoom_preset (int64_t ms)
3802 temporal_zoom_session();
3806 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3807 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3811 Editor::set_visible_track_count (int32_t n)
3813 _visible_track_count = n;
3815 /* if the canvas hasn't really been allocated any size yet, just
3816 record the desired number of visible tracks and return. when canvas
3817 allocation happens, we will get called again and then we can do the
3821 if (_visible_canvas_height <= 1) {
3827 DisplaySuspender ds;
3829 if (_visible_track_count > 0) {
3830 h = trackviews_height() / _visible_track_count;
3831 std::ostringstream s;
3832 s << _visible_track_count;
3834 } else if (_visible_track_count == 0) {
3836 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3837 if ((*i)->marked_for_display()) {
3841 h = trackviews_height() / n;
3844 /* negative value means that the visible track count has
3845 been overridden by explicit track height changes.
3847 visible_tracks_selector.set_text (X_("*"));
3851 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3852 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3855 if (str != visible_tracks_selector.get_text()) {
3856 visible_tracks_selector.set_text (str);
3861 Editor::override_visible_track_count ()
3863 _visible_track_count = -1;
3864 visible_tracks_selector.set_text ( _("*") );
3868 Editor::edit_controls_button_release (GdkEventButton* ev)
3870 if (Keyboard::is_context_menu_event (ev)) {
3871 ARDOUR_UI::instance()->add_route ();
3872 } else if (ev->button == 1) {
3873 selection->clear_tracks ();
3880 Editor::mouse_select_button_release (GdkEventButton* ev)
3882 /* this handles just right-clicks */
3884 if (ev->button != 3) {
3892 Editor::set_zoom_focus (ZoomFocus f)
3894 string str = zoom_focus_strings[(int)f];
3896 if (str != zoom_focus_selector.get_text()) {
3897 zoom_focus_selector.set_text (str);
3900 if (zoom_focus != f) {
3907 Editor::cycle_zoom_focus ()
3909 switch (zoom_focus) {
3911 set_zoom_focus (ZoomFocusRight);
3913 case ZoomFocusRight:
3914 set_zoom_focus (ZoomFocusCenter);
3916 case ZoomFocusCenter:
3917 set_zoom_focus (ZoomFocusPlayhead);
3919 case ZoomFocusPlayhead:
3920 set_zoom_focus (ZoomFocusMouse);
3922 case ZoomFocusMouse:
3923 set_zoom_focus (ZoomFocusEdit);
3926 set_zoom_focus (ZoomFocusLeft);
3932 Editor::set_show_measures (bool yn)
3934 if (_show_measures != yn) {
3937 if ((_show_measures = yn) == true) {
3939 tempo_lines->show();
3942 std::vector<TempoMap::BBTPoint> grid;
3943 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3944 draw_measures (grid);
3952 Editor::toggle_follow_playhead ()
3954 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3956 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3957 set_follow_playhead (tact->get_active());
3961 /** @param yn true to follow playhead, otherwise false.
3962 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3965 Editor::set_follow_playhead (bool yn, bool catch_up)
3967 if (_follow_playhead != yn) {
3968 if ((_follow_playhead = yn) == true && catch_up) {
3970 reset_x_origin_to_follow_playhead ();
3977 Editor::toggle_stationary_playhead ()
3979 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3981 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3982 set_stationary_playhead (tact->get_active());
3987 Editor::set_stationary_playhead (bool yn)
3989 if (_stationary_playhead != yn) {
3990 if ((_stationary_playhead = yn) == true) {
3992 // FIXME need a 3.0 equivalent of this 2.X call
3993 // update_current_screen ();
4000 Editor::playlist_selector () const
4002 return *_playlist_selector;
4006 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4008 if (paste_count == 0) {
4009 /* don't bother calculating an offset that will be zero anyway */
4013 /* calculate basic unsnapped multi-paste offset */
4014 framecnt_t offset = paste_count * duration;
4016 /* snap offset so pos + offset is aligned to the grid */
4017 MusicFrame offset_pos (pos + offset, 0);
4018 snap_to(offset_pos, RoundUpMaybe);
4019 offset = offset_pos.frame - pos;
4025 Editor::get_grid_beat_divisions(framepos_t position)
4027 switch (_snap_type) {
4028 case SnapToBeatDiv128: return 128;
4029 case SnapToBeatDiv64: return 64;
4030 case SnapToBeatDiv32: return 32;
4031 case SnapToBeatDiv28: return 28;
4032 case SnapToBeatDiv24: return 24;
4033 case SnapToBeatDiv20: return 20;
4034 case SnapToBeatDiv16: return 16;
4035 case SnapToBeatDiv14: return 14;
4036 case SnapToBeatDiv12: return 12;
4037 case SnapToBeatDiv10: return 10;
4038 case SnapToBeatDiv8: return 8;
4039 case SnapToBeatDiv7: return 7;
4040 case SnapToBeatDiv6: return 6;
4041 case SnapToBeatDiv5: return 5;
4042 case SnapToBeatDiv4: return 4;
4043 case SnapToBeatDiv3: return 3;
4044 case SnapToBeatDiv2: return 2;
4050 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4051 if the grid is non-musical, returns 0.
4052 if the grid is snapped to bars, returns -1.
4053 @param event_state the current keyboard modifier mask.
4056 Editor::get_grid_music_divisions (uint32_t event_state)
4058 if (snap_mode() == Editing::SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4062 if (snap_mode() != Editing::SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4066 switch (_snap_type) {
4067 case SnapToBeatDiv128: return 128;
4068 case SnapToBeatDiv64: return 64;
4069 case SnapToBeatDiv32: return 32;
4070 case SnapToBeatDiv28: return 28;
4071 case SnapToBeatDiv24: return 24;
4072 case SnapToBeatDiv20: return 20;
4073 case SnapToBeatDiv16: return 16;
4074 case SnapToBeatDiv14: return 14;
4075 case SnapToBeatDiv12: return 12;
4076 case SnapToBeatDiv10: return 10;
4077 case SnapToBeatDiv8: return 8;
4078 case SnapToBeatDiv7: return 7;
4079 case SnapToBeatDiv6: return 6;
4080 case SnapToBeatDiv5: return 5;
4081 case SnapToBeatDiv4: return 4;
4082 case SnapToBeatDiv3: return 3;
4083 case SnapToBeatDiv2: return 2;
4084 case SnapToBeat: return 1;
4085 case SnapToBar : return -1;
4092 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4096 const unsigned divisions = get_grid_beat_divisions(position);
4098 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4101 switch (_snap_type) {
4103 return Evoral::Beats(4.0 / _session->tempo_map().meter_at_frame (position).note_divisor());
4106 const Meter& m = _session->tempo_map().meter_at_frame (position);
4107 return Evoral::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4115 return Evoral::Beats();
4119 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4123 ret = nudge_clock->current_duration (pos);
4124 next = ret + 1; /* XXXX fix me */
4130 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4132 ArdourDialog dialog (_("Playlist Deletion"));
4133 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4134 "If it is kept, its audio files will not be cleaned.\n"
4135 "If it is deleted, audio files used by it alone will be cleaned."),
4138 dialog.set_position (WIN_POS_CENTER);
4139 dialog.get_vbox()->pack_start (label);
4143 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4144 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4145 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4146 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4147 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4149 // by default gtk uses the left most button
4150 keep->grab_focus ();
4152 switch (dialog.run ()) {
4154 /* keep this and all remaining ones */
4159 /* delete this and all others */
4163 case RESPONSE_ACCEPT:
4164 /* delete the playlist */
4168 case RESPONSE_REJECT:
4169 /* keep the playlist */
4181 Editor::audio_region_selection_covers (framepos_t where)
4183 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4184 if ((*a)->region()->covers (where)) {
4193 Editor::prepare_for_cleanup ()
4195 cut_buffer->clear_regions ();
4196 cut_buffer->clear_playlists ();
4198 selection->clear_regions ();
4199 selection->clear_playlists ();
4201 _regions->suspend_redisplay ();
4205 Editor::finish_cleanup ()
4207 _regions->resume_redisplay ();
4211 Editor::transport_loop_location()
4214 return _session->locations()->auto_loop_location();
4221 Editor::transport_punch_location()
4224 return _session->locations()->auto_punch_location();
4231 Editor::control_layout_scroll (GdkEventScroll* ev)
4233 /* Just forward to the normal canvas scroll method. The coordinate
4234 systems are different but since the canvas is always larger than the
4235 track headers, and aligned with the trackview area, this will work.
4237 In the not too distant future this layout is going away anyway and
4238 headers will be on the canvas.
4240 return canvas_scroll_event (ev, false);
4244 Editor::session_state_saved (string)
4247 _snapshots->redisplay ();
4251 Editor::maximise_editing_space ()
4257 Gtk::Window* toplevel = current_toplevel();
4260 toplevel->fullscreen ();
4266 Editor::restore_editing_space ()
4272 Gtk::Window* toplevel = current_toplevel();
4275 toplevel->unfullscreen();
4281 * Make new playlists for a given track and also any others that belong
4282 * to the same active route group with the `select' property.
4287 Editor::new_playlists (TimeAxisView* v)
4289 begin_reversible_command (_("new playlists"));
4290 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4291 _session->playlists->get (playlists);
4292 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4293 commit_reversible_command ();
4297 * Use a copy of the current playlist for a given track and also any others that belong
4298 * to the same active route group with the `select' property.
4303 Editor::copy_playlists (TimeAxisView* v)
4305 begin_reversible_command (_("copy playlists"));
4306 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4307 _session->playlists->get (playlists);
4308 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4309 commit_reversible_command ();
4312 /** Clear the current playlist for a given track and also any others that belong
4313 * to the same active route group with the `select' property.
4318 Editor::clear_playlists (TimeAxisView* v)
4320 begin_reversible_command (_("clear playlists"));
4321 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4322 _session->playlists->get (playlists);
4323 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4324 commit_reversible_command ();
4328 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4330 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4334 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4336 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4340 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4342 atv.clear_playlist ();
4346 Editor::get_y_origin () const
4348 return vertical_adjustment.get_value ();
4351 /** Queue up a change to the viewport x origin.
4352 * @param frame New x origin.
4355 Editor::reset_x_origin (framepos_t frame)
4357 pending_visual_change.add (VisualChange::TimeOrigin);
4358 pending_visual_change.time_origin = frame;
4359 ensure_visual_change_idle_handler ();
4363 Editor::reset_y_origin (double y)
4365 pending_visual_change.add (VisualChange::YOrigin);
4366 pending_visual_change.y_origin = y;
4367 ensure_visual_change_idle_handler ();
4371 Editor::reset_zoom (framecnt_t spp)
4373 if (spp == samples_per_pixel) {
4377 pending_visual_change.add (VisualChange::ZoomLevel);
4378 pending_visual_change.samples_per_pixel = spp;
4379 ensure_visual_change_idle_handler ();
4383 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4385 reset_x_origin (frame);
4388 if (!no_save_visual) {
4389 undo_visual_stack.push_back (current_visual_state(false));
4393 Editor::VisualState::VisualState (bool with_tracks)
4394 : gui_state (with_tracks ? new GUIObjectState : 0)
4398 Editor::VisualState::~VisualState ()
4403 Editor::VisualState*
4404 Editor::current_visual_state (bool with_tracks)
4406 VisualState* vs = new VisualState (with_tracks);
4407 vs->y_position = vertical_adjustment.get_value();
4408 vs->samples_per_pixel = samples_per_pixel;
4409 vs->leftmost_frame = leftmost_frame;
4410 vs->zoom_focus = zoom_focus;
4413 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4420 Editor::undo_visual_state ()
4422 if (undo_visual_stack.empty()) {
4426 VisualState* vs = undo_visual_stack.back();
4427 undo_visual_stack.pop_back();
4430 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4433 use_visual_state (*vs);
4438 Editor::redo_visual_state ()
4440 if (redo_visual_stack.empty()) {
4444 VisualState* vs = redo_visual_stack.back();
4445 redo_visual_stack.pop_back();
4447 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4448 // why do we check here?
4449 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4452 use_visual_state (*vs);
4457 Editor::swap_visual_state ()
4459 if (undo_visual_stack.empty()) {
4460 redo_visual_state ();
4462 undo_visual_state ();
4467 Editor::use_visual_state (VisualState& vs)
4469 PBD::Unwinder<bool> nsv (no_save_visual, true);
4470 DisplaySuspender ds;
4472 vertical_adjustment.set_value (vs.y_position);
4474 set_zoom_focus (vs.zoom_focus);
4475 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4478 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4480 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4481 (*i)->clear_property_cache();
4482 (*i)->reset_visual_state ();
4486 _routes->update_visibility ();
4489 /** This is the core function that controls the zoom level of the canvas. It is called
4490 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4491 * @param spp new number of samples per pixel
4494 Editor::set_samples_per_pixel (framecnt_t spp)
4500 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4501 const framecnt_t lots_of_pixels = 4000;
4503 /* if the zoom level is greater than what you'd get trying to display 3
4504 * days of audio on a really big screen, then it's too big.
4507 if (spp * lots_of_pixels > three_days) {
4511 samples_per_pixel = spp;
4514 tempo_lines->tempo_map_changed(_session->tempo_map().music_origin());
4517 bool const showing_time_selection = selection->time.length() > 0;
4519 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4520 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4521 (*i)->reshow_selection (selection->time);
4525 ZoomChanged (); /* EMIT_SIGNAL */
4527 ArdourCanvas::GtkCanvasViewport* c;
4529 c = get_track_canvas();
4531 c->canvas()->zoomed ();
4534 if (playhead_cursor) {
4535 playhead_cursor->set_position (playhead_cursor->current_frame ());
4538 refresh_location_display();
4539 _summary->set_overlays_dirty ();
4541 update_marker_labels ();
4547 Editor::playhead_cursor_sample () const
4549 return playhead_cursor->current_frame();
4553 Editor::queue_visual_videotimeline_update ()
4556 * pending_visual_change.add (VisualChange::VideoTimeline);
4557 * or maybe even more specific: which videotimeline-image
4558 * currently it calls update_video_timeline() to update
4559 * _all outdated_ images on the video-timeline.
4560 * see 'exposeimg()' in video_image_frame.cc
4562 ensure_visual_change_idle_handler ();
4566 Editor::ensure_visual_change_idle_handler ()
4568 if (pending_visual_change.idle_handler_id < 0) {
4569 // see comment in add_to_idle_resize above.
4570 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4571 pending_visual_change.being_handled = false;
4576 Editor::_idle_visual_changer (void* arg)
4578 return static_cast<Editor*>(arg)->idle_visual_changer ();
4582 Editor::idle_visual_changer ()
4584 /* set_horizontal_position() below (and maybe other calls) call
4585 gtk_main_iteration(), so it's possible that a signal will be handled
4586 half-way through this method. If this signal wants an
4587 idle_visual_changer we must schedule another one after this one, so
4588 mark the idle_handler_id as -1 here to allow that. Also make a note
4589 that we are doing the visual change, so that changes in response to
4590 super-rapid-screen-update can be dropped if we are still processing
4594 pending_visual_change.idle_handler_id = -1;
4595 pending_visual_change.being_handled = true;
4597 VisualChange vc = pending_visual_change;
4599 pending_visual_change.pending = (VisualChange::Type) 0;
4601 visual_changer (vc);
4603 pending_visual_change.being_handled = false;
4605 return 0; /* this is always a one-shot call */
4609 Editor::visual_changer (const VisualChange& vc)
4611 double const last_time_origin = horizontal_position ();
4613 if (vc.pending & VisualChange::ZoomLevel) {
4614 set_samples_per_pixel (vc.samples_per_pixel);
4616 compute_fixed_ruler_scale ();
4618 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4619 update_tempo_based_rulers ();
4621 update_video_timeline();
4624 if (vc.pending & VisualChange::TimeOrigin) {
4625 set_horizontal_position (sample_to_pixel_unrounded (vc.time_origin));
4628 if (vc.pending & VisualChange::YOrigin) {
4629 vertical_adjustment.set_value (vc.y_origin);
4632 if (last_time_origin == horizontal_position ()) {
4633 /* changed signal not emitted */
4634 update_fixed_rulers ();
4635 redisplay_tempo (true);
4638 if (!(vc.pending & VisualChange::ZoomLevel)) {
4639 update_video_timeline();
4642 _summary->set_overlays_dirty ();
4645 struct EditorOrderTimeAxisSorter {
4646 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4647 return a->order () < b->order ();
4652 Editor::sort_track_selection (TrackViewList& sel)
4654 EditorOrderTimeAxisSorter cmp;
4659 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4662 framepos_t where = 0;
4663 EditPoint ep = _edit_point;
4665 if (Profile->get_mixbus()) {
4666 if (ep == EditAtSelectedMarker) {
4667 ep = EditAtPlayhead;
4671 if (from_outside_canvas && (ep == EditAtMouse)) {
4672 ep = EditAtPlayhead;
4673 } else if (from_context_menu && (ep == EditAtMouse)) {
4674 return canvas_event_sample (&context_click_event, 0, 0);
4677 if (entered_marker) {
4678 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4679 return entered_marker->position();
4682 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4683 ep = EditAtSelectedMarker;
4686 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4687 ep = EditAtPlayhead;
4690 MusicFrame snap_mf (0, 0);
4693 case EditAtPlayhead:
4694 if (_dragging_playhead && _control_scroll_target) {
4695 where = *_control_scroll_target;
4697 where = _session->audible_frame();
4699 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4702 case EditAtSelectedMarker:
4703 if (!selection->markers.empty()) {
4705 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4708 where = loc->start();
4712 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4720 if (!mouse_frame (where, ignored)) {
4721 /* XXX not right but what can we do ? */
4724 snap_mf.frame = where;
4726 where = snap_mf.frame;
4727 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4735 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4737 if (!_session) return;
4739 begin_reversible_command (cmd);
4743 if ((tll = transport_loop_location()) == 0) {
4744 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4745 XMLNode &before = _session->locations()->get_state();
4746 _session->locations()->add (loc, true);
4747 _session->set_auto_loop_location (loc);
4748 XMLNode &after = _session->locations()->get_state();
4749 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4751 XMLNode &before = tll->get_state();
4752 tll->set_hidden (false, this);
4753 tll->set (start, end);
4754 XMLNode &after = tll->get_state();
4755 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4758 commit_reversible_command ();
4762 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4764 if (!_session) return;
4766 begin_reversible_command (cmd);
4770 if ((tpl = transport_punch_location()) == 0) {
4771 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4772 XMLNode &before = _session->locations()->get_state();
4773 _session->locations()->add (loc, true);
4774 _session->set_auto_punch_location (loc);
4775 XMLNode &after = _session->locations()->get_state();
4776 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4778 XMLNode &before = tpl->get_state();
4779 tpl->set_hidden (false, this);
4780 tpl->set (start, end);
4781 XMLNode &after = tpl->get_state();
4782 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4785 commit_reversible_command ();
4788 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4789 * @param rs List to which found regions are added.
4790 * @param where Time to look at.
4791 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4794 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4796 const TrackViewList* tracks;
4799 tracks = &track_views;
4804 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4806 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4809 boost::shared_ptr<Track> tr;
4810 boost::shared_ptr<Playlist> pl;
4812 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4814 boost::shared_ptr<RegionList> regions = pl->regions_at (
4815 (framepos_t) floor ( (double) where * tr->speed()));
4817 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4818 RegionView* rv = rtv->view()->find_view (*i);
4829 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4831 const TrackViewList* tracks;
4834 tracks = &track_views;
4839 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4840 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4842 boost::shared_ptr<Track> tr;
4843 boost::shared_ptr<Playlist> pl;
4845 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4847 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4848 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4850 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4852 RegionView* rv = rtv->view()->find_view (*i);
4863 /** Get regions using the following method:
4865 * Make a region list using:
4866 * (a) any selected regions
4867 * (b) the intersection of any selected tracks and the edit point(*)
4868 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4870 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4872 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4876 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4878 RegionSelection regions;
4880 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4881 regions.add (entered_regionview);
4883 regions = selection->regions;
4886 if ( regions.empty() ) {
4887 TrackViewList tracks = selection->tracks;
4889 if (!tracks.empty()) {
4890 /* no region selected or entered, but some selected tracks:
4891 * act on all regions on the selected tracks at the edit point
4893 framepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4894 get_regions_at(regions, where, tracks);
4901 /** Get regions using the following method:
4903 * Make a region list using:
4904 * (a) any selected regions
4905 * (b) the intersection of any selected tracks and the edit point(*)
4906 * (c) if neither exists, then whatever region is under the mouse
4908 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4910 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4913 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4915 RegionSelection regions;
4917 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4918 regions.add (entered_regionview);
4920 regions = selection->regions;
4923 if ( regions.empty() ) {
4924 TrackViewList tracks = selection->tracks;
4926 if (!tracks.empty()) {
4927 /* no region selected or entered, but some selected tracks:
4928 * act on all regions on the selected tracks at the edit point
4930 get_regions_at(regions, pos, tracks);
4937 /** Start with regions that are selected, or the entered regionview if none are selected.
4938 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4939 * of the regions that we started with.
4943 Editor::get_regions_from_selection_and_entered () const
4945 RegionSelection regions = selection->regions;
4947 if (regions.empty() && entered_regionview) {
4948 regions.add (entered_regionview);
4955 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4957 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4958 RouteTimeAxisView* rtav;
4960 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4961 boost::shared_ptr<Playlist> pl;
4962 std::vector<boost::shared_ptr<Region> > results;
4963 boost::shared_ptr<Track> tr;
4965 if ((tr = rtav->track()) == 0) {
4970 if ((pl = (tr->playlist())) != 0) {
4971 boost::shared_ptr<Region> r = pl->region_by_id (id);
4973 RegionView* rv = rtav->view()->find_view (r);
4975 regions.push_back (rv);
4984 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4987 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4988 MidiTimeAxisView* mtav;
4990 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4992 mtav->get_per_region_note_selection (selection);
4999 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5001 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5003 RouteTimeAxisView* tatv;
5005 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5007 boost::shared_ptr<Playlist> pl;
5008 vector<boost::shared_ptr<Region> > results;
5010 boost::shared_ptr<Track> tr;
5012 if ((tr = tatv->track()) == 0) {
5017 if ((pl = (tr->playlist())) != 0) {
5018 if (src_comparison) {
5019 pl->get_source_equivalent_regions (region, results);
5021 pl->get_region_list_equivalent_regions (region, results);
5025 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5026 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5027 regions.push_back (marv);
5036 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5038 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5039 RouteTimeAxisView* tatv;
5040 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5041 if (!tatv->track()) {
5044 RegionView* marv = tatv->view()->find_view (region);
5054 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5056 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5057 RouteTimeAxisView* rtav;
5058 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5059 if (rtav->route() == route) {
5068 Editor::show_rhythm_ferret ()
5070 if (rhythm_ferret == 0) {
5071 rhythm_ferret = new RhythmFerret(*this);
5074 rhythm_ferret->set_session (_session);
5075 rhythm_ferret->show ();
5076 rhythm_ferret->present ();
5080 Editor::first_idle ()
5082 MessageDialog* dialog = 0;
5084 if (track_views.size() > 1) {
5085 Timers::TimerSuspender t;
5086 dialog = new MessageDialog (
5087 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5091 ARDOUR_UI::instance()->flush_pending (60);
5094 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5098 /* now that all regionviews should exist, setup region selection */
5102 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5103 /* this is cumulative: rs is NOT cleared each time */
5104 get_regionviews_by_id (*pr, rs);
5107 selection->set (rs);
5109 // first idle adds route children (automation tracks), so we need to redisplay here
5110 _routes->redisplay ();
5114 if (_session->undo_depth() == 0) {
5115 undo_action->set_sensitive(false);
5117 redo_action->set_sensitive(false);
5118 begin_selection_op_history ();
5124 Editor::_idle_resize (gpointer arg)
5126 return ((Editor*)arg)->idle_resize ();
5130 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5132 if (resize_idle_id < 0) {
5133 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5134 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5135 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5137 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5138 _pending_resize_amount = 0;
5141 /* make a note of the smallest resulting height, so that we can clamp the
5142 lower limit at TimeAxisView::hSmall */
5144 int32_t min_resulting = INT32_MAX;
5146 _pending_resize_amount += h;
5147 _pending_resize_view = view;
5149 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5151 if (selection->tracks.contains (_pending_resize_view)) {
5152 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5153 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5157 if (min_resulting < 0) {
5162 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5163 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5167 /** Handle pending resizing of tracks */
5169 Editor::idle_resize ()
5171 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5173 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5174 selection->tracks.contains (_pending_resize_view)) {
5176 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5177 if (*i != _pending_resize_view) {
5178 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5183 _pending_resize_amount = 0;
5184 _group_tabs->set_dirty ();
5185 resize_idle_id = -1;
5193 ENSURE_GUI_THREAD (*this, &Editor::located);
5196 playhead_cursor->set_position (_session->audible_frame ());
5197 if (_follow_playhead && !_pending_initial_locate) {
5198 reset_x_origin_to_follow_playhead ();
5202 _pending_locate_request = false;
5203 _pending_initial_locate = false;
5204 _last_update_time = 0;
5208 Editor::region_view_added (RegionView * rv)
5210 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5212 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5213 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5214 if (rv->region()->id () == (*rnote).first) {
5215 mrv->select_notes ((*rnote).second);
5216 selection->pending_midi_note_selection.erase(rnote);
5222 _summary->set_background_dirty ();
5226 Editor::region_view_removed ()
5228 _summary->set_background_dirty ();
5232 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5234 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5235 if ((*j)->stripable() == s) {
5244 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5246 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5247 if ((*j)->control() == c) {
5251 TimeAxisView::Children kids = (*j)->get_child_list ();
5253 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5254 if ((*k)->control() == c) {
5264 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5268 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5269 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5279 Editor::suspend_route_redisplay ()
5282 _routes->suspend_redisplay();
5287 Editor::resume_route_redisplay ()
5290 _routes->redisplay(); // queue redisplay
5291 _routes->resume_redisplay();
5296 Editor::add_vcas (VCAList& vlist)
5300 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5301 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5304 add_stripables (sl);
5308 Editor::add_routes (RouteList& rlist)
5312 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5316 add_stripables (sl);
5320 Editor::add_stripables (StripableList& sl)
5322 list<TimeAxisView*> new_views;
5323 boost::shared_ptr<VCA> v;
5324 boost::shared_ptr<Route> r;
5325 TrackViewList new_selection;
5326 bool from_scratch = (track_views.size() == 0);
5328 sl.sort (Stripable::Sorter());
5330 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5332 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5334 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5336 new_views.push_back (vtv);
5338 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5340 if (r->is_auditioner() || r->is_monitor()) {
5344 RouteTimeAxisView* rtv;
5345 DataType dt = r->input()->default_type();
5347 if (dt == ARDOUR::DataType::AUDIO) {
5348 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5350 } else if (dt == ARDOUR::DataType::MIDI) {
5351 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5354 throw unknown_type();
5357 new_views.push_back (rtv);
5358 track_views.push_back (rtv);
5359 new_selection.push_back (rtv);
5361 rtv->effective_gain_display ();
5363 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5364 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5368 if (new_views.size() > 0) {
5369 _routes->time_axis_views_added (new_views);
5370 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5373 /* note: !new_selection.empty() means that we got some routes rather
5377 if (!from_scratch && !new_selection.empty()) {
5378 selection->set (new_selection);
5379 begin_selection_op_history();
5382 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5383 show_editor_mixer (true);
5386 editor_list_button.set_sensitive (true);
5390 Editor::timeaxisview_deleted (TimeAxisView *tv)
5392 if (tv == entered_track) {
5396 if (_session && _session->deletion_in_progress()) {
5397 /* the situation is under control */
5401 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5403 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5405 _routes->route_removed (tv);
5407 TimeAxisView::Children c = tv->get_child_list ();
5408 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5409 if (entered_track == i->get()) {
5414 /* remove it from the list of track views */
5416 TrackViewList::iterator i;
5418 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5419 i = track_views.erase (i);
5422 /* update whatever the current mixer strip is displaying, if revelant */
5424 boost::shared_ptr<Route> route;
5427 route = rtav->route ();
5430 if (current_mixer_strip && current_mixer_strip->route() == route) {
5432 TimeAxisView* next_tv;
5434 if (track_views.empty()) {
5436 } else if (i == track_views.end()) {
5437 next_tv = track_views.front();
5442 // skip VCAs (cannot be selected, n/a in editor-mixer)
5443 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5444 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5445 next_tv = track_views.front();
5447 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5448 /* just in case: no master, only a VCA remains */
5454 set_selected_mixer_strip (*next_tv);
5456 /* make the editor mixer strip go away setting the
5457 * button to inactive (which also unticks the menu option)
5460 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5466 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5471 if (apply_to_selection) {
5472 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5474 TrackSelection::iterator j = i;
5477 hide_track_in_display (*i, false);
5482 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5484 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5485 // this will hide the mixer strip
5486 set_selected_mixer_strip (*tv);
5489 _routes->hide_track_in_display (*tv);
5494 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5499 _routes->show_track_in_display (*tv);
5500 if (move_into_view) {
5501 ensure_time_axis_view_is_visible (*tv, false);
5506 Editor::sync_track_view_list_and_routes ()
5508 track_views = TrackViewList (_routes->views ());
5510 _summary->set_background_dirty();
5511 _group_tabs->set_dirty ();
5513 return false; // do not call again (until needed)
5517 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5519 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5524 /** Find a RouteTimeAxisView by the ID of its route */
5526 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5528 RouteTimeAxisView* v;
5530 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5531 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5532 if(v->route()->id() == id) {
5542 Editor::fit_route_group (RouteGroup *g)
5544 TrackViewList ts = axis_views_from_routes (g->route_list ());
5549 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5551 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5554 _session->cancel_audition ();
5558 if (_session->is_auditioning()) {
5559 _session->cancel_audition ();
5560 if (r == last_audition_region) {
5565 _session->audition_region (r);
5566 last_audition_region = r;
5571 Editor::hide_a_region (boost::shared_ptr<Region> r)
5573 r->set_hidden (true);
5577 Editor::show_a_region (boost::shared_ptr<Region> r)
5579 r->set_hidden (false);
5583 Editor::audition_region_from_region_list ()
5585 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5589 Editor::hide_region_from_region_list ()
5591 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5595 Editor::show_region_in_region_list ()
5597 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5601 Editor::step_edit_status_change (bool yn)
5604 start_step_editing ();
5606 stop_step_editing ();
5611 Editor::start_step_editing ()
5613 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5617 Editor::stop_step_editing ()
5619 step_edit_connection.disconnect ();
5623 Editor::check_step_edit ()
5625 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5626 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5628 mtv->check_step_edit ();
5632 return true; // do it again, till we stop
5636 Editor::scroll_press (Direction dir)
5638 ++_scroll_callbacks;
5640 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5641 /* delay the first auto-repeat */
5647 scroll_backward (1);
5655 scroll_up_one_track ();
5659 scroll_down_one_track ();
5663 /* do hacky auto-repeat */
5664 if (!_scroll_connection.connected ()) {
5666 _scroll_connection = Glib::signal_timeout().connect (
5667 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5670 _scroll_callbacks = 0;
5677 Editor::scroll_release ()
5679 _scroll_connection.disconnect ();
5682 /** Queue a change for the Editor viewport x origin to follow the playhead */
5684 Editor::reset_x_origin_to_follow_playhead ()
5686 framepos_t const frame = playhead_cursor->current_frame ();
5688 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5690 if (_session->transport_speed() < 0) {
5692 if (frame > (current_page_samples() / 2)) {
5693 center_screen (frame-(current_page_samples()/2));
5695 center_screen (current_page_samples()/2);
5702 if (frame < leftmost_frame) {
5704 if (_session->transport_rolling()) {
5705 /* rolling; end up with the playhead at the right of the page */
5706 l = frame - current_page_samples ();
5708 /* not rolling: end up with the playhead 1/4 of the way along the page */
5709 l = frame - current_page_samples() / 4;
5713 if (_session->transport_rolling()) {
5714 /* rolling: end up with the playhead on the left of the page */
5717 /* not rolling: end up with the playhead 3/4 of the way along the page */
5718 l = frame - 3 * current_page_samples() / 4;
5726 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5732 Editor::super_rapid_screen_update ()
5734 if (!_session || !_session->engine().running()) {
5738 /* METERING / MIXER STRIPS */
5740 /* update track meters, if required */
5741 if (contents().is_mapped() && meters_running) {
5742 RouteTimeAxisView* rtv;
5743 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5744 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5745 rtv->fast_update ();
5750 /* and any current mixer strip */
5751 if (current_mixer_strip) {
5752 current_mixer_strip->fast_update ();
5755 /* PLAYHEAD AND VIEWPORT */
5757 /* There are a few reasons why we might not update the playhead / viewport stuff:
5759 * 1. we don't update things when there's a pending locate request, otherwise
5760 * when the editor requests a locate there is a chance that this method
5761 * will move the playhead before the locate request is processed, causing
5763 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5764 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5766 if (_pending_locate_request || !_session->transport_rolling ()) {
5767 _last_update_time = 0;
5771 if (_dragging_playhead) {
5772 _last_update_time = 0;
5776 bool latent_locate = false;
5777 framepos_t frame = _session->audible_frame (&latent_locate);
5778 const int64_t now = g_get_monotonic_time ();
5781 if (_last_update_time > 0) {
5782 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_frame_rate () * 1e-6;
5783 framepos_t guess = playhead_cursor->current_frame () + rint (ds);
5784 err = frame - guess;
5786 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5787 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5790 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5792 err, _err_screen_engine);
5797 _err_screen_engine = 0;
5800 if (err > 8192 || latent_locate) {
5801 // in case of x-runs or freewheeling
5802 _last_update_time = 0;
5804 _last_update_time = now;
5807 if (playhead_cursor->current_frame () == frame) {
5811 playhead_cursor->set_position (frame);
5813 if (_session->requested_return_frame() >= 0) {
5814 _last_update_time = 0;
5818 if (!_follow_playhead || pending_visual_change.being_handled) {
5819 /* We only do this if we aren't already
5820 * handling a visual change (ie if
5821 * pending_visual_change.being_handled is
5822 * false) so that these requests don't stack
5823 * up there are too many of them to handle in
5829 if (!_stationary_playhead) {
5830 reset_x_origin_to_follow_playhead ();
5832 framepos_t const frame = playhead_cursor->current_frame ();
5833 double target = ((double)frame - (double)current_page_samples() / 2.0);
5834 if (target <= 0.0) {
5837 // compare to EditorCursor::set_position()
5838 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5839 double const new_pos = sample_to_pixel_unrounded (target);
5840 if (rint (new_pos) != rint (old_pos)) {
5841 reset_x_origin (pixel_to_sample (new_pos));
5848 Editor::session_going_away ()
5850 _have_idled = false;
5852 _session_connections.drop_connections ();
5854 super_rapid_screen_update_connection.disconnect ();
5856 selection->clear ();
5857 cut_buffer->clear ();
5859 clicked_regionview = 0;
5860 clicked_axisview = 0;
5861 clicked_routeview = 0;
5862 entered_regionview = 0;
5864 _last_update_time = 0;
5867 playhead_cursor->hide ();
5869 /* rip everything out of the list displays */
5873 _route_groups->clear ();
5875 /* do this first so that deleting a track doesn't reset cms to null
5876 and thus cause a leak.
5879 if (current_mixer_strip) {
5880 if (current_mixer_strip->get_parent() != 0) {
5881 global_hpacker.remove (*current_mixer_strip);
5883 delete current_mixer_strip;
5884 current_mixer_strip = 0;
5887 /* delete all trackviews */
5889 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5892 track_views.clear ();
5894 nudge_clock->set_session (0);
5896 editor_list_button.set_active(false);
5897 editor_list_button.set_sensitive(false);
5899 /* clear tempo/meter rulers */
5900 remove_metric_marks ();
5902 clear_marker_display ();
5907 stop_step_editing ();
5911 /* get rid of any existing editor mixer strip */
5913 WindowTitle title(Glib::get_application_name());
5914 title += _("Editor");
5916 own_window()->set_title (title.get_string());
5919 SessionHandlePtr::session_going_away ();
5923 Editor::trigger_script (int i)
5925 LuaInstance::instance()-> call_action (i);
5929 Editor::show_editor_list (bool yn)
5932 _editor_list_vbox.show ();
5934 _editor_list_vbox.hide ();
5939 Editor::change_region_layering_order (bool from_context_menu)
5941 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5943 if (!clicked_routeview) {
5944 if (layering_order_editor) {
5945 layering_order_editor->hide ();
5950 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5956 boost::shared_ptr<Playlist> pl = track->playlist();
5962 if (layering_order_editor == 0) {
5963 layering_order_editor = new RegionLayeringOrderEditor (*this);
5966 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5967 layering_order_editor->maybe_present ();
5971 Editor::update_region_layering_order_editor ()
5973 if (layering_order_editor && layering_order_editor->is_visible ()) {
5974 change_region_layering_order (true);
5979 Editor::setup_fade_images ()
5981 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5982 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5983 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5984 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5985 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5987 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5988 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5989 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5990 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5991 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5995 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5997 Editor::action_menu_item (std::string const & name)
5999 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6002 return *manage (a->create_menu_item ());
6006 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6008 EventBox* b = manage (new EventBox);
6009 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6010 Label* l = manage (new Label (name));
6014 _the_notebook.append_page (widget, *b);
6018 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6020 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6021 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6024 if (ev->type == GDK_2BUTTON_PRESS) {
6026 /* double-click on a notebook tab shrinks or expands the notebook */
6028 if (_notebook_shrunk) {
6029 if (pre_notebook_shrink_pane_width) {
6030 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6032 _notebook_shrunk = false;
6034 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6036 /* this expands the LHS of the edit pane to cover the notebook
6037 PAGE but leaves the tabs visible.
6039 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6040 _notebook_shrunk = true;
6048 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6050 using namespace Menu_Helpers;
6052 MenuList& items = _control_point_context_menu.items ();
6055 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6056 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6057 if (!can_remove_control_point (item)) {
6058 items.back().set_sensitive (false);
6061 _control_point_context_menu.popup (event->button.button, event->button.time);
6065 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6067 using namespace Menu_Helpers;
6069 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6074 /* We need to get the selection here and pass it to the operations, since
6075 popping up the menu will cause a region leave event which clears
6076 entered_regionview. */
6078 MidiRegionView& mrv = note->region_view();
6079 const RegionSelection rs = get_regions_from_selection_and_entered ();
6080 const uint32_t sel_size = mrv.selection_size ();
6082 MenuList& items = _note_context_menu.items();
6086 items.push_back(MenuElem(_("Delete"),
6087 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6090 items.push_back(MenuElem(_("Edit..."),
6091 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6092 if (sel_size != 1) {
6093 items.back().set_sensitive (false);
6096 items.push_back(MenuElem(_("Transpose..."),
6097 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6100 items.push_back(MenuElem(_("Legatize"),
6101 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6103 items.back().set_sensitive (false);
6106 items.push_back(MenuElem(_("Quantize..."),
6107 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6109 items.push_back(MenuElem(_("Remove Overlap"),
6110 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6112 items.back().set_sensitive (false);
6115 items.push_back(MenuElem(_("Transform..."),
6116 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6118 _note_context_menu.popup (event->button.button, event->button.time);
6122 Editor::zoom_vertical_modifier_released()
6124 _stepping_axis_view = 0;
6128 Editor::ui_parameter_changed (string parameter)
6130 if (parameter == "icon-set") {
6131 while (!_cursor_stack.empty()) {
6132 _cursor_stack.pop_back();
6134 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6135 _cursor_stack.push_back(_cursors->grabber);
6136 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6137 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6139 } else if (parameter == "draggable-playhead") {
6140 if (_verbose_cursor) {
6141 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6147 Editor::use_own_window (bool and_fill_it)
6149 bool new_window = !own_window();
6151 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6153 if (win && new_window) {
6154 win->set_name ("EditorWindow");
6156 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6158 // win->signal_realize().connect (*this, &Editor::on_realize);
6159 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6160 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6161 win->set_data ("ardour-bindings", bindings);
6166 DisplaySuspender ds;
6167 contents().show_all ();
6169 /* XXX: this is a bit unfortunate; it would probably
6170 be nicer if we could just call show () above rather
6171 than needing the show_all ()
6174 /* re-hide stuff if necessary */
6175 editor_list_button_toggled ();
6176 parameter_changed ("show-summary");
6177 parameter_changed ("show-group-tabs");
6178 parameter_changed ("show-zoom-tools");
6180 /* now reset all audio_time_axis heights, because widgets might need
6186 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6187 tv = (static_cast<TimeAxisView*>(*i));
6188 tv->reset_height ();
6191 if (current_mixer_strip) {
6192 current_mixer_strip->hide_things ();
6193 current_mixer_strip->parameter_changed ("mixer-element-visibility");