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/gtk_ui.h"
61 #include "gtkmm2ext/keyboard.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
66 #include "ardour/analysis_graph.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
78 #include "ardour/vca_manager.h"
79 #include "ardour/vca.h"
81 #include "canvas/debug.h"
82 #include "canvas/note.h"
83 #include "canvas/text.h"
85 #include "widgets/ardour_spacer.h"
86 #include "widgets/eventboxext.h"
87 #include "widgets/tooltips.h"
89 #include "control_protocol/control_protocol.h"
92 #include "analysis_window.h"
93 #include "audio_clock.h"
94 #include "audio_region_view.h"
95 #include "audio_streamview.h"
96 #include "audio_time_axis.h"
97 #include "automation_time_axis.h"
98 #include "bundle_manager.h"
99 #include "crossfade_edit.h"
102 #include "editing_convert.h"
104 #include "editor_cursors.h"
105 #include "editor_drag.h"
106 #include "editor_group_tabs.h"
107 #include "editor_locations.h"
108 #include "editor_regions.h"
109 #include "editor_route_groups.h"
110 #include "editor_routes.h"
111 #include "editor_snapshots.h"
112 #include "editor_summary.h"
113 #include "enums_convert.h"
114 #include "export_report.h"
115 #include "global_port_matrix.h"
116 #include "gui_object.h"
117 #include "gui_thread.h"
118 #include "keyboard.h"
119 #include "luainstance.h"
121 #include "midi_region_view.h"
122 #include "midi_time_axis.h"
123 #include "mixer_strip.h"
124 #include "mixer_ui.h"
125 #include "mouse_cursors.h"
126 #include "note_base.h"
127 #include "playlist_selector.h"
128 #include "public_editor.h"
129 #include "quantize_dialog.h"
130 #include "region_layering_order_editor.h"
131 #include "rgb_macros.h"
132 #include "rhythm_ferret.h"
133 #include "route_sorter.h"
134 #include "selection.h"
135 #include "simple_progress_dialog.h"
137 #include "grid_lines.h"
138 #include "time_axis_view.h"
139 #include "time_info_box.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 ArdourWidgets;
151 using namespace ARDOUR_UI_UTILS;
154 using namespace Glib;
155 using namespace Gtkmm2ext;
156 using namespace Editing;
158 using PBD::internationalize;
160 using Gtkmm2ext::Keyboard;
162 double Editor::timebar_height = 15.0;
164 static const gchar *_grid_type_strings[] = {
173 N_("1/3 (8th triplet)"), // or "1/12" ?
174 N_("1/6 (16th triplet)"),
175 N_("1/12 (32nd triplet)"),
176 N_("1/24 (64th triplet)"),
177 N_("1/5 (8th quintuplet)"),
178 N_("1/10 (16th quintuplet)"),
179 N_("1/20 (32nd quintuplet)"),
180 N_("1/7 (8th septuplet)"),
181 N_("1/14 (16th septuplet)"),
182 N_("1/28 (32nd septuplet)"),
189 static const gchar *_edit_point_strings[] = {
196 static const gchar *_edit_mode_strings[] = {
204 static const gchar *_zoom_focus_strings[] = {
214 #ifdef USE_RUBBERBAND
215 static const gchar *_rb_opt_strings[] = {
218 N_("Balanced multitimbral mixture"),
219 N_("Unpitched percussion with stable notes"),
220 N_("Crisp monophonic instrumental"),
221 N_("Unpitched solo percussion"),
222 N_("Resample without preserving pitch"),
227 /* Robin says: this should be odd to accomodate cairo drawing offset (width/2 rounds up to pixel boundary) */
229 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
231 #define COMBO_TRIANGLE_WIDTH 11 // as-measured for win/linux.
235 : PublicEditor (global_hpacker)
236 , editor_mixer_strip_width (Wide)
237 , constructed (false)
238 , _playlist_selector (0)
240 , no_save_visual (false)
241 , _leftmost_sample (0)
242 , samples_per_pixel (2048)
243 , zoom_focus (ZoomFocusPlayhead)
244 , mouse_mode (MouseObject)
245 , pre_internal_grid_type (GridTypeBeat)
246 , pre_internal_snap_mode (SnapOff)
247 , internal_grid_type (GridTypeBeat)
248 , internal_snap_mode (SnapOff)
249 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
250 , _notebook_shrunk (false)
251 , location_marker_color (0)
252 , location_range_color (0)
253 , location_loop_color (0)
254 , location_punch_color (0)
255 , location_cd_marker_color (0)
257 , _show_marker_lines (false)
258 , clicked_axisview (0)
259 , clicked_routeview (0)
260 , clicked_regionview (0)
261 , clicked_selection (0)
262 , clicked_control_point (0)
263 , button_release_can_deselect (true)
264 , _mouse_changed_selection (false)
265 , region_edit_menu_split_item (0)
266 , region_edit_menu_split_multichannel_item (0)
267 , track_region_edit_playlist_menu (0)
268 , track_edit_playlist_submenu (0)
269 , track_selection_edit_playlist_submenu (0)
270 , _popup_region_menu_item (0)
272 , _track_canvas_viewport (0)
273 , within_track_canvas (false)
274 , _verbose_cursor (0)
278 , range_marker_group (0)
279 , transport_marker_group (0)
280 , cd_marker_group (0)
281 , _time_markers_group (0)
282 , hv_scroll_group (0)
284 , cursor_scroll_group (0)
285 , no_scroll_group (0)
286 , _trackview_group (0)
287 , _drag_motion_group (0)
288 , _canvas_drop_zone (0)
289 , no_ruler_shown_update (false)
290 , ruler_grabbed_widget (0)
292 , minsec_mark_interval (0)
293 , minsec_mark_modulo (0)
295 , timecode_ruler_scale (timecode_show_many_hours)
296 , timecode_mark_modulo (0)
297 , timecode_nmarks (0)
298 , _samples_ruler_interval (0)
299 , bbt_ruler_scale (bbt_show_many)
302 , bbt_bar_helper_on (0)
303 , bbt_accent_modulo (0)
308 , visible_timebars (0)
309 , editor_ruler_menu (0)
313 , range_marker_bar (0)
314 , transport_marker_bar (0)
316 , minsec_label (_("Mins:Secs"))
317 , bbt_label (_("Bars:Beats"))
318 , timecode_label (_("Timecode"))
319 , samples_label (_("Samples"))
320 , tempo_label (_("Tempo"))
321 , meter_label (_("Meter"))
322 , mark_label (_("Location Markers"))
323 , range_mark_label (_("Range Markers"))
324 , transport_mark_label (_("Loop/Punch Ranges"))
325 , cd_mark_label (_("CD Markers"))
326 , videotl_label (_("Video Timeline"))
329 , playhead_cursor (0)
330 , _region_boundary_cache_dirty (true)
331 , edit_packer (4, 4, true)
332 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
333 , horizontal_adjustment (0.0, 0.0, 1e16)
334 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
335 , controls_layout (unused_adjustment, vertical_adjustment)
336 , _scroll_callbacks (0)
337 , _visible_canvas_width (0)
338 , _visible_canvas_height (0)
339 , _full_canvas_height (0)
340 , edit_controls_left_menu (0)
341 , edit_controls_right_menu (0)
342 , visual_change_queued(false)
343 , _last_update_time (0)
344 , _err_screen_engine (0)
345 , cut_buffer_start (0)
346 , cut_buffer_length (0)
347 , button_bindings (0)
348 , last_paste_pos (-1)
351 , current_interthread_info (0)
352 , analysis_window (0)
353 , select_new_marker (false)
355 , scrubbing_direction (0)
356 , scrub_reversals (0)
357 , scrub_reverse_distance (0)
358 , have_pending_keyboard_selection (false)
359 , pending_keyboard_selection_start (0)
360 , _grid_type (GridTypeBeat)
361 , _snap_mode (SnapOff)
362 , ignore_gui_changes (false)
363 , _drags (new DragManager (this))
365 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
366 , _dragging_playhead (false)
367 , _dragging_edit_point (false)
368 , _follow_playhead (true)
369 , _stationary_playhead (false)
372 , global_rect_group (0)
373 , time_line_group (0)
374 , tempo_marker_menu (0)
375 , meter_marker_menu (0)
377 , range_marker_menu (0)
378 , transport_marker_menu (0)
379 , new_transport_marker_menu (0)
381 , marker_menu_item (0)
382 , bbt_beat_subdivision (4)
383 , _visible_track_count (-1)
384 , toolbar_selection_clock_table (2,3)
385 , automation_mode_button (_("mode"))
386 , selection (new Selection (this, true))
387 , cut_buffer (new Selection (this, false))
388 , _selection_memento (new SelectionMemento())
389 , _all_region_actions_sensitized (false)
390 , _ignore_region_action (false)
391 , _last_region_menu_was_main (false)
392 , _track_selection_change_without_scroll (false)
393 , _editor_track_selection_change_without_scroll (false)
394 , cd_marker_bar_drag_rect (0)
395 , range_bar_drag_rect (0)
396 , transport_bar_drag_rect (0)
397 , transport_bar_range_rect (0)
398 , transport_bar_preroll_rect (0)
399 , transport_bar_postroll_rect (0)
400 , transport_loop_range_rect (0)
401 , transport_punch_range_rect (0)
402 , transport_punchin_line (0)
403 , transport_punchout_line (0)
404 , transport_preroll_rect (0)
405 , transport_postroll_rect (0)
407 , rubberband_rect (0)
413 , autoscroll_horizontal_allowed (false)
414 , autoscroll_vertical_allowed (false)
416 , autoscroll_widget (0)
417 , show_gain_after_trim (false)
418 , selection_op_cmd_depth (0)
419 , selection_op_history_it (0)
420 , no_save_instant (false)
422 , current_mixer_strip (0)
423 , show_editor_mixer_when_tracks_arrive (false)
424 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
425 , current_stepping_trackview (0)
426 , last_track_height_step_timestamp (0)
428 , entered_regionview (0)
429 , clear_entered_track (false)
430 , _edit_point (EditAtMouse)
431 , meters_running (false)
433 , _have_idled (false)
434 , resize_idle_id (-1)
435 , _pending_resize_amount (0)
436 , _pending_resize_view (0)
437 , _pending_locate_request (false)
438 , _pending_initial_locate (false)
442 , layering_order_editor (0)
443 , _last_cut_copy_source_track (0)
444 , _region_selection_change_updates_region_list (true)
446 , _following_mixer_selection (false)
447 , _control_point_toggled_on_press (false)
448 , _stepping_axis_view (0)
449 , quantize_dialog (0)
450 , _main_menu_disabler (0)
451 , myactions (X_("editor"))
453 /* we are a singleton */
455 PublicEditor::_instance = this;
459 last_event_time.tv_sec = 0;
460 last_event_time.tv_usec = 0;
462 selection_op_history.clear();
465 grid_type_strings = I18N (_grid_type_strings);
466 zoom_focus_strings = I18N (_zoom_focus_strings);
467 edit_mode_strings = I18N (_edit_mode_strings);
468 edit_point_strings = I18N (_edit_point_strings);
469 #ifdef USE_RUBBERBAND
470 rb_opt_strings = I18N (_rb_opt_strings);
474 build_edit_mode_menu();
475 build_zoom_focus_menu();
476 build_track_count_menu();
477 build_grid_type_menu();
478 build_edit_point_menu();
480 location_marker_color = UIConfiguration::instance().color ("location marker");
481 location_range_color = UIConfiguration::instance().color ("location range");
482 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
483 location_loop_color = UIConfiguration::instance().color ("location loop");
484 location_punch_color = UIConfiguration::instance().color ("location punch");
486 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
488 TimeAxisView::setup_sizes ();
489 ArdourMarker::setup_sizes (timebar_height);
490 TempoCurve::setup_sizes (timebar_height);
492 bbt_label.set_name ("EditorRulerLabel");
493 bbt_label.set_size_request (-1, (int)timebar_height);
494 bbt_label.set_alignment (1.0, 0.5);
495 bbt_label.set_padding (5,0);
497 bbt_label.set_no_show_all();
498 minsec_label.set_name ("EditorRulerLabel");
499 minsec_label.set_size_request (-1, (int)timebar_height);
500 minsec_label.set_alignment (1.0, 0.5);
501 minsec_label.set_padding (5,0);
502 minsec_label.hide ();
503 minsec_label.set_no_show_all();
504 timecode_label.set_name ("EditorRulerLabel");
505 timecode_label.set_size_request (-1, (int)timebar_height);
506 timecode_label.set_alignment (1.0, 0.5);
507 timecode_label.set_padding (5,0);
508 timecode_label.hide ();
509 timecode_label.set_no_show_all();
510 samples_label.set_name ("EditorRulerLabel");
511 samples_label.set_size_request (-1, (int)timebar_height);
512 samples_label.set_alignment (1.0, 0.5);
513 samples_label.set_padding (5,0);
514 samples_label.hide ();
515 samples_label.set_no_show_all();
517 tempo_label.set_name ("EditorRulerLabel");
518 tempo_label.set_size_request (-1, (int)timebar_height);
519 tempo_label.set_alignment (1.0, 0.5);
520 tempo_label.set_padding (5,0);
522 tempo_label.set_no_show_all();
524 meter_label.set_name ("EditorRulerLabel");
525 meter_label.set_size_request (-1, (int)timebar_height);
526 meter_label.set_alignment (1.0, 0.5);
527 meter_label.set_padding (5,0);
529 meter_label.set_no_show_all();
531 if (Profile->get_trx()) {
532 mark_label.set_text (_("Markers"));
534 mark_label.set_name ("EditorRulerLabel");
535 mark_label.set_size_request (-1, (int)timebar_height);
536 mark_label.set_alignment (1.0, 0.5);
537 mark_label.set_padding (5,0);
539 mark_label.set_no_show_all();
541 cd_mark_label.set_name ("EditorRulerLabel");
542 cd_mark_label.set_size_request (-1, (int)timebar_height);
543 cd_mark_label.set_alignment (1.0, 0.5);
544 cd_mark_label.set_padding (5,0);
545 cd_mark_label.hide();
546 cd_mark_label.set_no_show_all();
548 videotl_bar_height = 4;
549 videotl_label.set_name ("EditorRulerLabel");
550 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
551 videotl_label.set_alignment (1.0, 0.5);
552 videotl_label.set_padding (5,0);
553 videotl_label.hide();
554 videotl_label.set_no_show_all();
556 range_mark_label.set_name ("EditorRulerLabel");
557 range_mark_label.set_size_request (-1, (int)timebar_height);
558 range_mark_label.set_alignment (1.0, 0.5);
559 range_mark_label.set_padding (5,0);
560 range_mark_label.hide();
561 range_mark_label.set_no_show_all();
563 transport_mark_label.set_name ("EditorRulerLabel");
564 transport_mark_label.set_size_request (-1, (int)timebar_height);
565 transport_mark_label.set_alignment (1.0, 0.5);
566 transport_mark_label.set_padding (5,0);
567 transport_mark_label.hide();
568 transport_mark_label.set_no_show_all();
570 initialize_canvas ();
572 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
574 _summary = new EditorSummary (this);
576 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
577 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
579 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
581 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
582 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
584 edit_controls_vbox.set_spacing (0);
585 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
586 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
588 HBox* h = manage (new HBox);
589 _group_tabs = new EditorGroupTabs (this);
590 if (!ARDOUR::Profile->get_trx()) {
591 h->pack_start (*_group_tabs, PACK_SHRINK);
593 h->pack_start (edit_controls_vbox);
594 controls_layout.add (*h);
596 controls_layout.set_name ("EditControlsBase");
597 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
598 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
599 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
601 _cursors = new MouseCursors;
602 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
603 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
605 /* Push default cursor to ever-present bottom of cursor stack. */
606 push_canvas_cursor(_cursors->grabber);
608 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
610 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
611 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
612 pad_line_1->set_outline_color (0xFF0000FF);
618 edit_packer.set_col_spacings (0);
619 edit_packer.set_row_spacings (0);
620 edit_packer.set_homogeneous (false);
621 edit_packer.set_border_width (0);
622 edit_packer.set_name ("EditorWindow");
624 time_bars_event_box.add (time_bars_vbox);
625 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
626 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
628 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
629 axis_view_shadow->set_size_request (4, -1);
630 axis_view_shadow->set_name("EditorWindow");
631 axis_view_shadow->show();
633 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
635 /* labels for the time bars */
636 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
638 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
640 edit_packer.attach (*_track_canvas_viewport, 2, 3, 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_arrow_left = manage (new Button);
687 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
688 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
689 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 Button* summary_arrow_right = manage (new Button);
692 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
693 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
694 summary_arrow_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_arrow_left);
699 VBox* summary_arrows_right = manage (new VBox);
700 summary_arrows_right->pack_start (*summary_arrow_right);
702 Frame* summary_frame = manage (new Frame);
703 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
705 summary_frame->add (*_summary);
706 summary_frame->show ();
708 _summary_hbox.pack_start (*summary_arrows_left, false, false);
709 _summary_hbox.pack_start (*summary_frame, true, true);
710 _summary_hbox.pack_start (*summary_arrows_right, false, false);
712 if (!ARDOUR::Profile->get_trx()) {
713 editor_summary_pane.add (_summary_hbox);
716 edit_pane.set_check_divider_position (true);
717 edit_pane.add (editor_summary_pane);
718 if (!ARDOUR::Profile->get_trx()) {
719 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
720 _editor_list_vbox.pack_start (_the_notebook);
721 edit_pane.add (_editor_list_vbox);
722 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
725 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
726 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
729 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
730 /* initial allocation is 90% to canvas, 10% to notebook */
733 edit_pane.set_divider (0, fract);
735 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
736 /* initial allocation is 90% to canvas, 10% to summary */
739 editor_summary_pane.set_divider (0, fract);
741 global_vpacker.set_spacing (0);
742 global_vpacker.set_border_width (0);
744 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
746 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
747 ebox->set_name("EditorWindow");
748 ebox->add (ebox_hpacker);
750 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
751 epane_box->set_name("EditorWindow");
752 epane_box->add (edit_pane);
754 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
755 epane_box2->set_name("EditorWindow");
756 epane_box2->add (global_vpacker);
758 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
759 toolbar_shadow->set_size_request (-1, 4);
760 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
761 toolbar_shadow->set_name("EditorWindow");
762 toolbar_shadow->show();
764 global_vpacker.pack_start (*toolbar_shadow, false, false);
765 global_vpacker.pack_start (*ebox, false, false);
766 global_vpacker.pack_start (*epane_box, true, true);
767 global_hpacker.pack_start (*epane_box2, true, true);
769 /* need to show the "contents" widget so that notebook will show if tab is switched to
772 global_hpacker.show ();
776 /* register actions now so that set_state() can find them and set toggles/checks etc */
783 _playlist_selector = new PlaylistSelector();
784 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
786 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
790 nudge_forward_button.set_name ("nudge button");
791 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
793 nudge_backward_button.set_name ("nudge button");
794 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
796 fade_context_menu.set_name ("ArdourContextMenu");
798 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
800 /* allow external control surfaces/protocols to do various things */
802 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
803 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
804 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
805 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
806 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
807 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
808 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
809 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
810 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
811 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
812 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
813 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
814 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
815 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
817 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
818 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
819 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
820 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
821 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
823 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
827 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
829 /* problematic: has to return a value and thus cannot be x-thread */
831 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
833 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
834 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
836 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
838 _ignore_region_action = false;
839 _last_region_menu_was_main = false;
840 _popup_region_menu_item = 0;
842 _show_marker_lines = false;
844 /* Button bindings */
846 button_bindings = new Bindings ("editor-mouse");
848 XMLNode* node = button_settings();
850 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
851 button_bindings->load_operation (**i);
857 /* grab current parameter state */
858 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
859 UIConfiguration::instance().map_parameters (pc);
861 setup_fade_images ();
863 set_grid_to (GridTypeNone);
870 delete button_bindings;
872 delete _route_groups;
873 delete _track_canvas_viewport;
876 delete _verbose_cursor;
877 delete quantize_dialog;
883 delete _playlist_selector;
884 delete _time_info_box;
889 LuaInstance::destroy_instance ();
891 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
894 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
897 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
903 Editor::button_settings () const
905 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
906 XMLNode* node = find_named_node (*settings, X_("Buttons"));
909 node = new XMLNode (X_("Buttons"));
916 Editor::get_smart_mode () const
918 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
922 Editor::catch_vanishing_regionview (RegionView *rv)
924 /* note: the selection will take care of the vanishing
925 audioregionview by itself.
928 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
932 if (clicked_regionview == rv) {
933 clicked_regionview = 0;
936 if (entered_regionview == rv) {
937 set_entered_regionview (0);
940 if (!_all_region_actions_sensitized) {
941 sensitize_all_region_actions (true);
946 Editor::set_entered_regionview (RegionView* rv)
948 if (rv == entered_regionview) {
952 if (entered_regionview) {
953 entered_regionview->exited ();
956 entered_regionview = rv;
958 if (entered_regionview != 0) {
959 entered_regionview->entered ();
962 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
963 /* This RegionView entry might have changed what region actions
964 are allowed, so sensitize them all in case a key is pressed.
966 sensitize_all_region_actions (true);
971 Editor::set_entered_track (TimeAxisView* tav)
974 entered_track->exited ();
980 entered_track->entered ();
985 Editor::instant_save ()
987 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
992 _session->add_instant_xml(get_state());
994 Config->add_instant_xml(get_state());
999 Editor::control_vertical_zoom_in_all ()
1001 tav_zoom_smooth (false, true);
1005 Editor::control_vertical_zoom_out_all ()
1007 tav_zoom_smooth (true, true);
1011 Editor::control_vertical_zoom_in_selected ()
1013 tav_zoom_smooth (false, false);
1017 Editor::control_vertical_zoom_out_selected ()
1019 tav_zoom_smooth (true, false);
1023 Editor::control_view (uint32_t view)
1025 goto_visual_state (view);
1029 Editor::control_unselect ()
1031 selection->clear_tracks ();
1035 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1037 TimeAxisView* tav = time_axis_view_from_stripable (s);
1041 case Selection::Add:
1042 selection->add (tav);
1044 case Selection::Toggle:
1045 selection->toggle (tav);
1047 case Selection::Extend:
1049 case Selection::Set:
1050 selection->set (tav);
1054 selection->clear_tracks ();
1059 Editor::control_step_tracks_up ()
1061 scroll_tracks_up_line ();
1065 Editor::control_step_tracks_down ()
1067 scroll_tracks_down_line ();
1071 Editor::control_scroll (float fraction)
1073 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1079 double step = fraction * current_page_samples();
1082 _control_scroll_target is an optional<T>
1084 it acts like a pointer to an samplepos_t, with
1085 a operator conversion to boolean to check
1086 that it has a value could possibly use
1087 playhead_cursor->current_sample to store the
1088 value and a boolean in the class to know
1089 when it's out of date
1092 if (!_control_scroll_target) {
1093 _control_scroll_target = _session->transport_sample();
1094 _dragging_playhead = true;
1097 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1098 *_control_scroll_target = 0;
1099 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1100 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1102 *_control_scroll_target += (samplepos_t) trunc (step);
1105 /* move visuals, we'll catch up with it later */
1107 playhead_cursor->set_position (*_control_scroll_target);
1108 UpdateAllTransportClocks (*_control_scroll_target);
1110 if (*_control_scroll_target > (current_page_samples() / 2)) {
1111 /* try to center PH in window */
1112 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1118 Now we do a timeout to actually bring the session to the right place
1119 according to the playhead. This is to avoid reading disk buffers on every
1120 call to control_scroll, which is driven by ScrollTimeline and therefore
1121 probably by a control surface wheel which can generate lots of events.
1123 /* cancel the existing timeout */
1125 control_scroll_connection.disconnect ();
1127 /* add the next timeout */
1129 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1133 Editor::deferred_control_scroll (samplepos_t /*target*/)
1135 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1136 /* reset for next stream */
1137 _control_scroll_target = boost::none;
1138 _dragging_playhead = false;
1143 Editor::access_action (const std::string& action_group, const std::string& action_item)
1149 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1152 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
1160 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1162 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1166 Editor::on_realize ()
1170 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1171 start_lock_event_timing ();
1176 Editor::start_lock_event_timing ()
1178 /* check if we should lock the GUI every 30 seconds */
1180 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1184 Editor::generic_event_handler (GdkEvent* ev)
1187 case GDK_BUTTON_PRESS:
1188 case GDK_BUTTON_RELEASE:
1189 case GDK_MOTION_NOTIFY:
1191 case GDK_KEY_RELEASE:
1192 if (contents().is_mapped()) {
1193 gettimeofday (&last_event_time, 0);
1197 case GDK_LEAVE_NOTIFY:
1198 switch (ev->crossing.detail) {
1199 case GDK_NOTIFY_UNKNOWN:
1200 case GDK_NOTIFY_INFERIOR:
1201 case GDK_NOTIFY_ANCESTOR:
1203 case GDK_NOTIFY_VIRTUAL:
1204 case GDK_NOTIFY_NONLINEAR:
1205 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1206 /* leaving window, so reset focus, thus ending any and
1207 all text entry operations.
1209 ARDOUR_UI::instance()->reset_focus (&contents());
1222 Editor::lock_timeout_callback ()
1224 struct timeval now, delta;
1226 gettimeofday (&now, 0);
1228 timersub (&now, &last_event_time, &delta);
1230 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1232 /* don't call again. Returning false will effectively
1233 disconnect us from the timer callback.
1235 unlock() will call start_lock_event_timing() to get things
1245 Editor::map_position_change (samplepos_t sample)
1247 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1249 if (_session == 0) {
1253 if (_follow_playhead) {
1254 center_screen (sample);
1257 playhead_cursor->set_position (sample);
1261 Editor::center_screen (samplepos_t sample)
1263 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1265 /* if we're off the page, then scroll.
1268 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1269 center_screen_internal (sample, page);
1274 Editor::center_screen_internal (samplepos_t sample, float page)
1278 if (sample > page) {
1279 sample -= (samplepos_t) page;
1284 reset_x_origin (sample);
1289 Editor::update_title ()
1291 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1293 if (!own_window()) {
1298 bool dirty = _session->dirty();
1300 string session_name;
1302 if (_session->snap_name() != _session->name()) {
1303 session_name = _session->snap_name();
1305 session_name = _session->name();
1309 session_name = "*" + session_name;
1312 WindowTitle title(session_name);
1313 title += S_("Window|Editor");
1314 title += Glib::get_application_name();
1315 own_window()->set_title (title.get_string());
1317 /* ::session_going_away() will have taken care of it */
1322 Editor::set_session (Session *t)
1324 SessionHandlePtr::set_session (t);
1330 /* initialize _leftmost_sample to the extents of the session
1331 * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
1332 * before the visible state has been loaded from instant.xml */
1333 _leftmost_sample = session_gui_extents().first;
1335 _playlist_selector->set_session (_session);
1336 nudge_clock->set_session (_session);
1337 _summary->set_session (_session);
1338 _group_tabs->set_session (_session);
1339 _route_groups->set_session (_session);
1340 _regions->set_session (_session);
1341 _snapshots->set_session (_session);
1342 _routes->set_session (_session);
1343 _locations->set_session (_session);
1344 _time_info_box->set_session (_session);
1346 if (rhythm_ferret) {
1347 rhythm_ferret->set_session (_session);
1350 if (analysis_window) {
1351 analysis_window->set_session (_session);
1355 sfbrowser->set_session (_session);
1358 compute_fixed_ruler_scale ();
1360 /* Make sure we have auto loop and auto punch ranges */
1362 Location* loc = _session->locations()->auto_loop_location();
1364 loc->set_name (_("Loop"));
1367 loc = _session->locations()->auto_punch_location();
1370 loc->set_name (_("Punch"));
1373 refresh_location_display ();
1375 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1376 * the selected Marker; this needs the LocationMarker list to be available.
1378 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1379 set_state (*node, Stateful::loading_state_version);
1381 /* catch up on selection state, etc. */
1384 sc.add (Properties::selected);
1385 presentation_info_changed (sc);
1387 /* catch up with the playhead */
1389 _session->request_locate (playhead_cursor->current_sample ());
1390 _pending_initial_locate = true;
1394 /* These signals can all be emitted by a non-GUI thread. Therefore the
1395 handlers for them must not attempt to directly interact with the GUI,
1396 but use PBD::Signal<T>::connect() which accepts an event loop
1397 ("context") where the handler will be asked to run.
1400 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1401 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1402 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1403 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1404 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1405 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1406 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1407 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1408 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1409 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1410 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1411 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1412 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1413 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1414 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1415 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1417 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1418 playhead_cursor->show ();
1420 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1421 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1422 snapped_cursor->show ();
1424 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1425 Config->map_parameters (pc);
1426 _session->config.map_parameters (pc);
1428 restore_ruler_visibility ();
1429 //tempo_map_changed (PropertyChange (0));
1430 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1432 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1433 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1436 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1437 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1440 /* register for undo history */
1441 _session->register_with_memento_command_factory(id(), this);
1442 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1444 LuaInstance::instance()->set_session(_session);
1446 start_updating_meters ();
1450 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1452 using namespace Menu_Helpers;
1454 void (Editor::*emf)(FadeShape);
1455 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1458 images = &_xfade_in_images;
1459 emf = &Editor::set_fade_in_shape;
1461 images = &_xfade_out_images;
1462 emf = &Editor::set_fade_out_shape;
1467 _("Linear (for highly correlated material)"),
1468 *(*images)[FadeLinear],
1469 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 _("Constant power"),
1478 *(*images)[FadeConstantPower],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *(*images)[FadeSymmetric],
1488 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *(*images)[FadeSlow],
1498 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1501 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1506 *(*images)[FadeFast],
1507 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1510 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 /** Pop up a context menu for when the user clicks on a start crossfade */
1515 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1517 using namespace Menu_Helpers;
1518 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1523 MenuList& items (xfade_in_context_menu.items());
1526 if (arv->audio_region()->fade_in_active()) {
1527 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1529 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1532 items.push_back (SeparatorElem());
1533 fill_xfade_menu (items, true);
1535 xfade_in_context_menu.popup (button, time);
1538 /** Pop up a context menu for when the user clicks on an end crossfade */
1540 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1542 using namespace Menu_Helpers;
1543 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1548 MenuList& items (xfade_out_context_menu.items());
1551 if (arv->audio_region()->fade_out_active()) {
1552 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1554 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1557 items.push_back (SeparatorElem());
1558 fill_xfade_menu (items, false);
1560 xfade_out_context_menu.popup (button, time);
1564 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1566 using namespace Menu_Helpers;
1567 Menu* (Editor::*build_menu_function)();
1570 switch (item_type) {
1572 case RegionViewName:
1573 case RegionViewNameHighlight:
1574 case LeftFrameHandle:
1575 case RightFrameHandle:
1576 if (with_selection) {
1577 build_menu_function = &Editor::build_track_selection_context_menu;
1579 build_menu_function = &Editor::build_track_region_context_menu;
1584 if (with_selection) {
1585 build_menu_function = &Editor::build_track_selection_context_menu;
1587 build_menu_function = &Editor::build_track_context_menu;
1592 if (clicked_routeview->track()) {
1593 build_menu_function = &Editor::build_track_context_menu;
1595 build_menu_function = &Editor::build_track_bus_context_menu;
1600 /* probably shouldn't happen but if it does, we don't care */
1604 menu = (this->*build_menu_function)();
1605 menu->set_name ("ArdourContextMenu");
1607 /* now handle specific situations */
1609 switch (item_type) {
1611 case RegionViewName:
1612 case RegionViewNameHighlight:
1613 case LeftFrameHandle:
1614 case RightFrameHandle:
1615 if (!with_selection) {
1616 if (region_edit_menu_split_item) {
1617 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1618 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1620 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1623 if (region_edit_menu_split_multichannel_item) {
1624 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1625 region_edit_menu_split_multichannel_item->set_sensitive (true);
1627 region_edit_menu_split_multichannel_item->set_sensitive (false);
1640 /* probably shouldn't happen but if it does, we don't care */
1644 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1646 /* Bounce to disk */
1648 using namespace Menu_Helpers;
1649 MenuList& edit_items = menu->items();
1651 edit_items.push_back (SeparatorElem());
1653 switch (clicked_routeview->audio_track()->freeze_state()) {
1654 case AudioTrack::NoFreeze:
1655 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1658 case AudioTrack::Frozen:
1659 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1662 case AudioTrack::UnFrozen:
1663 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1669 if (item_type == StreamItem && clicked_routeview) {
1670 clicked_routeview->build_underlay_menu(menu);
1673 /* When the region menu is opened, we setup the actions so that they look right
1676 sensitize_the_right_region_actions (false);
1677 _last_region_menu_was_main = false;
1679 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1680 menu->popup (button, time);
1684 Editor::build_track_context_menu ()
1686 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_context_menu.items();
1691 add_dstream_context_items (edit_items);
1692 return &track_context_menu;
1696 Editor::build_track_bus_context_menu ()
1698 using namespace Menu_Helpers;
1700 MenuList& edit_items = track_context_menu.items();
1703 add_bus_context_items (edit_items);
1704 return &track_context_menu;
1708 Editor::build_track_region_context_menu ()
1710 using namespace Menu_Helpers;
1711 MenuList& edit_items = track_region_context_menu.items();
1714 /* we've just cleared the track region context menu, so the menu that these
1715 two items were on will have disappeared; stop them dangling.
1717 region_edit_menu_split_item = 0;
1718 region_edit_menu_split_multichannel_item = 0;
1720 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1723 boost::shared_ptr<Track> tr;
1724 boost::shared_ptr<Playlist> pl;
1726 if ((tr = rtv->track())) {
1727 add_region_context_items (edit_items, tr);
1731 add_dstream_context_items (edit_items);
1733 return &track_region_context_menu;
1737 Editor::loudness_analyze_region_selection ()
1742 Selection& s (PublicEditor::instance ().get_selection ());
1743 RegionSelection ars = s.regions;
1744 ARDOUR::AnalysisGraph ag (_session);
1745 samplecnt_t total_work = 0;
1747 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1748 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1752 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1755 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1756 total_work += arv->region ()->length ();
1759 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1761 ag.set_total_samples (total_work);
1762 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1765 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1766 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1770 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1774 ag.analyze_region (ar);
1777 if (!ag.canceled ()) {
1778 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1784 Editor::loudness_analyze_range_selection ()
1789 Selection& s (PublicEditor::instance ().get_selection ());
1790 TimeSelection ts = s.time;
1791 ARDOUR::AnalysisGraph ag (_session);
1792 samplecnt_t total_work = 0;
1794 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1795 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1799 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1803 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1804 total_work += j->length ();
1808 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1810 ag.set_total_samples (total_work);
1811 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1814 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1815 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1819 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1823 ag.analyze_range (rui->route (), pl, ts);
1826 if (!ag.canceled ()) {
1827 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1833 Editor::spectral_analyze_region_selection ()
1835 if (analysis_window == 0) {
1836 analysis_window = new AnalysisWindow();
1839 analysis_window->set_session(_session);
1841 analysis_window->show_all();
1844 analysis_window->set_regionmode();
1845 analysis_window->analyze();
1847 analysis_window->present();
1851 Editor::spectral_analyze_range_selection()
1853 if (analysis_window == 0) {
1854 analysis_window = new AnalysisWindow();
1857 analysis_window->set_session(_session);
1859 analysis_window->show_all();
1862 analysis_window->set_rangemode();
1863 analysis_window->analyze();
1865 analysis_window->present();
1869 Editor::build_track_selection_context_menu ()
1871 using namespace Menu_Helpers;
1872 MenuList& edit_items = track_selection_context_menu.items();
1873 edit_items.clear ();
1875 add_selection_context_items (edit_items);
1876 // edit_items.push_back (SeparatorElem());
1877 // add_dstream_context_items (edit_items);
1879 return &track_selection_context_menu;
1883 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1885 using namespace Menu_Helpers;
1887 /* OK, stick the region submenu at the top of the list, and then add
1891 RegionSelection rs = get_regions_from_selection_and_entered ();
1893 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1895 if (_popup_region_menu_item == 0) {
1896 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1897 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1898 _popup_region_menu_item->show ();
1900 _popup_region_menu_item->set_label (menu_item_name);
1903 /* No layering allowed in later is higher layering model */
1904 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1905 if (act && Config->get_layer_model() == LaterHigher) {
1906 act->set_sensitive (false);
1908 act->set_sensitive (true);
1911 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1913 edit_items.push_back (*_popup_region_menu_item);
1914 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1915 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1917 edit_items.push_back (SeparatorElem());
1920 /** Add context menu items relevant to selection ranges.
1921 * @param edit_items List to add the items to.
1924 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1926 using namespace Menu_Helpers;
1928 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1929 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1931 edit_items.push_back (SeparatorElem());
1932 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1934 edit_items.push_back (SeparatorElem());
1935 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1936 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1938 edit_items.push_back (SeparatorElem());
1940 edit_items.push_back (
1942 _("Move Range Start to Previous Region Boundary"),
1943 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1947 edit_items.push_back (
1949 _("Move Range Start to Next Region Boundary"),
1950 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1954 edit_items.push_back (
1956 _("Move Range End to Previous Region Boundary"),
1957 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1961 edit_items.push_back (
1963 _("Move Range End to Next Region Boundary"),
1964 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1970 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1972 edit_items.push_back (SeparatorElem());
1973 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1977 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1978 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1983 edit_items.push_back (SeparatorElem());
1984 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1985 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1987 edit_items.push_back (SeparatorElem());
1988 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1989 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1990 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1991 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1992 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1993 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1994 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2000 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2002 using namespace Menu_Helpers;
2006 Menu *play_menu = manage (new Menu);
2007 MenuList& play_items = play_menu->items();
2008 play_menu->set_name ("ArdourContextMenu");
2010 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2011 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2012 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2013 play_items.push_back (SeparatorElem());
2014 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2016 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2020 Menu *select_menu = manage (new Menu);
2021 MenuList& select_items = select_menu->items();
2022 select_menu->set_name ("ArdourContextMenu");
2024 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2025 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2026 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2027 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2028 select_items.push_back (SeparatorElem());
2029 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2030 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2031 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2032 select_items.push_back (SeparatorElem());
2033 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2034 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2035 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2036 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2037 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2038 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2039 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2041 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2045 Menu *cutnpaste_menu = manage (new Menu);
2046 MenuList& cutnpaste_items = cutnpaste_menu->items();
2047 cutnpaste_menu->set_name ("ArdourContextMenu");
2049 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2050 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2051 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2053 cutnpaste_items.push_back (SeparatorElem());
2055 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2056 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2058 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2060 /* Adding new material */
2062 edit_items.push_back (SeparatorElem());
2063 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2064 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2068 Menu *nudge_menu = manage (new Menu());
2069 MenuList& nudge_items = nudge_menu->items();
2070 nudge_menu->set_name ("ArdourContextMenu");
2072 edit_items.push_back (SeparatorElem());
2073 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2075 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2076 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2078 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2082 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2084 using namespace Menu_Helpers;
2088 Menu *play_menu = manage (new Menu);
2089 MenuList& play_items = play_menu->items();
2090 play_menu->set_name ("ArdourContextMenu");
2092 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2093 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2094 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2098 Menu *select_menu = manage (new Menu);
2099 MenuList& select_items = select_menu->items();
2100 select_menu->set_name ("ArdourContextMenu");
2102 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2103 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2104 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2105 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2106 select_items.push_back (SeparatorElem());
2107 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2108 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2109 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2110 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2112 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2116 Menu *cutnpaste_menu = manage (new Menu);
2117 MenuList& cutnpaste_items = cutnpaste_menu->items();
2118 cutnpaste_menu->set_name ("ArdourContextMenu");
2120 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2121 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2122 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2124 Menu *nudge_menu = manage (new Menu());
2125 MenuList& nudge_items = nudge_menu->items();
2126 nudge_menu->set_name ("ArdourContextMenu");
2128 edit_items.push_back (SeparatorElem());
2129 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2130 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2131 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2132 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2134 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2138 Editor::grid_type() const
2144 Editor::grid_musical() const
2146 switch (_grid_type) {
2147 case GridTypeBeatDiv32:
2148 case GridTypeBeatDiv28:
2149 case GridTypeBeatDiv24:
2150 case GridTypeBeatDiv20:
2151 case GridTypeBeatDiv16:
2152 case GridTypeBeatDiv14:
2153 case GridTypeBeatDiv12:
2154 case GridTypeBeatDiv10:
2155 case GridTypeBeatDiv8:
2156 case GridTypeBeatDiv7:
2157 case GridTypeBeatDiv6:
2158 case GridTypeBeatDiv5:
2159 case GridTypeBeatDiv4:
2160 case GridTypeBeatDiv3:
2161 case GridTypeBeatDiv2:
2166 case GridTypeTimecode:
2167 case GridTypeMinSec:
2168 case GridTypeCDFrame:
2175 Editor::grid_nonmusical() const
2177 switch (_grid_type) {
2178 case GridTypeTimecode:
2179 case GridTypeMinSec:
2180 case GridTypeCDFrame:
2182 case GridTypeBeatDiv32:
2183 case GridTypeBeatDiv28:
2184 case GridTypeBeatDiv24:
2185 case GridTypeBeatDiv20:
2186 case GridTypeBeatDiv16:
2187 case GridTypeBeatDiv14:
2188 case GridTypeBeatDiv12:
2189 case GridTypeBeatDiv10:
2190 case GridTypeBeatDiv8:
2191 case GridTypeBeatDiv7:
2192 case GridTypeBeatDiv6:
2193 case GridTypeBeatDiv5:
2194 case GridTypeBeatDiv4:
2195 case GridTypeBeatDiv3:
2196 case GridTypeBeatDiv2:
2205 Editor::snap_mode() const
2211 Editor::show_rulers_for_grid ()
2213 /* show appropriate rulers for this grid setting. */
2214 if (grid_musical()) {
2215 ruler_tempo_action->set_active(true);
2216 ruler_meter_action->set_active(true);
2217 ruler_bbt_action->set_active(true);
2219 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2220 ruler_timecode_action->set_active(false);
2221 ruler_minsec_action->set_active(false);
2222 ruler_samples_action->set_active(false);
2224 } else if (_grid_type == GridTypeTimecode) {
2225 ruler_timecode_action->set_active(true);
2227 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2228 ruler_tempo_action->set_active(false);
2229 ruler_meter_action->set_active(false);
2230 ruler_bbt_action->set_active(false);
2231 ruler_minsec_action->set_active(false);
2232 ruler_samples_action->set_active(false);
2234 } else if (_grid_type == GridTypeMinSec) {
2235 ruler_minsec_action->set_active(true);
2237 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2238 ruler_tempo_action->set_active(false);
2239 ruler_meter_action->set_active(false);
2240 ruler_bbt_action->set_active(false);
2241 ruler_timecode_action->set_active(false);
2242 ruler_samples_action->set_active(false);
2244 } else if (_grid_type == GridTypeCDFrame) {
2245 ruler_cd_marker_action->set_active(true);
2246 ruler_minsec_action->set_active(true);
2248 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2249 ruler_tempo_action->set_active(false);
2250 ruler_meter_action->set_active(false);
2251 ruler_bbt_action->set_active(false);
2252 ruler_timecode_action->set_active(false);
2253 ruler_samples_action->set_active(false);
2259 Editor::set_grid_to (GridType gt)
2261 if (_grid_type == gt) { // already set
2265 unsigned int grid_ind = (unsigned int)gt;
2267 if (internal_editing() && UIConfiguration::instance().get_grid_follows_internal()) {
2268 internal_grid_type = gt;
2270 pre_internal_grid_type = gt;
2275 if (grid_ind > grid_type_strings.size() - 1) {
2277 _grid_type = (GridType)grid_ind;
2280 string str = grid_type_strings[grid_ind];
2282 if (str != grid_type_selector.get_text()) {
2283 grid_type_selector.set_text (str);
2286 show_rulers_for_grid ();
2290 if (grid_musical()) {
2291 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2292 update_tempo_based_rulers ();
2295 mark_region_boundary_cache_dirty ();
2297 redisplay_grid (false);
2299 SnapChanged (); /* EMIT SIGNAL */
2303 Editor::set_snap_mode (SnapMode mode)
2305 if (internal_editing()) {
2306 internal_snap_mode = mode;
2308 pre_internal_snap_mode = mode;
2313 if (_snap_mode == SnapOff) {
2314 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2316 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2323 Editor::set_edit_point_preference (EditPoint ep, bool force)
2325 bool changed = (_edit_point != ep);
2328 if (Profile->get_mixbus())
2329 if (ep == EditAtSelectedMarker)
2330 ep = EditAtPlayhead;
2332 string str = edit_point_strings[(int)ep];
2333 if (str != edit_point_selector.get_text ()) {
2334 edit_point_selector.set_text (str);
2337 update_all_enter_cursors();
2339 if (!force && !changed) {
2343 const char* action=NULL;
2345 switch (_edit_point) {
2346 case EditAtPlayhead:
2347 action = "edit-at-playhead";
2349 case EditAtSelectedMarker:
2350 action = "edit-at-marker";
2353 action = "edit-at-mouse";
2357 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2359 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2363 bool in_track_canvas;
2365 if (!mouse_sample (foo, in_track_canvas)) {
2366 in_track_canvas = false;
2369 reset_canvas_action_sensitivity (in_track_canvas);
2370 sensitize_the_right_region_actions (false);
2376 Editor::set_state (const XMLNode& node, int version)
2379 PBD::Unwinder<bool> nsi (no_save_instant, true);
2382 Tabbable::set_state (node, version);
2385 if (_session && node.get_property ("playhead", ph_pos)) {
2387 playhead_cursor->set_position (ph_pos);
2389 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2390 playhead_cursor->set_position (0);
2393 playhead_cursor->set_position (0);
2396 node.get_property ("mixer-width", editor_mixer_strip_width);
2398 node.get_property ("zoom-focus", zoom_focus);
2399 zoom_focus_selection_done (zoom_focus);
2402 if (node.get_property ("zoom", z)) {
2403 /* older versions of ardour used floating point samples_per_pixel */
2404 reset_zoom (llrintf (z));
2406 reset_zoom (samples_per_pixel);
2410 if (node.get_property ("visible-track-count", cnt)) {
2411 set_visible_track_count (cnt);
2415 if (!node.get_property ("grid-type", grid_type)) {
2416 grid_type = _grid_type;
2418 set_grid_to (grid_type);
2421 if (node.get_property ("snap-mode", sm)) {
2422 snap_mode_selection_done(sm);
2423 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2424 * snap_mode_selection_done() will only mark an already active item as active
2425 * which does not trigger set_text().
2429 set_snap_mode (_snap_mode);
2432 node.get_property ("internal-grid-type", internal_grid_type);
2433 node.get_property ("internal-snap-mode", internal_snap_mode);
2434 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2435 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2438 if (node.get_property ("mouse-mode", mm_str)) {
2439 MouseMode m = str2mousemode(mm_str);
2440 set_mouse_mode (m, true);
2442 set_mouse_mode (MouseObject, true);
2446 if (node.get_property ("left-frame", lf_pos)) {
2450 reset_x_origin (lf_pos);
2454 if (node.get_property ("y-origin", y_origin)) {
2455 reset_y_origin (y_origin);
2458 if (node.get_property ("join-object-range", yn)) {
2459 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2461 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2462 tact->set_active (!yn);
2463 tact->set_active (yn);
2465 set_mouse_mode(mouse_mode, true);
2469 if (node.get_property ("edit-point", ep)) {
2470 set_edit_point_preference (ep, true);
2472 set_edit_point_preference (_edit_point);
2475 if (node.get_property ("follow-playhead", yn)) {
2476 set_follow_playhead (yn);
2479 if (node.get_property ("stationary-playhead", yn)) {
2480 set_stationary_playhead (yn);
2483 RegionListSortType sort_type;
2484 if (node.get_property ("region-list-sort-type", sort_type)) {
2485 _regions->reset_sort_type (sort_type, true);
2488 if (node.get_property ("show-editor-mixer", yn)) {
2490 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2493 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 /* do it twice to force the change */
2497 tact->set_active (!yn);
2498 tact->set_active (yn);
2501 if (node.get_property ("show-editor-list", yn)) {
2503 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2506 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2508 /* do it twice to force the change */
2510 tact->set_active (!yn);
2511 tact->set_active (yn);
2515 if (node.get_property (X_("editor-list-page"), el_page)) {
2516 _the_notebook.set_current_page (el_page);
2519 if (node.get_property (X_("show-marker-lines"), yn)) {
2520 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2522 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2524 tact->set_active (!yn);
2525 tact->set_active (yn);
2528 XMLNodeList children = node.children ();
2529 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2530 selection->set_state (**i, Stateful::current_state_version);
2531 _regions->set_state (**i);
2532 _locations->set_state (**i);
2535 if (node.get_property ("maximised", yn)) {
2536 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2538 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2539 bool fs = tact && tact->get_active();
2541 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2545 samplepos_t nudge_clock_value;
2546 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2547 nudge_clock->set (nudge_clock_value);
2549 nudge_clock->set_mode (AudioClock::Timecode);
2550 nudge_clock->set (_session->sample_rate() * 5, true);
2555 * Not all properties may have been in XML, but
2556 * those that are linked to a private variable may need changing
2560 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2561 yn = _follow_playhead;
2563 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2564 if (tact->get_active() != yn) {
2565 tact->set_active (yn);
2569 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2570 yn = _stationary_playhead;
2572 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2573 if (tact->get_active() != yn) {
2574 tact->set_active (yn);
2579 return LuaInstance::instance()->set_state(node);
2583 Editor::get_state ()
2585 XMLNode* node = new XMLNode (X_("Editor"));
2587 node->set_property ("id", id().to_s ());
2589 node->add_child_nocopy (Tabbable::get_state());
2591 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2592 node->set_property("notebook-shrunk", _notebook_shrunk);
2593 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2595 maybe_add_mixer_strip_width (*node);
2597 node->set_property ("zoom-focus", zoom_focus);
2599 node->set_property ("zoom", samples_per_pixel);
2600 node->set_property ("grid-type", _grid_type);
2601 node->set_property ("snap-mode", _snap_mode);
2602 node->set_property ("internal-grid-type", internal_grid_type);
2603 node->set_property ("internal-snap-mode", internal_snap_mode);
2604 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2605 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2606 node->set_property ("edit-point", _edit_point);
2607 node->set_property ("visible-track-count", _visible_track_count);
2609 node->set_property ("playhead", playhead_cursor->current_sample ());
2610 node->set_property ("left-frame", _leftmost_sample);
2611 node->set_property ("y-origin", vertical_adjustment.get_value ());
2613 node->set_property ("maximised", _maximised);
2614 node->set_property ("follow-playhead", _follow_playhead);
2615 node->set_property ("stationary-playhead", _stationary_playhead);
2616 node->set_property ("region-list-sort-type", _regions->sort_type ());
2617 node->set_property ("mouse-mode", mouse_mode);
2618 node->set_property ("join-object-range", smart_mode_action->get_active ());
2620 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2622 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2623 node->set_property (X_("show-editor-mixer"), tact->get_active());
2626 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2628 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2629 node->set_property (X_("show-editor-list"), tact->get_active());
2632 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2634 if (button_bindings) {
2635 XMLNode* bb = new XMLNode (X_("Buttons"));
2636 button_bindings->save (*bb);
2637 node->add_child_nocopy (*bb);
2640 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2642 node->add_child_nocopy (selection->get_state ());
2643 node->add_child_nocopy (_regions->get_state ());
2645 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2647 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2648 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2649 node->add_child_nocopy (_locations->get_state ());
2654 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2655 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2657 * @return pair: TimeAxisView that y is over, layer index.
2659 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2660 * in stacked or expanded region display mode, otherwise 0.
2662 std::pair<TimeAxisView *, double>
2663 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2665 if (!trackview_relative_offset) {
2666 y -= _trackview_group->canvas_origin().y;
2670 return std::make_pair ((TimeAxisView *) 0, 0);
2673 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2675 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2682 return std::make_pair ((TimeAxisView *) 0, 0);
2686 Editor::set_snapped_cursor_position (samplepos_t pos)
2688 if (_edit_point == EditAtMouse) {
2689 snapped_cursor->set_position(pos);
2694 /** Snap a position to the grid, if appropriate, taking into account current
2695 * grid settings and also the state of any snap modifier keys that may be pressed.
2696 * @param start Position to snap.
2697 * @param event Event to get current key modifier information from, or 0.
2700 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
2702 if (!_session || !event) {
2706 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2707 if (_snap_mode == SnapOff) {
2708 snap_to_internal (start, direction, pref);
2710 start.set (start.sample, 0);
2713 if (_snap_mode != SnapOff) {
2714 snap_to_internal (start, direction, pref);
2715 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2716 /* SnapOff, but we pressed the snap_delta modifier */
2717 snap_to_internal (start, direction, pref);
2719 start.set (start.sample, 0);
2725 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2727 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2728 start.set (start.sample, 0);
2732 snap_to_internal (start, direction, pref, ensure_snap);
2736 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2738 samplepos_t diff = abs (test - presnap);
2744 test = max_samplepos; // reset this so it doesn't get accidentally reused
2748 Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
2750 samplepos_t start = presnap.sample;
2751 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2752 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2754 TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
2757 case timecode_show_bits:
2758 case timecode_show_samples:
2759 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2760 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2761 /* start is already on a whole timecode frame, do nothing */
2762 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2763 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2765 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2769 case timecode_show_seconds:
2770 if (_session->config.get_timecode_offset_negative()) {
2771 start += _session->config.get_timecode_offset ();
2773 start -= _session->config.get_timecode_offset ();
2775 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2776 (start % one_timecode_second == 0)) {
2777 /* start is already on a whole second, do nothing */
2778 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2779 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2781 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2784 if (_session->config.get_timecode_offset_negative()) {
2785 start -= _session->config.get_timecode_offset ();
2787 start += _session->config.get_timecode_offset ();
2791 case timecode_show_minutes:
2792 case timecode_show_hours:
2793 case timecode_show_many_hours:
2794 if (_session->config.get_timecode_offset_negative()) {
2795 start += _session->config.get_timecode_offset ();
2797 start -= _session->config.get_timecode_offset ();
2799 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2800 (start % one_timecode_minute == 0)) {
2801 /* start is already on a whole minute, do nothing */
2802 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2803 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2805 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2807 if (_session->config.get_timecode_offset_negative()) {
2808 start -= _session->config.get_timecode_offset ();
2810 start += _session->config.get_timecode_offset ();
2814 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2817 MusicSample ret(start,0);
2822 Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
2824 MusicSample ret(presnap);
2826 const samplepos_t one_second = _session->sample_rate();
2827 const samplepos_t one_minute = one_second * 60;
2828 const samplepos_t one_hour = one_minute * 60;
2830 MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
2833 case minsec_show_msecs:
2834 case minsec_show_seconds: {
2835 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2836 presnap.sample % one_second == 0) {
2837 /* start is already on a whole second, do nothing */
2838 } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
2839 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
2841 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
2845 case minsec_show_minutes: {
2846 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2847 presnap.sample % one_minute == 0) {
2848 /* start is already on a whole minute, do nothing */
2849 } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2850 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
2852 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
2857 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2858 presnap.sample % one_hour == 0) {
2859 /* start is already on a whole hour, do nothing */
2860 } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
2861 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
2863 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
2872 Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
2874 if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
2875 return snap_to_minsec (presnap, direction, gpref);
2878 const samplepos_t one_second = _session->sample_rate();
2880 MusicSample ret(presnap);
2882 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2883 presnap.sample % (one_second/75) == 0) {
2884 /* start is already on a whole CD sample, do nothing */
2885 } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2886 ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2888 ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2895 Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
2897 MusicSample ret(presnap);
2899 if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
2902 switch (_grid_type) {
2903 case GridTypeBeatDiv3:
2904 case GridTypeBeatDiv6:
2905 case GridTypeBeatDiv12:
2906 case GridTypeBeatDiv24:
2909 case GridTypeBeatDiv5:
2910 case GridTypeBeatDiv10:
2911 case GridTypeBeatDiv20:
2914 case GridTypeBeatDiv7:
2915 case GridTypeBeatDiv14:
2916 case GridTypeBeatDiv28:
2923 BBTRulerScale scale = bbt_ruler_scale;
2930 ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
2932 case bbt_show_quarters:
2933 ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
2935 case bbt_show_eighths:
2936 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
2938 case bbt_show_sixteenths:
2939 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
2941 case bbt_show_thirtyseconds:
2942 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
2946 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
2953 Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
2955 MusicSample ret(presnap);
2957 if (grid_musical()) {
2958 ret = snap_to_bbt (presnap, direction, gpref);
2961 switch (_grid_type) {
2962 case GridTypeTimecode:
2963 ret = snap_to_timecode(presnap, direction, gpref);
2965 case GridTypeMinSec:
2966 ret = snap_to_minsec(presnap, direction, gpref);
2968 case GridTypeCDFrame:
2969 ret = snap_to_cd_frames(presnap, direction, gpref);
2979 Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
2985 _session->locations()->marks_either_side (presnap, before, after);
2987 if (before == max_samplepos && after == max_samplepos) {
2988 /* No marks to snap to, so just don't snap */
2990 } else if (before == max_samplepos) {
2992 } else if (after == max_samplepos) {
2995 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2997 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2999 } else if (direction == 0) {
3000 if ((presnap - before) < (after - presnap)) {
3012 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
3014 const samplepos_t presnap = start.sample;
3016 samplepos_t test = max_samplepos; // for each snap, we'll use this value
3017 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
3018 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
3020 /* check snap-to-marker */
3021 if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
3022 test = snap_to_marker (presnap, direction);
3023 check_best_snap(presnap, test, dist, best);
3026 /* check snap-to-region-{start/end/sync} */
3028 (pref == SnapToAny_Visual) &&
3029 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
3031 if (!region_boundary_cache.empty()) {
3033 vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
3034 vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
3035 if (next != region_boundary_cache.begin ()) {
3040 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
3042 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
3044 else if (direction == 0) {
3045 if ((presnap - *prev) < (*next - presnap)) {
3054 check_best_snap(presnap, test, dist, best);
3058 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
3059 MusicSample pre(presnap, 0);
3060 MusicSample post = snap_to_grid (pre, direction, pref);
3061 check_best_snap(presnap, post.sample, dist, best);
3064 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
3065 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
3066 * ToDo: Perhaps this should only occur if EditPointMouse?
3068 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
3070 start.set (best, 0);
3072 } else if (presnap > best) {
3073 if (presnap > (best+ snap_threshold_s)) {
3076 } else if (presnap < best) {
3077 if (presnap < (best - snap_threshold_s)) {
3082 start.set (best, 0);
3087 Editor::setup_toolbar ()
3089 HBox* mode_box = manage(new HBox);
3090 mode_box->set_border_width (2);
3091 mode_box->set_spacing(2);
3093 HBox* mouse_mode_box = manage (new HBox);
3094 HBox* mouse_mode_hbox = manage (new HBox);
3095 VBox* mouse_mode_vbox = manage (new VBox);
3096 Alignment* mouse_mode_align = manage (new Alignment);
3098 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3099 mouse_mode_size_group->add_widget (smart_mode_button);
3100 mouse_mode_size_group->add_widget (mouse_move_button);
3101 mouse_mode_size_group->add_widget (mouse_cut_button);
3102 mouse_mode_size_group->add_widget (mouse_select_button);
3103 mouse_mode_size_group->add_widget (mouse_timefx_button);
3104 mouse_mode_size_group->add_widget (mouse_audition_button);
3105 mouse_mode_size_group->add_widget (mouse_draw_button);
3106 mouse_mode_size_group->add_widget (mouse_content_button);
3108 if (!Profile->get_mixbus()) {
3109 mouse_mode_size_group->add_widget (zoom_in_button);
3110 mouse_mode_size_group->add_widget (zoom_out_button);
3111 mouse_mode_size_group->add_widget (zoom_out_full_button);
3112 mouse_mode_size_group->add_widget (zoom_focus_selector);
3113 mouse_mode_size_group->add_widget (tav_shrink_button);
3114 mouse_mode_size_group->add_widget (tav_expand_button);
3116 mouse_mode_size_group->add_widget (zoom_preset_selector);
3117 mouse_mode_size_group->add_widget (visible_tracks_selector);
3120 mouse_mode_size_group->add_widget (grid_type_selector);
3121 mouse_mode_size_group->add_widget (snap_mode_button);
3123 mouse_mode_size_group->add_widget (edit_point_selector);
3124 mouse_mode_size_group->add_widget (edit_mode_selector);
3126 mouse_mode_size_group->add_widget (*nudge_clock);
3127 mouse_mode_size_group->add_widget (nudge_forward_button);
3128 mouse_mode_size_group->add_widget (nudge_backward_button);
3130 mouse_mode_hbox->set_spacing (2);
3132 if (!ARDOUR::Profile->get_trx()) {
3133 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3136 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3137 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3139 if (!ARDOUR::Profile->get_mixbus()) {
3140 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3141 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3144 if (!ARDOUR::Profile->get_trx()) {
3145 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3146 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3147 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3150 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3152 mouse_mode_align->add (*mouse_mode_vbox);
3153 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3155 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3157 edit_mode_selector.set_name ("mouse mode button");
3159 if (!ARDOUR::Profile->get_trx()) {
3160 mode_box->pack_start (edit_mode_selector, false, false);
3161 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3162 mode_box->pack_start (edit_point_selector, false, false);
3163 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3166 mode_box->pack_start (*mouse_mode_box, false, false);
3170 _zoom_box.set_spacing (2);
3171 _zoom_box.set_border_width (2);
3175 zoom_preset_selector.set_name ("zoom button");
3176 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3178 zoom_in_button.set_name ("zoom button");
3179 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3180 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3181 zoom_in_button.set_related_action (act);
3183 zoom_out_button.set_name ("zoom button");
3184 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3185 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3186 zoom_out_button.set_related_action (act);
3188 zoom_out_full_button.set_name ("zoom button");
3189 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3190 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3191 zoom_out_full_button.set_related_action (act);
3193 zoom_focus_selector.set_name ("zoom button");
3195 if (ARDOUR::Profile->get_mixbus()) {
3196 _zoom_box.pack_start (zoom_preset_selector, false, false);
3197 } else if (ARDOUR::Profile->get_trx()) {
3198 mode_box->pack_start (zoom_out_button, false, false);
3199 mode_box->pack_start (zoom_in_button, false, false);
3201 _zoom_box.pack_start (zoom_out_button, false, false);
3202 _zoom_box.pack_start (zoom_in_button, false, false);
3203 _zoom_box.pack_start (zoom_out_full_button, false, false);
3204 _zoom_box.pack_start (zoom_focus_selector, false, false);
3207 /* Track zoom buttons */
3208 _track_box.set_spacing (2);
3209 _track_box.set_border_width (2);
3211 visible_tracks_selector.set_name ("zoom button");
3212 if (Profile->get_mixbus()) {
3213 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3215 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3218 tav_expand_button.set_name ("zoom button");
3219 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3220 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3221 tav_expand_button.set_related_action (act);
3223 tav_shrink_button.set_name ("zoom button");
3224 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3225 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3226 tav_shrink_button.set_related_action (act);
3228 if (ARDOUR::Profile->get_mixbus()) {
3229 _track_box.pack_start (visible_tracks_selector);
3230 } else if (ARDOUR::Profile->get_trx()) {
3231 _track_box.pack_start (tav_shrink_button);
3232 _track_box.pack_start (tav_expand_button);
3234 _track_box.pack_start (visible_tracks_selector);
3235 _track_box.pack_start (tav_shrink_button);
3236 _track_box.pack_start (tav_expand_button);
3239 snap_box.set_spacing (2);
3240 snap_box.set_border_width (2);
3242 grid_type_selector.set_name ("mouse mode button");
3244 snap_mode_button.set_name ("mouse mode button");
3246 edit_point_selector.set_name ("mouse mode button");
3248 snap_box.pack_start (snap_mode_button, false, false);
3249 snap_box.pack_start (grid_type_selector, false, false);
3253 HBox *nudge_box = manage (new HBox);
3254 nudge_box->set_spacing (2);
3255 nudge_box->set_border_width (2);
3257 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3258 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3260 nudge_box->pack_start (nudge_backward_button, false, false);
3261 nudge_box->pack_start (nudge_forward_button, false, false);
3262 nudge_box->pack_start (*nudge_clock, false, false);
3265 /* Pack everything in... */
3267 toolbar_hbox.set_spacing (2);
3268 toolbar_hbox.set_border_width (2);
3270 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3271 tool_shadow->set_size_request (4, -1);
3272 tool_shadow->show();
3274 ebox_hpacker.pack_start (*tool_shadow, false, false);
3275 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3277 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3278 spacer->set_name("EditorWindow");
3279 spacer->set_size_request(-1,4);
3282 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3283 ebox_vpacker.pack_start(*spacer, false, false);
3284 ebox_vpacker.show();
3286 toolbar_hbox.pack_start (*mode_box, false, false);
3288 if (!ARDOUR::Profile->get_trx()) {
3290 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3292 toolbar_hbox.pack_start (snap_box, false, false);
3294 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3296 toolbar_hbox.pack_start (*nudge_box, false, false);
3298 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3300 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3302 toolbar_hbox.pack_end (_track_box, false, false);
3306 toolbar_hbox.show_all ();
3310 Editor::build_edit_point_menu ()
3312 using namespace Menu_Helpers;
3314 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3315 if(!Profile->get_mixbus())
3316 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3317 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3319 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3323 Editor::build_edit_mode_menu ()
3325 using namespace Menu_Helpers;
3327 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3328 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3329 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3330 /* Note: Splice was removed */
3332 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3336 Editor::build_grid_type_menu ()
3338 using namespace Menu_Helpers;
3340 /* main grid: bars, quarter-notes, etc */
3341 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3342 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3343 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3344 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3345 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3346 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3347 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3348 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3351 grid_type_selector.AddMenuElem(SeparatorElem());
3352 Gtk::Menu *_triplet_menu = manage (new Menu);
3353 MenuList& triplet_items (_triplet_menu->items());
3355 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3356 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3357 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3358 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3360 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3362 /* quintuplet grid */
3363 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3364 MenuList& quintuplet_items (_quintuplet_menu->items());
3366 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3367 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3368 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3370 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3372 /* septuplet grid */
3373 Gtk::Menu *_septuplet_menu = manage (new Menu);
3374 MenuList& septuplet_items (_septuplet_menu->items());
3376 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3377 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3378 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3380 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3382 grid_type_selector.AddMenuElem(SeparatorElem());
3383 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3384 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3385 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3389 Editor::setup_tooltips ()
3391 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3392 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3393 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3394 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3395 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3396 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3397 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3398 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3399 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3400 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3401 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3402 set_tooltip (zoom_in_button, _("Zoom In"));
3403 set_tooltip (zoom_out_button, _("Zoom Out"));
3404 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3405 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3406 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3407 set_tooltip (tav_expand_button, _("Expand Tracks"));
3408 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3409 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3410 set_tooltip (grid_type_selector, _("Grid Mode"));
3411 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3412 set_tooltip (edit_point_selector, _("Edit Point"));
3413 set_tooltip (edit_mode_selector, _("Edit Mode"));
3414 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3418 Editor::convert_drop_to_paths (
3419 vector<string>& paths,
3420 const RefPtr<Gdk::DragContext>& /*context*/,
3423 const SelectionData& data,
3427 if (_session == 0) {
3431 vector<string> uris = data.get_uris();
3435 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3436 are actually URI lists. So do it by hand.
3439 if (data.get_target() != "text/plain") {
3443 /* Parse the "uri-list" format that Nautilus provides,
3444 where each pathname is delimited by \r\n.
3446 THERE MAY BE NO NULL TERMINATING CHAR!!!
3449 string txt = data.get_text();
3453 p = (char *) malloc (txt.length() + 1);
3454 txt.copy (p, txt.length(), 0);
3455 p[txt.length()] = '\0';
3461 while (g_ascii_isspace (*p))
3465 while (*q && (*q != '\n') && (*q != '\r')) {
3472 while (q > p && g_ascii_isspace (*q))
3477 uris.push_back (string (p, q - p + 1));
3481 p = strchr (p, '\n');
3493 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3494 if ((*i).substr (0,7) == "file://") {
3495 paths.push_back (Glib::filename_from_uri (*i));
3503 Editor::new_tempo_section ()
3508 Editor::map_transport_state ()
3510 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3512 if (_session && _session->transport_stopped()) {
3513 have_pending_keyboard_selection = false;
3516 update_loop_range_view ();
3520 Editor::transport_looped ()
3522 /* reset Playhead position interpolation.
3523 * see Editor::super_rapid_screen_update
3525 _last_update_time = 0;
3531 Editor::begin_selection_op_history ()
3533 selection_op_cmd_depth = 0;
3534 selection_op_history_it = 0;
3536 while(!selection_op_history.empty()) {
3537 delete selection_op_history.front();
3538 selection_op_history.pop_front();
3541 selection_undo_action->set_sensitive (false);
3542 selection_redo_action->set_sensitive (false);
3543 selection_op_history.push_front (&_selection_memento->get_state ());
3547 Editor::begin_reversible_selection_op (string name)
3550 //cerr << name << endl;
3551 /* begin/commit pairs can be nested */
3552 selection_op_cmd_depth++;
3557 Editor::commit_reversible_selection_op ()
3560 if (selection_op_cmd_depth == 1) {
3562 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3563 /* The user has undone some selection ops and then made a new one,
3564 * making anything earlier in the list invalid.
3567 list<XMLNode *>::iterator it = selection_op_history.begin();
3568 list<XMLNode *>::iterator e_it = it;
3569 advance (e_it, selection_op_history_it);
3571 for (; it != e_it; ++it) {
3574 selection_op_history.erase (selection_op_history.begin(), e_it);
3577 selection_op_history.push_front (&_selection_memento->get_state ());
3578 selection_op_history_it = 0;
3580 selection_undo_action->set_sensitive (true);
3581 selection_redo_action->set_sensitive (false);
3584 if (selection_op_cmd_depth > 0) {
3585 selection_op_cmd_depth--;
3591 Editor::undo_selection_op ()
3594 selection_op_history_it++;
3596 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3597 if (n == selection_op_history_it) {
3598 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3599 selection_redo_action->set_sensitive (true);
3603 /* is there an earlier entry? */
3604 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3605 selection_undo_action->set_sensitive (false);
3611 Editor::redo_selection_op ()
3614 if (selection_op_history_it > 0) {
3615 selection_op_history_it--;
3618 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3619 if (n == selection_op_history_it) {
3620 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3621 selection_undo_action->set_sensitive (true);
3626 if (selection_op_history_it == 0) {
3627 selection_redo_action->set_sensitive (false);
3633 Editor::begin_reversible_command (string name)
3636 before.push_back (&_selection_memento->get_state ());
3637 _session->begin_reversible_command (name);
3642 Editor::begin_reversible_command (GQuark q)
3645 before.push_back (&_selection_memento->get_state ());
3646 _session->begin_reversible_command (q);
3651 Editor::abort_reversible_command ()
3654 while(!before.empty()) {
3655 delete before.front();
3658 _session->abort_reversible_command ();
3663 Editor::commit_reversible_command ()
3666 if (before.size() == 1) {
3667 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3668 redo_action->set_sensitive(false);
3669 undo_action->set_sensitive(true);
3670 begin_selection_op_history ();
3673 if (before.empty()) {
3674 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3679 _session->commit_reversible_command ();
3684 Editor::history_changed ()
3688 if (undo_action && _session) {
3689 if (_session->undo_depth() == 0) {
3690 label = S_("Command|Undo");
3692 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3694 undo_action->property_label() = label;
3697 if (redo_action && _session) {
3698 if (_session->redo_depth() == 0) {
3700 redo_action->set_sensitive (false);
3702 label = string_compose(_("Redo (%1)"), _session->next_redo());
3703 redo_action->set_sensitive (true);
3705 redo_action->property_label() = label;
3710 Editor::duplicate_range (bool with_dialog)
3714 RegionSelection rs = get_regions_from_selection_and_entered ();
3716 if (selection->time.length() == 0 && rs.empty()) {
3722 ArdourDialog win (_("Duplicate"));
3723 Label label (_("Number of duplications:"));
3724 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3725 SpinButton spinner (adjustment, 0.0, 1);
3728 win.get_vbox()->set_spacing (12);
3729 win.get_vbox()->pack_start (hbox);
3730 hbox.set_border_width (6);
3731 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3733 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3734 place, visually. so do this by hand.
3737 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3738 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3739 spinner.grab_focus();
3745 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3746 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3747 win.set_default_response (RESPONSE_ACCEPT);
3749 spinner.grab_focus ();
3751 switch (win.run ()) {
3752 case RESPONSE_ACCEPT:
3758 times = adjustment.get_value();
3761 if ((current_mouse_mode() == MouseRange)) {
3762 if (selection->time.length()) {
3763 duplicate_selection (times);
3765 } else if (get_smart_mode()) {
3766 if (selection->time.length()) {
3767 duplicate_selection (times);
3769 duplicate_some_regions (rs, times);
3771 duplicate_some_regions (rs, times);
3776 Editor::set_edit_mode (EditMode m)
3778 Config->set_edit_mode (m);
3782 Editor::cycle_edit_mode ()
3784 switch (Config->get_edit_mode()) {
3786 Config->set_edit_mode (Ripple);
3790 Config->set_edit_mode (Lock);
3793 Config->set_edit_mode (Slide);
3799 Editor::edit_mode_selection_done (EditMode m)
3801 Config->set_edit_mode (m);
3805 Editor::grid_type_selection_done (GridType gridtype)
3807 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3809 ract->set_active ();
3814 Editor::snap_mode_selection_done (SnapMode mode)
3816 RefPtr<RadioAction> ract = snap_mode_action (mode);
3819 ract->set_active (true);
3824 Editor::cycle_edit_point (bool with_marker)
3826 if(Profile->get_mixbus())
3827 with_marker = false;
3829 switch (_edit_point) {
3831 set_edit_point_preference (EditAtPlayhead);
3833 case EditAtPlayhead:
3835 set_edit_point_preference (EditAtSelectedMarker);
3837 set_edit_point_preference (EditAtMouse);
3840 case EditAtSelectedMarker:
3841 set_edit_point_preference (EditAtMouse);
3847 Editor::edit_point_selection_done (EditPoint ep)
3849 set_edit_point_preference (ep);
3853 Editor::build_zoom_focus_menu ()
3855 using namespace Menu_Helpers;
3857 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3858 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3859 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3860 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3861 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3862 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3864 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3868 Editor::zoom_focus_selection_done (ZoomFocus f)
3870 RefPtr<RadioAction> ract = zoom_focus_action (f);
3872 ract->set_active ();
3877 Editor::build_track_count_menu ()
3879 using namespace Menu_Helpers;
3881 if (!Profile->get_mixbus()) {
3882 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3883 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3884 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3885 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3886 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3887 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3888 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3889 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3890 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3891 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3892 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3893 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3894 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3896 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3897 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3898 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3899 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3900 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3901 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3902 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3903 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3904 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3905 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3907 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3908 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3909 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3910 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3911 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3912 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3913 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3914 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3915 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3916 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3917 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3918 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3923 Editor::set_zoom_preset (int64_t ms)
3926 temporal_zoom_session();
3930 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3931 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3935 Editor::set_visible_track_count (int32_t n)
3937 _visible_track_count = n;
3939 /* if the canvas hasn't really been allocated any size yet, just
3940 record the desired number of visible tracks and return. when canvas
3941 allocation happens, we will get called again and then we can do the
3945 if (_visible_canvas_height <= 1) {
3951 DisplaySuspender ds;
3953 if (_visible_track_count > 0) {
3954 h = trackviews_height() / _visible_track_count;
3955 std::ostringstream s;
3956 s << _visible_track_count;
3958 } else if (_visible_track_count == 0) {
3960 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3961 if ((*i)->marked_for_display()) {
3963 TimeAxisView::Children cl ((*i)->get_child_list ());
3964 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3965 if ((*j)->marked_for_display()) {
3972 visible_tracks_selector.set_text (X_("*"));
3975 h = trackviews_height() / n;
3978 /* negative value means that the visible track count has
3979 been overridden by explicit track height changes.
3981 visible_tracks_selector.set_text (X_("*"));
3985 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3986 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3989 if (str != visible_tracks_selector.get_text()) {
3990 visible_tracks_selector.set_text (str);
3995 Editor::override_visible_track_count ()
3997 _visible_track_count = -1;
3998 visible_tracks_selector.set_text (_("*"));
4002 Editor::edit_controls_button_release (GdkEventButton* ev)
4004 if (Keyboard::is_context_menu_event (ev)) {
4005 ARDOUR_UI::instance()->add_route ();
4006 } else if (ev->button == 1) {
4007 selection->clear_tracks ();
4014 Editor::mouse_select_button_release (GdkEventButton* ev)
4016 /* this handles just right-clicks */
4018 if (ev->button != 3) {
4026 Editor::set_zoom_focus (ZoomFocus f)
4028 string str = zoom_focus_strings[(int)f];
4030 if (str != zoom_focus_selector.get_text()) {
4031 zoom_focus_selector.set_text (str);
4034 if (zoom_focus != f) {
4041 Editor::cycle_zoom_focus ()
4043 switch (zoom_focus) {
4045 set_zoom_focus (ZoomFocusRight);
4047 case ZoomFocusRight:
4048 set_zoom_focus (ZoomFocusCenter);
4050 case ZoomFocusCenter:
4051 set_zoom_focus (ZoomFocusPlayhead);
4053 case ZoomFocusPlayhead:
4054 set_zoom_focus (ZoomFocusMouse);
4056 case ZoomFocusMouse:
4057 set_zoom_focus (ZoomFocusEdit);
4060 set_zoom_focus (ZoomFocusLeft);
4066 Editor::update_grid ()
4068 if (grid_musical()) {
4069 std::vector<TempoMap::BBTPoint> grid;
4070 if (bbt_ruler_scale != bbt_show_many) {
4071 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
4073 maybe_draw_grid_lines ();
4074 } else if (grid_nonmusical()) {
4075 maybe_draw_grid_lines ();
4082 Editor::toggle_follow_playhead ()
4084 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
4086 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4087 set_follow_playhead (tact->get_active());
4091 /** @param yn true to follow playhead, otherwise false.
4092 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4095 Editor::set_follow_playhead (bool yn, bool catch_up)
4097 if (_follow_playhead != yn) {
4098 if ((_follow_playhead = yn) == true && catch_up) {
4100 reset_x_origin_to_follow_playhead ();
4107 Editor::toggle_stationary_playhead ()
4109 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
4111 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
4112 set_stationary_playhead (tact->get_active());
4117 Editor::set_stationary_playhead (bool yn)
4119 if (_stationary_playhead != yn) {
4120 if ((_stationary_playhead = yn) == true) {
4121 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
4122 // update_current_screen ();
4129 Editor::playlist_selector () const
4131 return *_playlist_selector;
4135 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4137 if (paste_count == 0) {
4138 /* don't bother calculating an offset that will be zero anyway */
4142 /* calculate basic unsnapped multi-paste offset */
4143 samplecnt_t offset = paste_count * duration;
4145 /* snap offset so pos + offset is aligned to the grid */
4146 MusicSample offset_pos (pos + offset, 0);
4147 snap_to(offset_pos, RoundUpMaybe);
4148 offset = offset_pos.sample - pos;
4154 Editor::get_grid_beat_divisions(samplepos_t position)
4156 switch (_grid_type) {
4157 case GridTypeBeatDiv32: return 32;
4158 case GridTypeBeatDiv28: return 28;
4159 case GridTypeBeatDiv24: return 24;
4160 case GridTypeBeatDiv20: return 20;
4161 case GridTypeBeatDiv16: return 16;
4162 case GridTypeBeatDiv14: return 14;
4163 case GridTypeBeatDiv12: return 12;
4164 case GridTypeBeatDiv10: return 10;
4165 case GridTypeBeatDiv8: return 8;
4166 case GridTypeBeatDiv7: return 7;
4167 case GridTypeBeatDiv6: return 6;
4168 case GridTypeBeatDiv5: return 5;
4169 case GridTypeBeatDiv4: return 4;
4170 case GridTypeBeatDiv3: return 3;
4171 case GridTypeBeatDiv2: return 2;
4173 case GridTypeNone: return 0;
4174 case GridTypeTimecode: return 0;
4175 case GridTypeMinSec: return 0;
4176 case GridTypeCDFrame: return 0;
4182 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4183 if the grid is non-musical, returns 0.
4184 if the grid is snapped to bars, returns -1.
4185 @param event_state the current keyboard modifier mask.
4188 Editor::get_grid_music_divisions (uint32_t event_state)
4190 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4194 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4198 switch (_grid_type) {
4199 case GridTypeBeatDiv32: return 32;
4200 case GridTypeBeatDiv28: return 28;
4201 case GridTypeBeatDiv24: return 24;
4202 case GridTypeBeatDiv20: return 20;
4203 case GridTypeBeatDiv16: return 16;
4204 case GridTypeBeatDiv14: return 14;
4205 case GridTypeBeatDiv12: return 12;
4206 case GridTypeBeatDiv10: return 10;
4207 case GridTypeBeatDiv8: return 8;
4208 case GridTypeBeatDiv7: return 7;
4209 case GridTypeBeatDiv6: return 6;
4210 case GridTypeBeatDiv5: return 5;
4211 case GridTypeBeatDiv4: return 4;
4212 case GridTypeBeatDiv3: return 3;
4213 case GridTypeBeatDiv2: return 2;
4214 case GridTypeBeat: return 1;
4215 case GridTypeBar : return -1;
4217 case GridTypeNone: return 0;
4218 case GridTypeTimecode: return 0;
4219 case GridTypeMinSec: return 0;
4220 case GridTypeCDFrame: return 0;
4226 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4230 const unsigned divisions = get_grid_beat_divisions(position);
4232 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4235 switch (_grid_type) {
4237 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4240 const Meter& m = _session->tempo_map().meter_at_sample (position);
4241 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4249 return Temporal::Beats();
4253 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4257 ret = nudge_clock->current_duration (pos);
4258 next = ret + 1; /* XXXX fix me */
4264 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4266 ArdourDialog dialog (_("Playlist Deletion"));
4267 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4268 "If it is kept, its audio files will not be cleaned.\n"
4269 "If it is deleted, audio files used by it alone will be cleaned."),
4272 dialog.set_position (WIN_POS_CENTER);
4273 dialog.get_vbox()->pack_start (label);
4277 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4278 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4279 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4280 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4281 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4283 /* by default gtk uses the left most button */
4284 keep->grab_focus ();
4286 switch (dialog.run ()) {
4288 /* keep this and all remaining ones */
4293 /* delete this and all others */
4297 case RESPONSE_ACCEPT:
4298 /* delete the playlist */
4302 case RESPONSE_REJECT:
4303 /* keep the playlist */
4315 Editor::audio_region_selection_covers (samplepos_t where)
4317 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4318 if ((*a)->region()->covers (where)) {
4327 Editor::prepare_for_cleanup ()
4329 cut_buffer->clear_regions ();
4330 cut_buffer->clear_playlists ();
4332 selection->clear_regions ();
4333 selection->clear_playlists ();
4335 _regions->suspend_redisplay ();
4339 Editor::finish_cleanup ()
4341 _regions->resume_redisplay ();
4345 Editor::transport_loop_location()
4348 return _session->locations()->auto_loop_location();
4355 Editor::transport_punch_location()
4358 return _session->locations()->auto_punch_location();
4365 Editor::control_layout_scroll (GdkEventScroll* ev)
4367 /* Just forward to the normal canvas scroll method. The coordinate
4368 systems are different but since the canvas is always larger than the
4369 track headers, and aligned with the trackview area, this will work.
4371 In the not too distant future this layout is going away anyway and
4372 headers will be on the canvas.
4374 return canvas_scroll_event (ev, false);
4378 Editor::session_state_saved (string)
4381 _snapshots->redisplay ();
4385 Editor::maximise_editing_space ()
4391 Gtk::Window* toplevel = current_toplevel();
4394 toplevel->fullscreen ();
4400 Editor::restore_editing_space ()
4406 Gtk::Window* toplevel = current_toplevel();
4409 toplevel->unfullscreen();
4415 * Make new playlists for a given track and also any others that belong
4416 * to the same active route group with the `select' property.
4421 Editor::new_playlists (TimeAxisView* v)
4423 begin_reversible_command (_("new playlists"));
4424 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4425 _session->playlists->get (playlists);
4426 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4427 commit_reversible_command ();
4431 * Use a copy of the current playlist for a given track and also any others that belong
4432 * to the same active route group with the `select' property.
4437 Editor::copy_playlists (TimeAxisView* v)
4439 begin_reversible_command (_("copy playlists"));
4440 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4441 _session->playlists->get (playlists);
4442 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4443 commit_reversible_command ();
4446 /** Clear the current playlist for a given track and also any others that belong
4447 * to the same active route group with the `select' property.
4452 Editor::clear_playlists (TimeAxisView* v)
4454 begin_reversible_command (_("clear playlists"));
4455 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4456 _session->playlists->get (playlists);
4457 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4458 commit_reversible_command ();
4462 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4464 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4468 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4470 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4474 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4476 atv.clear_playlist ();
4480 Editor::get_y_origin () const
4482 return vertical_adjustment.get_value ();
4485 /** Queue up a change to the viewport x origin.
4486 * @param sample New x origin.
4489 Editor::reset_x_origin (samplepos_t sample)
4491 pending_visual_change.add (VisualChange::TimeOrigin);
4492 pending_visual_change.time_origin = sample;
4493 ensure_visual_change_idle_handler ();
4497 Editor::reset_y_origin (double y)
4499 pending_visual_change.add (VisualChange::YOrigin);
4500 pending_visual_change.y_origin = y;
4501 ensure_visual_change_idle_handler ();
4505 Editor::reset_zoom (samplecnt_t spp)
4507 if (spp == samples_per_pixel) {
4511 pending_visual_change.add (VisualChange::ZoomLevel);
4512 pending_visual_change.samples_per_pixel = spp;
4513 ensure_visual_change_idle_handler ();
4517 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4519 reset_x_origin (sample);
4522 if (!no_save_visual) {
4523 undo_visual_stack.push_back (current_visual_state(false));
4527 Editor::VisualState::VisualState (bool with_tracks)
4528 : gui_state (with_tracks ? new GUIObjectState : 0)
4532 Editor::VisualState::~VisualState ()
4537 Editor::VisualState*
4538 Editor::current_visual_state (bool with_tracks)
4540 VisualState* vs = new VisualState (with_tracks);
4541 vs->y_position = vertical_adjustment.get_value();
4542 vs->samples_per_pixel = samples_per_pixel;
4543 vs->_leftmost_sample = _leftmost_sample;
4544 vs->zoom_focus = zoom_focus;
4547 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4554 Editor::undo_visual_state ()
4556 if (undo_visual_stack.empty()) {
4560 VisualState* vs = undo_visual_stack.back();
4561 undo_visual_stack.pop_back();
4564 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4567 use_visual_state (*vs);
4572 Editor::redo_visual_state ()
4574 if (redo_visual_stack.empty()) {
4578 VisualState* vs = redo_visual_stack.back();
4579 redo_visual_stack.pop_back();
4581 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4582 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4585 use_visual_state (*vs);
4590 Editor::swap_visual_state ()
4592 if (undo_visual_stack.empty()) {
4593 redo_visual_state ();
4595 undo_visual_state ();
4600 Editor::use_visual_state (VisualState& vs)
4602 PBD::Unwinder<bool> nsv (no_save_visual, true);
4603 DisplaySuspender ds;
4605 vertical_adjustment.set_value (vs.y_position);
4607 set_zoom_focus (vs.zoom_focus);
4608 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4611 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4613 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4614 (*i)->clear_property_cache();
4615 (*i)->reset_visual_state ();
4619 _routes->update_visibility ();
4622 /** This is the core function that controls the zoom level of the canvas. It is called
4623 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4624 * @param spp new number of samples per pixel
4627 Editor::set_samples_per_pixel (samplecnt_t spp)
4633 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4634 const samplecnt_t lots_of_pixels = 4000;
4636 /* if the zoom level is greater than what you'd get trying to display 3
4637 * days of audio on a really big screen, then it's too big.
4640 if (spp * lots_of_pixels > three_days) {
4644 samples_per_pixel = spp;
4648 Editor::on_samples_per_pixel_changed ()
4650 bool const showing_time_selection = selection->time.length() > 0;
4652 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4653 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4654 (*i)->reshow_selection (selection->time);
4658 ZoomChanged (); /* EMIT_SIGNAL */
4660 ArdourCanvas::GtkCanvasViewport* c;
4662 c = get_track_canvas();
4664 c->canvas()->zoomed ();
4667 if (playhead_cursor) {
4668 playhead_cursor->set_position (playhead_cursor->current_sample ());
4671 refresh_location_display();
4672 _summary->set_overlays_dirty ();
4674 update_marker_labels ();
4680 Editor::playhead_cursor_sample () const
4682 return playhead_cursor->current_sample();
4686 Editor::queue_visual_videotimeline_update ()
4688 pending_visual_change.add (VisualChange::VideoTimeline);
4689 ensure_visual_change_idle_handler ();
4693 Editor::ensure_visual_change_idle_handler ()
4695 if (pending_visual_change.idle_handler_id < 0) {
4696 /* see comment in add_to_idle_resize above. */
4697 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4698 pending_visual_change.being_handled = false;
4703 Editor::_idle_visual_changer (void* arg)
4705 return static_cast<Editor*>(arg)->idle_visual_changer ();
4709 Editor::pre_render ()
4711 visual_change_queued = false;
4713 if (pending_visual_change.pending != 0) {
4714 ensure_visual_change_idle_handler();
4719 Editor::idle_visual_changer ()
4721 pending_visual_change.idle_handler_id = -1;
4723 if (pending_visual_change.pending == 0) {
4727 /* set_horizontal_position() below (and maybe other calls) call
4728 gtk_main_iteration(), so it's possible that a signal will be handled
4729 half-way through this method. If this signal wants an
4730 idle_visual_changer we must schedule another one after this one, so
4731 mark the idle_handler_id as -1 here to allow that. Also make a note
4732 that we are doing the visual change, so that changes in response to
4733 super-rapid-screen-update can be dropped if we are still processing
4737 if (visual_change_queued) {
4741 pending_visual_change.being_handled = true;
4743 VisualChange vc = pending_visual_change;
4745 pending_visual_change.pending = (VisualChange::Type) 0;
4747 visual_changer (vc);
4749 pending_visual_change.being_handled = false;
4751 visual_change_queued = true;
4753 return 0; /* this is always a one-shot call */
4757 Editor::visual_changer (const VisualChange& vc)
4760 * Changed first so the correct horizontal canvas position is calculated in
4761 * Editor::set_horizontal_position
4763 if (vc.pending & VisualChange::ZoomLevel) {
4764 set_samples_per_pixel (vc.samples_per_pixel);
4767 if (vc.pending & VisualChange::TimeOrigin) {
4768 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4769 set_horizontal_position (new_time_origin);
4772 if (vc.pending & VisualChange::YOrigin) {
4773 vertical_adjustment.set_value (vc.y_origin);
4777 * Now the canvas is in the final state before render the canvas items that
4778 * support the Item::prepare_for_render interface can calculate the correct
4779 * item to visible canvas intersection.
4781 if (vc.pending & VisualChange::ZoomLevel) {
4782 on_samples_per_pixel_changed ();
4784 compute_fixed_ruler_scale ();
4786 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4787 update_tempo_based_rulers ();
4790 if (!(vc.pending & VisualChange::ZoomLevel)) {
4791 /* If the canvas is not being zoomed then the canvas items will not change
4792 * and cause Item::prepare_for_render to be called so do it here manually.
4793 * Not ideal, but I can't think of a better solution atm.
4795 _track_canvas->prepare_for_render();
4798 /* If we are only scrolling vertically there is no need to update these */
4799 if (vc.pending != VisualChange::YOrigin) {
4800 update_fixed_rulers ();
4801 redisplay_grid (true);
4803 /* video frames & position need to be updated for zoom, horiz-scroll
4804 * and (explicitly) VisualChange::VideoTimeline.
4806 update_video_timeline();
4809 _summary->set_overlays_dirty ();
4812 struct EditorOrderTimeAxisSorter {
4813 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4814 return a->order () < b->order ();
4819 Editor::sort_track_selection (TrackViewList& sel)
4821 EditorOrderTimeAxisSorter cmp;
4826 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4829 samplepos_t where = 0;
4830 EditPoint ep = _edit_point;
4832 if (Profile->get_mixbus()) {
4833 if (ep == EditAtSelectedMarker) {
4834 ep = EditAtPlayhead;
4838 if (from_outside_canvas && (ep == EditAtMouse)) {
4839 ep = EditAtPlayhead;
4840 } else if (from_context_menu && (ep == EditAtMouse)) {
4841 return canvas_event_sample (&context_click_event, 0, 0);
4844 if (entered_marker) {
4845 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4846 return entered_marker->position();
4849 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4850 ep = EditAtSelectedMarker;
4853 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4854 ep = EditAtPlayhead;
4857 MusicSample snap_mf (0, 0);
4860 case EditAtPlayhead:
4861 if (_dragging_playhead) {
4862 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4863 where = playhead_cursor->current_sample();
4865 where = _session->audible_sample();
4867 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4870 case EditAtSelectedMarker:
4871 if (!selection->markers.empty()) {
4873 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4876 where = loc->start();
4880 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4888 if (!mouse_sample (where, ignored)) {
4889 /* XXX not right but what can we do ? */
4892 snap_mf.sample = where;
4894 where = snap_mf.sample;
4895 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4903 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4905 if (!_session) return;
4907 begin_reversible_command (cmd);
4911 if ((tll = transport_loop_location()) == 0) {
4912 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4913 XMLNode &before = _session->locations()->get_state();
4914 _session->locations()->add (loc, true);
4915 _session->set_auto_loop_location (loc);
4916 XMLNode &after = _session->locations()->get_state();
4917 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4919 XMLNode &before = tll->get_state();
4920 tll->set_hidden (false, this);
4921 tll->set (start, end);
4922 XMLNode &after = tll->get_state();
4923 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4926 commit_reversible_command ();
4930 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4932 if (!_session) return;
4934 begin_reversible_command (cmd);
4938 if ((tpl = transport_punch_location()) == 0) {
4939 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4940 XMLNode &before = _session->locations()->get_state();
4941 _session->locations()->add (loc, true);
4942 _session->set_auto_punch_location (loc);
4943 XMLNode &after = _session->locations()->get_state();
4944 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4946 XMLNode &before = tpl->get_state();
4947 tpl->set_hidden (false, this);
4948 tpl->set (start, end);
4949 XMLNode &after = tpl->get_state();
4950 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4953 commit_reversible_command ();
4956 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4957 * @param rs List to which found regions are added.
4958 * @param where Time to look at.
4959 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4962 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4964 const TrackViewList* tracks;
4967 tracks = &track_views;
4972 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4974 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4977 boost::shared_ptr<Track> tr;
4978 boost::shared_ptr<Playlist> pl;
4980 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4982 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4984 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4985 RegionView* rv = rtv->view()->find_view (*i);
4996 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4998 const TrackViewList* tracks;
5001 tracks = &track_views;
5006 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
5007 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
5009 boost::shared_ptr<Track> tr;
5010 boost::shared_ptr<Playlist> pl;
5012 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
5014 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
5016 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
5018 RegionView* rv = rtv->view()->find_view (*i);
5029 /** Get regions using the following method:
5031 * Make a region list using:
5032 * (a) any selected regions
5033 * (b) the intersection of any selected tracks and the edit point(*)
5034 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
5036 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5038 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5042 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
5044 RegionSelection regions;
5046 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5047 regions.add (entered_regionview);
5049 regions = selection->regions;
5052 if (regions.empty()) {
5053 TrackViewList tracks = selection->tracks;
5055 if (!tracks.empty()) {
5056 /* no region selected or entered, but some selected tracks:
5057 * act on all regions on the selected tracks at the edit point
5059 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
5060 get_regions_at(regions, where, tracks);
5067 /** Get regions using the following method:
5069 * Make a region list using:
5070 * (a) any selected regions
5071 * (b) the intersection of any selected tracks and the edit point(*)
5072 * (c) if neither exists, then whatever region is under the mouse
5074 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5076 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5079 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
5081 RegionSelection regions;
5083 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5084 regions.add (entered_regionview);
5086 regions = selection->regions;
5089 if (regions.empty()) {
5090 TrackViewList tracks = selection->tracks;
5092 if (!tracks.empty()) {
5093 /* no region selected or entered, but some selected tracks:
5094 * act on all regions on the selected tracks at the edit point
5096 get_regions_at(regions, pos, tracks);
5103 /** Start with regions that are selected, or the entered regionview if none are selected.
5104 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5105 * of the regions that we started with.
5109 Editor::get_regions_from_selection_and_entered () const
5111 RegionSelection regions = selection->regions;
5113 if (regions.empty() && entered_regionview) {
5114 regions.add (entered_regionview);
5121 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5123 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5124 RouteTimeAxisView* rtav;
5126 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5127 boost::shared_ptr<Playlist> pl;
5128 std::vector<boost::shared_ptr<Region> > results;
5129 boost::shared_ptr<Track> tr;
5131 if ((tr = rtav->track()) == 0) {
5136 if ((pl = (tr->playlist())) != 0) {
5137 boost::shared_ptr<Region> r = pl->region_by_id (id);
5139 RegionView* rv = rtav->view()->find_view (r);
5141 regions.push_back (rv);
5150 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5153 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5154 MidiTimeAxisView* mtav;
5156 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5158 mtav->get_per_region_note_selection (selection);
5165 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5167 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5169 RouteTimeAxisView* tatv;
5171 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5173 boost::shared_ptr<Playlist> pl;
5174 vector<boost::shared_ptr<Region> > results;
5176 boost::shared_ptr<Track> tr;
5178 if ((tr = tatv->track()) == 0) {
5183 if ((pl = (tr->playlist())) != 0) {
5184 if (src_comparison) {
5185 pl->get_source_equivalent_regions (region, results);
5187 pl->get_region_list_equivalent_regions (region, results);
5191 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5192 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5193 regions.push_back (marv);
5202 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5204 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5205 RouteTimeAxisView* tatv;
5206 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5207 if (!tatv->track()) {
5210 RegionView* marv = tatv->view()->find_view (region);
5220 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5222 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5223 RouteTimeAxisView* rtav;
5224 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5225 if (rtav->route() == route) {
5234 Editor::show_rhythm_ferret ()
5236 if (rhythm_ferret == 0) {
5237 rhythm_ferret = new RhythmFerret(*this);
5240 rhythm_ferret->set_session (_session);
5241 rhythm_ferret->show ();
5242 rhythm_ferret->present ();
5246 Editor::first_idle ()
5248 MessageDialog* dialog = 0;
5250 if (track_views.size() > 1) {
5251 Timers::TimerSuspender t;
5252 dialog = new MessageDialog (
5253 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5257 ARDOUR_UI::instance()->flush_pending (60);
5260 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5264 /* now that all regionviews should exist, setup region selection */
5268 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5269 /* this is cumulative: rs is NOT cleared each time */
5270 get_regionviews_by_id (*pr, rs);
5273 selection->set (rs);
5275 /* first idle adds route children (automation tracks), so we need to redisplay here */
5276 _routes->redisplay ();
5280 if (_session->undo_depth() == 0) {
5281 undo_action->set_sensitive(false);
5283 redo_action->set_sensitive(false);
5284 begin_selection_op_history ();
5290 Editor::_idle_resize (gpointer arg)
5292 return ((Editor*)arg)->idle_resize ();
5296 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5298 if (resize_idle_id < 0) {
5299 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5300 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5301 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5303 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5304 _pending_resize_amount = 0;
5307 /* make a note of the smallest resulting height, so that we can clamp the
5308 lower limit at TimeAxisView::hSmall */
5310 int32_t min_resulting = INT32_MAX;
5312 _pending_resize_amount += h;
5313 _pending_resize_view = view;
5315 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5317 if (selection->tracks.contains (_pending_resize_view)) {
5318 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5319 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5323 if (min_resulting < 0) {
5328 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5329 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5333 /** Handle pending resizing of tracks */
5335 Editor::idle_resize ()
5337 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5339 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5340 selection->tracks.contains (_pending_resize_view)) {
5342 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5343 if (*i != _pending_resize_view) {
5344 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5349 _pending_resize_amount = 0;
5350 _group_tabs->set_dirty ();
5351 resize_idle_id = -1;
5359 ENSURE_GUI_THREAD (*this, &Editor::located);
5362 playhead_cursor->set_position (_session->audible_sample ());
5363 if (_follow_playhead && !_pending_initial_locate) {
5364 reset_x_origin_to_follow_playhead ();
5368 _pending_locate_request = false;
5369 _pending_initial_locate = false;
5370 _last_update_time = 0;
5374 Editor::region_view_added (RegionView * rv)
5376 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5378 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5379 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5380 if (rv->region()->id () == (*rnote).first) {
5381 mrv->select_notes ((*rnote).second);
5382 selection->pending_midi_note_selection.erase(rnote);
5388 _summary->set_background_dirty ();
5390 mark_region_boundary_cache_dirty ();
5394 Editor::region_view_removed ()
5396 _summary->set_background_dirty ();
5398 mark_region_boundary_cache_dirty ();
5402 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5404 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5405 if ((*j)->stripable() == s) {
5414 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5416 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5417 if ((*j)->control() == c) {
5421 TimeAxisView::Children kids = (*j)->get_child_list ();
5423 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5424 if ((*k)->control() == c) {
5434 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5438 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5439 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5449 Editor::suspend_route_redisplay ()
5452 _routes->suspend_redisplay();
5457 Editor::resume_route_redisplay ()
5460 _routes->redisplay(); // queue redisplay
5461 _routes->resume_redisplay();
5466 Editor::add_vcas (VCAList& vlist)
5470 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5471 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5474 add_stripables (sl);
5478 Editor::add_routes (RouteList& rlist)
5482 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5486 add_stripables (sl);
5490 Editor::add_stripables (StripableList& sl)
5492 list<TimeAxisView*> new_views;
5493 boost::shared_ptr<VCA> v;
5494 boost::shared_ptr<Route> r;
5495 TrackViewList new_selection;
5496 bool from_scratch = (track_views.size() == 0);
5498 sl.sort (Stripable::Sorter());
5500 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5502 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5504 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5506 new_views.push_back (vtv);
5508 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5510 if (r->is_auditioner() || r->is_monitor()) {
5514 RouteTimeAxisView* rtv;
5515 DataType dt = r->input()->default_type();
5517 if (dt == ARDOUR::DataType::AUDIO) {
5518 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5520 } else if (dt == ARDOUR::DataType::MIDI) {
5521 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5524 throw unknown_type();
5527 new_views.push_back (rtv);
5528 track_views.push_back (rtv);
5529 new_selection.push_back (rtv);
5531 rtv->effective_gain_display ();
5533 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5534 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5538 if (new_views.size() > 0) {
5539 _routes->time_axis_views_added (new_views);
5540 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5543 /* note: !new_selection.empty() means that we got some routes rather
5547 if (!from_scratch && !new_selection.empty()) {
5548 selection->set (new_selection);
5549 begin_selection_op_history();
5552 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5553 show_editor_mixer (true);
5556 editor_list_button.set_sensitive (true);
5560 Editor::timeaxisview_deleted (TimeAxisView *tv)
5562 if (tv == entered_track) {
5566 if (_session && _session->deletion_in_progress()) {
5567 /* the situation is under control */
5571 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5573 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5575 _routes->route_removed (tv);
5577 TimeAxisView::Children c = tv->get_child_list ();
5578 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5579 if (entered_track == i->get()) {
5584 /* remove it from the list of track views */
5586 TrackViewList::iterator i;
5588 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5589 i = track_views.erase (i);
5592 /* update whatever the current mixer strip is displaying, if revelant */
5594 boost::shared_ptr<Route> route;
5597 route = rtav->route ();
5600 if (current_mixer_strip && current_mixer_strip->route() == route) {
5602 TimeAxisView* next_tv;
5604 if (track_views.empty()) {
5606 } else if (i == track_views.end()) {
5607 next_tv = track_views.front();
5612 // skip VCAs (cannot be selected, n/a in editor-mixer)
5613 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5614 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5615 next_tv = track_views.front();
5617 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5618 /* just in case: no master, only a VCA remains */
5624 set_selected_mixer_strip (*next_tv);
5626 /* make the editor mixer strip go away setting the
5627 * button to inactive (which also unticks the menu option)
5630 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5636 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5642 DisplaySuspender ds;
5643 PresentationInfo::ChangeSuspender cs;
5645 if (apply_to_selection) {
5646 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5648 TrackSelection::iterator j = i;
5651 hide_track_in_display (*i, false);
5656 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5658 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5659 /* this will hide the mixer strip */
5660 set_selected_mixer_strip (*tv);
5663 _routes->hide_track_in_display (*tv);
5668 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5673 _routes->show_track_in_display (*tv);
5674 if (move_into_view) {
5675 ensure_time_axis_view_is_visible (*tv, false);
5680 Editor::sync_track_view_list_and_routes ()
5682 track_views = TrackViewList (_routes->views ());
5684 _summary->set_background_dirty();
5685 _group_tabs->set_dirty ();
5687 return false; // do not call again (until needed)
5691 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5693 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5698 /** Find a StripableTimeAxisView by the ID of its stripable */
5699 StripableTimeAxisView*
5700 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5702 StripableTimeAxisView* v;
5704 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5705 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5706 if(v->stripable()->id() == id) {
5716 Editor::fit_route_group (RouteGroup *g)
5718 TrackViewList ts = axis_views_from_routes (g->route_list ());
5723 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5725 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5728 _session->cancel_audition ();
5732 if (_session->is_auditioning()) {
5733 _session->cancel_audition ();
5734 if (r == last_audition_region) {
5739 _session->audition_region (r);
5740 last_audition_region = r;
5745 Editor::hide_a_region (boost::shared_ptr<Region> r)
5747 r->set_hidden (true);
5751 Editor::show_a_region (boost::shared_ptr<Region> r)
5753 r->set_hidden (false);
5757 Editor::audition_region_from_region_list ()
5759 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5763 Editor::hide_region_from_region_list ()
5765 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5769 Editor::show_region_in_region_list ()
5771 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5775 Editor::step_edit_status_change (bool yn)
5778 start_step_editing ();
5780 stop_step_editing ();
5785 Editor::start_step_editing ()
5787 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5791 Editor::stop_step_editing ()
5793 step_edit_connection.disconnect ();
5797 Editor::check_step_edit ()
5799 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5800 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5802 mtv->check_step_edit ();
5806 return true; // do it again, till we stop
5810 Editor::scroll_press (Direction dir)
5812 ++_scroll_callbacks;
5814 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5815 /* delay the first auto-repeat */
5821 scroll_backward (1);
5829 scroll_up_one_track ();
5833 scroll_down_one_track ();
5837 /* do hacky auto-repeat */
5838 if (!_scroll_connection.connected ()) {
5840 _scroll_connection = Glib::signal_timeout().connect (
5841 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5844 _scroll_callbacks = 0;
5851 Editor::scroll_release ()
5853 _scroll_connection.disconnect ();
5856 /** Queue a change for the Editor viewport x origin to follow the playhead */
5858 Editor::reset_x_origin_to_follow_playhead ()
5860 samplepos_t const sample = playhead_cursor->current_sample ();
5862 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5864 if (_session->transport_speed() < 0) {
5866 if (sample > (current_page_samples() / 2)) {
5867 center_screen (sample-(current_page_samples()/2));
5869 center_screen (current_page_samples()/2);
5876 if (sample < _leftmost_sample) {
5878 if (_session->transport_rolling()) {
5879 /* rolling; end up with the playhead at the right of the page */
5880 l = sample - current_page_samples ();
5882 /* not rolling: end up with the playhead 1/4 of the way along the page */
5883 l = sample - current_page_samples() / 4;
5887 if (_session->transport_rolling()) {
5888 /* rolling: end up with the playhead on the left of the page */
5891 /* not rolling: end up with the playhead 3/4 of the way along the page */
5892 l = sample - 3 * current_page_samples() / 4;
5900 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5906 Editor::super_rapid_screen_update ()
5908 if (!_session || !_session->engine().running()) {
5912 /* METERING / MIXER STRIPS */
5914 /* update track meters, if required */
5915 if (contents().is_mapped() && meters_running) {
5916 RouteTimeAxisView* rtv;
5917 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5918 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5919 rtv->fast_update ();
5924 /* and any current mixer strip */
5925 if (current_mixer_strip) {
5926 current_mixer_strip->fast_update ();
5929 bool latent_locate = false;
5930 samplepos_t sample = _session->audible_sample (&latent_locate);
5931 const int64_t now = g_get_monotonic_time ();
5934 if (_session->exporting ()) {
5935 /* freewheel/export may be faster or slower than transport_speed() / SR.
5936 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5938 _last_update_time = 0;
5941 if (!_session->transport_rolling ()) {
5942 /* Do not interpolate the playhead position; just set it */
5943 _last_update_time = 0;
5946 if (_last_update_time > 0) {
5947 /* interpolate and smoothen playhead position */
5948 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5949 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5950 err = sample - guess;
5952 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5953 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5956 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5958 err, _err_screen_engine);
5963 _err_screen_engine = 0;
5966 if (err > 8192 || latent_locate) {
5967 // in case of x-runs or freewheeling
5968 _last_update_time = 0;
5969 sample = _session->audible_sample ();
5971 _last_update_time = now;
5974 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5976 MusicSample where (sample, 0);
5977 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5978 snapped_cursor->hide ();
5979 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5980 /* EditAtPlayhead does not snap */
5981 } else if (_edit_point == EditAtSelectedMarker) {
5982 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5983 * however, the current editing code -does- snap so I'll draw it that way for now.
5985 if (!selection->markers.empty()) {
5986 MusicSample ms (selection->markers.front()->position(), 0);
5987 snap_to (ms); // should use snap_to_with_modifier?
5988 snapped_cursor->set_position (ms.sample);
5989 snapped_cursor->show ();
5991 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5992 snapped_cursor->show ();
5993 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5994 snapped_cursor->hide ();
5997 /* There are a few reasons why we might not update the playhead / viewport stuff:
5999 * 1. we don't update things when there's a pending locate request, otherwise
6000 * when the editor requests a locate there is a chance that this method
6001 * will move the playhead before the locate request is processed, causing
6003 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
6004 * 3. if we're still at the same frame that we were last time, there's nothing to do.
6006 if (_pending_locate_request) {
6007 _last_update_time = 0;
6011 if (_dragging_playhead) {
6012 _last_update_time = 0;
6016 if (playhead_cursor->current_sample () == sample) {
6020 playhead_cursor->set_position (sample);
6022 if (_session->requested_return_sample() >= 0) {
6023 _last_update_time = 0;
6027 if (!_follow_playhead || pending_visual_change.being_handled) {
6028 /* We only do this if we aren't already
6029 * handling a visual change (ie if
6030 * pending_visual_change.being_handled is
6031 * false) so that these requests don't stack
6032 * up there are too many of them to handle in
6038 if (!_stationary_playhead) {
6039 reset_x_origin_to_follow_playhead ();
6041 samplepos_t const sample = playhead_cursor->current_sample ();
6042 double target = ((double)sample - (double)current_page_samples() / 2.0);
6043 if (target <= 0.0) {
6046 /* compare to EditorCursor::set_position() */
6047 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
6048 double const new_pos = sample_to_pixel_unrounded (target);
6049 if (rint (new_pos) != rint (old_pos)) {
6050 reset_x_origin (pixel_to_sample (new_pos));
6057 Editor::session_going_away ()
6059 _have_idled = false;
6061 _session_connections.drop_connections ();
6063 super_rapid_screen_update_connection.disconnect ();
6065 selection->clear ();
6066 cut_buffer->clear ();
6068 clicked_regionview = 0;
6069 clicked_axisview = 0;
6070 clicked_routeview = 0;
6071 entered_regionview = 0;
6073 _last_update_time = 0;
6076 playhead_cursor->hide ();
6078 /* rip everything out of the list displays */
6082 _route_groups->clear ();
6084 /* do this first so that deleting a track doesn't reset cms to null
6085 and thus cause a leak.
6088 if (current_mixer_strip) {
6089 if (current_mixer_strip->get_parent() != 0) {
6090 global_hpacker.remove (*current_mixer_strip);
6092 delete current_mixer_strip;
6093 current_mixer_strip = 0;
6096 /* delete all trackviews */
6098 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6101 track_views.clear ();
6103 nudge_clock->set_session (0);
6105 editor_list_button.set_active(false);
6106 editor_list_button.set_sensitive(false);
6108 /* clear tempo/meter rulers */
6109 remove_metric_marks ();
6110 clear_marker_display ();
6116 stop_step_editing ();
6120 /* get rid of any existing editor mixer strip */
6122 WindowTitle title(Glib::get_application_name());
6123 title += _("Editor");
6125 own_window()->set_title (title.get_string());
6128 SessionHandlePtr::session_going_away ();
6132 Editor::trigger_script (int i)
6134 LuaInstance::instance()-> call_action (i);
6138 Editor::show_editor_list (bool yn)
6141 _editor_list_vbox.show ();
6143 _editor_list_vbox.hide ();
6148 Editor::change_region_layering_order (bool from_context_menu)
6150 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6152 if (!clicked_routeview) {
6153 if (layering_order_editor) {
6154 layering_order_editor->hide ();
6159 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6165 boost::shared_ptr<Playlist> pl = track->playlist();
6171 if (layering_order_editor == 0) {
6172 layering_order_editor = new RegionLayeringOrderEditor (*this);
6175 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6176 layering_order_editor->maybe_present ();
6180 Editor::update_region_layering_order_editor ()
6182 if (layering_order_editor && layering_order_editor->is_visible ()) {
6183 change_region_layering_order (true);
6188 Editor::setup_fade_images ()
6190 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6191 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6192 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6193 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6194 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6196 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6197 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6198 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6199 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6200 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6204 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6206 Editor::action_menu_item (std::string const & name)
6208 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6211 return *manage (a->create_menu_item ());
6215 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6217 EventBox* b = manage (new EventBox);
6218 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6219 Label* l = manage (new Label (name));
6223 _the_notebook.append_page (widget, *b);
6227 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6229 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6230 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6233 if (ev->type == GDK_2BUTTON_PRESS) {
6235 /* double-click on a notebook tab shrinks or expands the notebook */
6237 if (_notebook_shrunk) {
6238 if (pre_notebook_shrink_pane_width) {
6239 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6241 _notebook_shrunk = false;
6243 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6245 /* this expands the LHS of the edit pane to cover the notebook
6246 PAGE but leaves the tabs visible.
6248 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6249 _notebook_shrunk = true;
6257 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6259 using namespace Menu_Helpers;
6261 MenuList& items = _control_point_context_menu.items ();
6264 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6265 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6266 if (!can_remove_control_point (item)) {
6267 items.back().set_sensitive (false);
6270 _control_point_context_menu.popup (event->button.button, event->button.time);
6274 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6276 using namespace Menu_Helpers;
6278 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6283 /* We need to get the selection here and pass it to the operations, since
6284 popping up the menu will cause a region leave event which clears
6285 entered_regionview. */
6287 MidiRegionView& mrv = note->region_view();
6288 const RegionSelection rs = get_regions_from_selection_and_entered ();
6289 const uint32_t sel_size = mrv.selection_size ();
6291 MenuList& items = _note_context_menu.items();
6295 items.push_back(MenuElem(_("Delete"),
6296 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6299 items.push_back(MenuElem(_("Edit..."),
6300 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6301 if (sel_size != 1) {
6302 items.back().set_sensitive (false);
6305 items.push_back(MenuElem(_("Transpose..."),
6306 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6309 items.push_back(MenuElem(_("Legatize"),
6310 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6312 items.back().set_sensitive (false);
6315 items.push_back(MenuElem(_("Quantize..."),
6316 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6318 items.push_back(MenuElem(_("Remove Overlap"),
6319 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6321 items.back().set_sensitive (false);
6324 items.push_back(MenuElem(_("Transform..."),
6325 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6327 _note_context_menu.popup (event->button.button, event->button.time);
6331 Editor::zoom_vertical_modifier_released()
6333 _stepping_axis_view = 0;
6337 Editor::ui_parameter_changed (string parameter)
6339 if (parameter == "icon-set") {
6340 while (!_cursor_stack.empty()) {
6341 _cursor_stack.pop_back();
6343 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6344 _cursor_stack.push_back(_cursors->grabber);
6345 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6346 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6348 } else if (parameter == "draggable-playhead") {
6349 if (_verbose_cursor) {
6350 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6352 } else if (parameter == "use-note-bars-for-velocity") {
6353 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6354 _track_canvas->request_redraw (_track_canvas->visible_area());
6355 } else if (parameter == "use-note-color-for-velocity") {
6356 /* handled individually by each MidiRegionView */
6361 Editor::use_own_window (bool and_fill_it)
6363 bool new_window = !own_window();
6365 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6367 if (win && new_window) {
6368 win->set_name ("EditorWindow");
6370 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6372 // win->signal_realize().connect (*this, &Editor::on_realize);
6373 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6374 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6375 win->set_data ("ardour-bindings", bindings);
6380 DisplaySuspender ds;
6381 contents().show_all ();
6383 /* XXX: this is a bit unfortunate; it would probably
6384 be nicer if we could just call show () above rather
6385 than needing the show_all ()
6388 /* re-hide stuff if necessary */
6389 editor_list_button_toggled ();
6390 parameter_changed ("show-summary");
6391 parameter_changed ("show-group-tabs");
6392 parameter_changed ("show-zoom-tools");
6394 /* now reset all audio_time_axis heights, because widgets might need
6400 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6401 tv = (static_cast<TimeAxisView*>(*i));
6402 tv->reset_height ();
6405 if (current_mixer_strip) {
6406 current_mixer_strip->hide_things ();
6407 current_mixer_strip->parameter_changed ("mixer-element-visibility");