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)
452 /* we are a singleton */
454 PublicEditor::_instance = this;
458 last_event_time.tv_sec = 0;
459 last_event_time.tv_usec = 0;
461 selection_op_history.clear();
464 grid_type_strings = I18N (_grid_type_strings);
465 zoom_focus_strings = I18N (_zoom_focus_strings);
466 edit_mode_strings = I18N (_edit_mode_strings);
467 edit_point_strings = I18N (_edit_point_strings);
468 #ifdef USE_RUBBERBAND
469 rb_opt_strings = I18N (_rb_opt_strings);
473 build_edit_mode_menu();
474 build_zoom_focus_menu();
475 build_track_count_menu();
476 build_grid_type_menu();
477 build_edit_point_menu();
479 location_marker_color = UIConfiguration::instance().color ("location marker");
480 location_range_color = UIConfiguration::instance().color ("location range");
481 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
482 location_loop_color = UIConfiguration::instance().color ("location loop");
483 location_punch_color = UIConfiguration::instance().color ("location punch");
485 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
487 TimeAxisView::setup_sizes ();
488 ArdourMarker::setup_sizes (timebar_height);
489 TempoCurve::setup_sizes (timebar_height);
491 bbt_label.set_name ("EditorRulerLabel");
492 bbt_label.set_size_request (-1, (int)timebar_height);
493 bbt_label.set_alignment (1.0, 0.5);
494 bbt_label.set_padding (5,0);
496 bbt_label.set_no_show_all();
497 minsec_label.set_name ("EditorRulerLabel");
498 minsec_label.set_size_request (-1, (int)timebar_height);
499 minsec_label.set_alignment (1.0, 0.5);
500 minsec_label.set_padding (5,0);
501 minsec_label.hide ();
502 minsec_label.set_no_show_all();
503 timecode_label.set_name ("EditorRulerLabel");
504 timecode_label.set_size_request (-1, (int)timebar_height);
505 timecode_label.set_alignment (1.0, 0.5);
506 timecode_label.set_padding (5,0);
507 timecode_label.hide ();
508 timecode_label.set_no_show_all();
509 samples_label.set_name ("EditorRulerLabel");
510 samples_label.set_size_request (-1, (int)timebar_height);
511 samples_label.set_alignment (1.0, 0.5);
512 samples_label.set_padding (5,0);
513 samples_label.hide ();
514 samples_label.set_no_show_all();
516 tempo_label.set_name ("EditorRulerLabel");
517 tempo_label.set_size_request (-1, (int)timebar_height);
518 tempo_label.set_alignment (1.0, 0.5);
519 tempo_label.set_padding (5,0);
521 tempo_label.set_no_show_all();
523 meter_label.set_name ("EditorRulerLabel");
524 meter_label.set_size_request (-1, (int)timebar_height);
525 meter_label.set_alignment (1.0, 0.5);
526 meter_label.set_padding (5,0);
528 meter_label.set_no_show_all();
530 if (Profile->get_trx()) {
531 mark_label.set_text (_("Markers"));
533 mark_label.set_name ("EditorRulerLabel");
534 mark_label.set_size_request (-1, (int)timebar_height);
535 mark_label.set_alignment (1.0, 0.5);
536 mark_label.set_padding (5,0);
538 mark_label.set_no_show_all();
540 cd_mark_label.set_name ("EditorRulerLabel");
541 cd_mark_label.set_size_request (-1, (int)timebar_height);
542 cd_mark_label.set_alignment (1.0, 0.5);
543 cd_mark_label.set_padding (5,0);
544 cd_mark_label.hide();
545 cd_mark_label.set_no_show_all();
547 videotl_bar_height = 4;
548 videotl_label.set_name ("EditorRulerLabel");
549 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
550 videotl_label.set_alignment (1.0, 0.5);
551 videotl_label.set_padding (5,0);
552 videotl_label.hide();
553 videotl_label.set_no_show_all();
555 range_mark_label.set_name ("EditorRulerLabel");
556 range_mark_label.set_size_request (-1, (int)timebar_height);
557 range_mark_label.set_alignment (1.0, 0.5);
558 range_mark_label.set_padding (5,0);
559 range_mark_label.hide();
560 range_mark_label.set_no_show_all();
562 transport_mark_label.set_name ("EditorRulerLabel");
563 transport_mark_label.set_size_request (-1, (int)timebar_height);
564 transport_mark_label.set_alignment (1.0, 0.5);
565 transport_mark_label.set_padding (5,0);
566 transport_mark_label.hide();
567 transport_mark_label.set_no_show_all();
569 initialize_canvas ();
571 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
573 _summary = new EditorSummary (this);
575 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
576 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
578 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
580 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
581 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
583 edit_controls_vbox.set_spacing (0);
584 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
585 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
587 HBox* h = manage (new HBox);
588 _group_tabs = new EditorGroupTabs (this);
589 if (!ARDOUR::Profile->get_trx()) {
590 h->pack_start (*_group_tabs, PACK_SHRINK);
592 h->pack_start (edit_controls_vbox);
593 controls_layout.add (*h);
595 controls_layout.set_name ("EditControlsBase");
596 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
597 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
598 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
600 _cursors = new MouseCursors;
601 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
602 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
604 /* Push default cursor to ever-present bottom of cursor stack. */
605 push_canvas_cursor(_cursors->grabber);
607 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
609 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
610 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
611 pad_line_1->set_outline_color (0xFF0000FF);
617 edit_packer.set_col_spacings (0);
618 edit_packer.set_row_spacings (0);
619 edit_packer.set_homogeneous (false);
620 edit_packer.set_border_width (0);
621 edit_packer.set_name ("EditorWindow");
623 time_bars_event_box.add (time_bars_vbox);
624 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
625 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
627 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
628 axis_view_shadow->set_size_request (4, -1);
629 axis_view_shadow->set_name("EditorWindow");
630 axis_view_shadow->show();
632 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
634 /* labels for the time bars */
635 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
637 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
639 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
641 bottom_hbox.set_border_width (2);
642 bottom_hbox.set_spacing (3);
644 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
646 _route_groups = new EditorRouteGroups (this);
647 _routes = new EditorRoutes (this);
648 _regions = new EditorRegions (this);
649 _snapshots = new EditorSnapshots (this);
650 _locations = new EditorLocations (this);
651 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
653 /* these are static location signals */
655 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
657 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
659 add_notebook_page (_("Regions"), _regions->widget ());
660 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
661 add_notebook_page (_("Snapshots"), _snapshots->widget ());
662 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
663 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
665 _the_notebook.set_show_tabs (true);
666 _the_notebook.set_scrollable (true);
667 _the_notebook.popup_disable ();
668 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
669 _the_notebook.show_all ();
671 _notebook_shrunk = false;
674 /* Pick up some settings we need to cache, early */
676 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
679 settings->get_property ("notebook-shrunk", _notebook_shrunk);
682 editor_summary_pane.set_check_divider_position (true);
683 editor_summary_pane.add (edit_packer);
685 Button* summary_arrow_left = manage (new Button);
686 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
687 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
688 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 Button* summary_arrow_right = manage (new Button);
691 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
692 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
693 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
695 VBox* summary_arrows_left = manage (new VBox);
696 summary_arrows_left->pack_start (*summary_arrow_left);
698 VBox* summary_arrows_right = manage (new VBox);
699 summary_arrows_right->pack_start (*summary_arrow_right);
701 Frame* summary_frame = manage (new Frame);
702 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
704 summary_frame->add (*_summary);
705 summary_frame->show ();
707 _summary_hbox.pack_start (*summary_arrows_left, false, false);
708 _summary_hbox.pack_start (*summary_frame, true, true);
709 _summary_hbox.pack_start (*summary_arrows_right, false, false);
711 if (!ARDOUR::Profile->get_trx()) {
712 editor_summary_pane.add (_summary_hbox);
715 edit_pane.set_check_divider_position (true);
716 edit_pane.add (editor_summary_pane);
717 if (!ARDOUR::Profile->get_trx()) {
718 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
719 _editor_list_vbox.pack_start (_the_notebook);
720 edit_pane.add (_editor_list_vbox);
721 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
724 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
725 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
728 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
729 /* initial allocation is 90% to canvas, 10% to notebook */
732 edit_pane.set_divider (0, fract);
734 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
735 /* initial allocation is 90% to canvas, 10% to summary */
738 editor_summary_pane.set_divider (0, fract);
740 global_vpacker.set_spacing (0);
741 global_vpacker.set_border_width (0);
743 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
745 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
746 ebox->set_name("EditorWindow");
747 ebox->add (ebox_hpacker);
749 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
750 epane_box->set_name("EditorWindow");
751 epane_box->add (edit_pane);
753 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
754 epane_box2->set_name("EditorWindow");
755 epane_box2->add (global_vpacker);
757 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
758 toolbar_shadow->set_size_request (-1, 4);
759 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
760 toolbar_shadow->set_name("EditorWindow");
761 toolbar_shadow->show();
763 global_vpacker.pack_start (*toolbar_shadow, false, false);
764 global_vpacker.pack_start (*ebox, false, false);
765 global_vpacker.pack_start (*epane_box, true, true);
766 global_hpacker.pack_start (*epane_box2, true, true);
768 /* need to show the "contents" widget so that notebook will show if tab is switched to
771 global_hpacker.show ();
775 /* register actions now so that set_state() can find them and set toggles/checks etc */
782 _playlist_selector = new PlaylistSelector();
783 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
785 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
789 nudge_forward_button.set_name ("nudge button");
790 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
792 nudge_backward_button.set_name ("nudge button");
793 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
795 fade_context_menu.set_name ("ArdourContextMenu");
797 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
799 /* allow external control surfaces/protocols to do various things */
801 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
802 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
803 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
804 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
805 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
806 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
807 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
808 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
809 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
810 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
811 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
812 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
813 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
814 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
816 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
817 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
818 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
819 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
820 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
822 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
826 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
828 /* problematic: has to return a value and thus cannot be x-thread */
830 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
832 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
833 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
835 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
837 _ignore_region_action = false;
838 _last_region_menu_was_main = false;
839 _popup_region_menu_item = 0;
841 _show_marker_lines = false;
843 /* Button bindings */
845 button_bindings = new Bindings ("editor-mouse");
847 XMLNode* node = button_settings();
849 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
850 button_bindings->load_operation (**i);
856 /* grab current parameter state */
857 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
858 UIConfiguration::instance().map_parameters (pc);
860 setup_fade_images ();
862 set_grid_to (GridTypeNone);
867 delete button_bindings;
869 delete _route_groups;
870 delete _track_canvas_viewport;
873 delete _verbose_cursor;
874 delete quantize_dialog;
880 delete _playlist_selector;
881 delete _time_info_box;
886 LuaInstance::destroy_instance ();
888 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
891 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
894 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
900 Editor::button_settings () const
902 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
903 XMLNode* node = find_named_node (*settings, X_("Buttons"));
906 node = new XMLNode (X_("Buttons"));
913 Editor::get_smart_mode () const
915 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
919 Editor::catch_vanishing_regionview (RegionView *rv)
921 /* note: the selection will take care of the vanishing
922 audioregionview by itself.
925 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
929 if (clicked_regionview == rv) {
930 clicked_regionview = 0;
933 if (entered_regionview == rv) {
934 set_entered_regionview (0);
937 if (!_all_region_actions_sensitized) {
938 sensitize_all_region_actions (true);
943 Editor::set_entered_regionview (RegionView* rv)
945 if (rv == entered_regionview) {
949 if (entered_regionview) {
950 entered_regionview->exited ();
953 entered_regionview = rv;
955 if (entered_regionview != 0) {
956 entered_regionview->entered ();
959 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
960 /* This RegionView entry might have changed what region actions
961 are allowed, so sensitize them all in case a key is pressed.
963 sensitize_all_region_actions (true);
968 Editor::set_entered_track (TimeAxisView* tav)
971 entered_track->exited ();
977 entered_track->entered ();
982 Editor::instant_save ()
984 if (!constructed || !_session || no_save_instant) {
988 _session->add_instant_xml(get_state());
992 Editor::control_vertical_zoom_in_all ()
994 tav_zoom_smooth (false, true);
998 Editor::control_vertical_zoom_out_all ()
1000 tav_zoom_smooth (true, true);
1004 Editor::control_vertical_zoom_in_selected ()
1006 tav_zoom_smooth (false, false);
1010 Editor::control_vertical_zoom_out_selected ()
1012 tav_zoom_smooth (true, false);
1016 Editor::control_view (uint32_t view)
1018 goto_visual_state (view);
1022 Editor::control_unselect ()
1024 selection->clear_tracks ();
1028 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1030 TimeAxisView* tav = time_axis_view_from_stripable (s);
1034 case Selection::Add:
1035 selection->add (tav);
1037 case Selection::Toggle:
1038 selection->toggle (tav);
1040 case Selection::Extend:
1042 case Selection::Set:
1043 selection->set (tav);
1047 selection->clear_tracks ();
1052 Editor::control_step_tracks_up ()
1054 scroll_tracks_up_line ();
1058 Editor::control_step_tracks_down ()
1060 scroll_tracks_down_line ();
1064 Editor::control_scroll (float fraction)
1066 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1072 double step = fraction * current_page_samples();
1075 _control_scroll_target is an optional<T>
1077 it acts like a pointer to an samplepos_t, with
1078 a operator conversion to boolean to check
1079 that it has a value could possibly use
1080 playhead_cursor->current_sample to store the
1081 value and a boolean in the class to know
1082 when it's out of date
1085 if (!_control_scroll_target) {
1086 _control_scroll_target = _session->transport_sample();
1087 _dragging_playhead = true;
1090 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1091 *_control_scroll_target = 0;
1092 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1093 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1095 *_control_scroll_target += (samplepos_t) trunc (step);
1098 /* move visuals, we'll catch up with it later */
1100 playhead_cursor->set_position (*_control_scroll_target);
1101 UpdateAllTransportClocks (*_control_scroll_target);
1103 if (*_control_scroll_target > (current_page_samples() / 2)) {
1104 /* try to center PH in window */
1105 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1111 Now we do a timeout to actually bring the session to the right place
1112 according to the playhead. This is to avoid reading disk buffers on every
1113 call to control_scroll, which is driven by ScrollTimeline and therefore
1114 probably by a control surface wheel which can generate lots of events.
1116 /* cancel the existing timeout */
1118 control_scroll_connection.disconnect ();
1120 /* add the next timeout */
1122 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1126 Editor::deferred_control_scroll (samplepos_t /*target*/)
1128 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1129 /* reset for next stream */
1130 _control_scroll_target = boost::none;
1131 _dragging_playhead = false;
1136 Editor::access_action (const std::string& action_group, const std::string& action_item)
1142 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1145 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
1153 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1155 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1159 Editor::on_realize ()
1163 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1164 start_lock_event_timing ();
1169 Editor::start_lock_event_timing ()
1171 /* check if we should lock the GUI every 30 seconds */
1173 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1177 Editor::generic_event_handler (GdkEvent* ev)
1180 case GDK_BUTTON_PRESS:
1181 case GDK_BUTTON_RELEASE:
1182 case GDK_MOTION_NOTIFY:
1184 case GDK_KEY_RELEASE:
1185 if (contents().is_mapped()) {
1186 gettimeofday (&last_event_time, 0);
1190 case GDK_LEAVE_NOTIFY:
1191 switch (ev->crossing.detail) {
1192 case GDK_NOTIFY_UNKNOWN:
1193 case GDK_NOTIFY_INFERIOR:
1194 case GDK_NOTIFY_ANCESTOR:
1196 case GDK_NOTIFY_VIRTUAL:
1197 case GDK_NOTIFY_NONLINEAR:
1198 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1199 /* leaving window, so reset focus, thus ending any and
1200 all text entry operations.
1202 ARDOUR_UI::instance()->reset_focus (&contents());
1215 Editor::lock_timeout_callback ()
1217 struct timeval now, delta;
1219 gettimeofday (&now, 0);
1221 timersub (&now, &last_event_time, &delta);
1223 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1225 /* don't call again. Returning false will effectively
1226 disconnect us from the timer callback.
1228 unlock() will call start_lock_event_timing() to get things
1238 Editor::map_position_change (samplepos_t sample)
1240 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1242 if (_session == 0) {
1246 if (_follow_playhead) {
1247 center_screen (sample);
1250 playhead_cursor->set_position (sample);
1254 Editor::center_screen (samplepos_t sample)
1256 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1258 /* if we're off the page, then scroll.
1261 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1262 center_screen_internal (sample, page);
1267 Editor::center_screen_internal (samplepos_t sample, float page)
1271 if (sample > page) {
1272 sample -= (samplepos_t) page;
1277 reset_x_origin (sample);
1282 Editor::update_title ()
1284 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1286 if (!own_window()) {
1291 bool dirty = _session->dirty();
1293 string session_name;
1295 if (_session->snap_name() != _session->name()) {
1296 session_name = _session->snap_name();
1298 session_name = _session->name();
1302 session_name = "*" + session_name;
1305 WindowTitle title(session_name);
1306 title += S_("Window|Editor");
1307 title += Glib::get_application_name();
1308 own_window()->set_title (title.get_string());
1310 /* ::session_going_away() will have taken care of it */
1315 Editor::set_session (Session *t)
1317 SessionHandlePtr::set_session (t);
1323 /* initialize _leftmost_sample to the extents of the session
1324 * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
1325 * before the visible state has been loaded from instant.xml */
1326 _leftmost_sample = session_gui_extents().first;
1328 _playlist_selector->set_session (_session);
1329 nudge_clock->set_session (_session);
1330 _summary->set_session (_session);
1331 _group_tabs->set_session (_session);
1332 _route_groups->set_session (_session);
1333 _regions->set_session (_session);
1334 _snapshots->set_session (_session);
1335 _routes->set_session (_session);
1336 _locations->set_session (_session);
1337 _time_info_box->set_session (_session);
1339 if (rhythm_ferret) {
1340 rhythm_ferret->set_session (_session);
1343 if (analysis_window) {
1344 analysis_window->set_session (_session);
1348 sfbrowser->set_session (_session);
1351 compute_fixed_ruler_scale ();
1353 /* Make sure we have auto loop and auto punch ranges */
1355 Location* loc = _session->locations()->auto_loop_location();
1357 loc->set_name (_("Loop"));
1360 loc = _session->locations()->auto_punch_location();
1363 loc->set_name (_("Punch"));
1366 refresh_location_display ();
1368 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1369 * the selected Marker; this needs the LocationMarker list to be available.
1371 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1372 set_state (*node, Stateful::loading_state_version);
1374 /* catch up on selection state, etc. */
1377 sc.add (Properties::selected);
1378 presentation_info_changed (sc);
1380 /* catch up with the playhead */
1382 _session->request_locate (playhead_cursor->current_sample ());
1383 _pending_initial_locate = true;
1387 /* These signals can all be emitted by a non-GUI thread. Therefore the
1388 handlers for them must not attempt to directly interact with the GUI,
1389 but use PBD::Signal<T>::connect() which accepts an event loop
1390 ("context") where the handler will be asked to run.
1393 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1394 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1395 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1396 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1397 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1398 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1399 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1400 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1401 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1402 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1403 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1404 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1405 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1406 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1407 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1408 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1410 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1411 playhead_cursor->show ();
1413 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1414 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1415 snapped_cursor->show ();
1417 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1418 Config->map_parameters (pc);
1419 _session->config.map_parameters (pc);
1421 restore_ruler_visibility ();
1422 //tempo_map_changed (PropertyChange (0));
1423 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1425 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1426 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1429 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1430 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1433 /* register for undo history */
1434 _session->register_with_memento_command_factory(id(), this);
1435 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1437 LuaInstance::instance()->set_session(_session);
1439 start_updating_meters ();
1443 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1445 using namespace Menu_Helpers;
1447 void (Editor::*emf)(FadeShape);
1448 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1451 images = &_xfade_in_images;
1452 emf = &Editor::set_fade_in_shape;
1454 images = &_xfade_out_images;
1455 emf = &Editor::set_fade_out_shape;
1460 _("Linear (for highly correlated material)"),
1461 *(*images)[FadeLinear],
1462 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1466 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1470 _("Constant power"),
1471 *(*images)[FadeConstantPower],
1472 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1475 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1480 *(*images)[FadeSymmetric],
1481 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1485 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1490 *(*images)[FadeSlow],
1491 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1494 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1499 *(*images)[FadeFast],
1500 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1503 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1506 /** Pop up a context menu for when the user clicks on a start crossfade */
1508 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1510 using namespace Menu_Helpers;
1511 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1516 MenuList& items (xfade_in_context_menu.items());
1519 if (arv->audio_region()->fade_in_active()) {
1520 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1522 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1525 items.push_back (SeparatorElem());
1526 fill_xfade_menu (items, true);
1528 xfade_in_context_menu.popup (button, time);
1531 /** Pop up a context menu for when the user clicks on an end crossfade */
1533 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1535 using namespace Menu_Helpers;
1536 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1541 MenuList& items (xfade_out_context_menu.items());
1544 if (arv->audio_region()->fade_out_active()) {
1545 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1547 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1550 items.push_back (SeparatorElem());
1551 fill_xfade_menu (items, false);
1553 xfade_out_context_menu.popup (button, time);
1557 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1559 using namespace Menu_Helpers;
1560 Menu* (Editor::*build_menu_function)();
1563 switch (item_type) {
1565 case RegionViewName:
1566 case RegionViewNameHighlight:
1567 case LeftFrameHandle:
1568 case RightFrameHandle:
1569 if (with_selection) {
1570 build_menu_function = &Editor::build_track_selection_context_menu;
1572 build_menu_function = &Editor::build_track_region_context_menu;
1577 if (with_selection) {
1578 build_menu_function = &Editor::build_track_selection_context_menu;
1580 build_menu_function = &Editor::build_track_context_menu;
1585 if (clicked_routeview->track()) {
1586 build_menu_function = &Editor::build_track_context_menu;
1588 build_menu_function = &Editor::build_track_bus_context_menu;
1593 /* probably shouldn't happen but if it does, we don't care */
1597 menu = (this->*build_menu_function)();
1598 menu->set_name ("ArdourContextMenu");
1600 /* now handle specific situations */
1602 switch (item_type) {
1604 case RegionViewName:
1605 case RegionViewNameHighlight:
1606 case LeftFrameHandle:
1607 case RightFrameHandle:
1608 if (!with_selection) {
1609 if (region_edit_menu_split_item) {
1610 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1611 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1613 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1616 if (region_edit_menu_split_multichannel_item) {
1617 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1618 region_edit_menu_split_multichannel_item->set_sensitive (true);
1620 region_edit_menu_split_multichannel_item->set_sensitive (false);
1633 /* probably shouldn't happen but if it does, we don't care */
1637 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1639 /* Bounce to disk */
1641 using namespace Menu_Helpers;
1642 MenuList& edit_items = menu->items();
1644 edit_items.push_back (SeparatorElem());
1646 switch (clicked_routeview->audio_track()->freeze_state()) {
1647 case AudioTrack::NoFreeze:
1648 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1651 case AudioTrack::Frozen:
1652 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1655 case AudioTrack::UnFrozen:
1656 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1662 if (item_type == StreamItem && clicked_routeview) {
1663 clicked_routeview->build_underlay_menu(menu);
1666 /* When the region menu is opened, we setup the actions so that they look right
1669 sensitize_the_right_region_actions (false);
1670 _last_region_menu_was_main = false;
1672 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1673 menu->popup (button, time);
1677 Editor::build_track_context_menu ()
1679 using namespace Menu_Helpers;
1681 MenuList& edit_items = track_context_menu.items();
1684 add_dstream_context_items (edit_items);
1685 return &track_context_menu;
1689 Editor::build_track_bus_context_menu ()
1691 using namespace Menu_Helpers;
1693 MenuList& edit_items = track_context_menu.items();
1696 add_bus_context_items (edit_items);
1697 return &track_context_menu;
1701 Editor::build_track_region_context_menu ()
1703 using namespace Menu_Helpers;
1704 MenuList& edit_items = track_region_context_menu.items();
1707 /* we've just cleared the track region context menu, so the menu that these
1708 two items were on will have disappeared; stop them dangling.
1710 region_edit_menu_split_item = 0;
1711 region_edit_menu_split_multichannel_item = 0;
1713 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1716 boost::shared_ptr<Track> tr;
1717 boost::shared_ptr<Playlist> pl;
1719 if ((tr = rtv->track())) {
1720 add_region_context_items (edit_items, tr);
1724 add_dstream_context_items (edit_items);
1726 return &track_region_context_menu;
1730 Editor::loudness_analyze_region_selection ()
1735 Selection& s (PublicEditor::instance ().get_selection ());
1736 RegionSelection ars = s.regions;
1737 ARDOUR::AnalysisGraph ag (_session);
1738 samplecnt_t total_work = 0;
1740 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1741 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1745 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1748 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1749 total_work += arv->region ()->length ();
1752 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1754 ag.set_total_samples (total_work);
1755 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1758 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1759 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1763 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1767 ag.analyze_region (ar);
1770 if (!ag.canceled ()) {
1771 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1777 Editor::loudness_analyze_range_selection ()
1782 Selection& s (PublicEditor::instance ().get_selection ());
1783 TimeSelection ts = s.time;
1784 ARDOUR::AnalysisGraph ag (_session);
1785 samplecnt_t total_work = 0;
1787 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1788 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1792 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1796 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1797 total_work += j->length ();
1801 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1803 ag.set_total_samples (total_work);
1804 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1807 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1808 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1812 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1816 ag.analyze_range (rui->route (), pl, ts);
1819 if (!ag.canceled ()) {
1820 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1826 Editor::spectral_analyze_region_selection ()
1828 if (analysis_window == 0) {
1829 analysis_window = new AnalysisWindow();
1832 analysis_window->set_session(_session);
1834 analysis_window->show_all();
1837 analysis_window->set_regionmode();
1838 analysis_window->analyze();
1840 analysis_window->present();
1844 Editor::spectral_analyze_range_selection()
1846 if (analysis_window == 0) {
1847 analysis_window = new AnalysisWindow();
1850 analysis_window->set_session(_session);
1852 analysis_window->show_all();
1855 analysis_window->set_rangemode();
1856 analysis_window->analyze();
1858 analysis_window->present();
1862 Editor::build_track_selection_context_menu ()
1864 using namespace Menu_Helpers;
1865 MenuList& edit_items = track_selection_context_menu.items();
1866 edit_items.clear ();
1868 add_selection_context_items (edit_items);
1869 // edit_items.push_back (SeparatorElem());
1870 // add_dstream_context_items (edit_items);
1872 return &track_selection_context_menu;
1876 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1878 using namespace Menu_Helpers;
1880 /* OK, stick the region submenu at the top of the list, and then add
1884 RegionSelection rs = get_regions_from_selection_and_entered ();
1886 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1888 if (_popup_region_menu_item == 0) {
1889 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1890 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1891 _popup_region_menu_item->show ();
1893 _popup_region_menu_item->set_label (menu_item_name);
1896 /* No layering allowed in later is higher layering model */
1897 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1898 if (act && Config->get_layer_model() == LaterHigher) {
1899 act->set_sensitive (false);
1901 act->set_sensitive (true);
1904 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1906 edit_items.push_back (*_popup_region_menu_item);
1907 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1908 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1910 edit_items.push_back (SeparatorElem());
1913 /** Add context menu items relevant to selection ranges.
1914 * @param edit_items List to add the items to.
1917 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1919 using namespace Menu_Helpers;
1921 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1922 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1924 edit_items.push_back (SeparatorElem());
1925 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1927 edit_items.push_back (SeparatorElem());
1928 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1929 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1931 edit_items.push_back (SeparatorElem());
1933 edit_items.push_back (
1935 _("Move Range Start to Previous Region Boundary"),
1936 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1940 edit_items.push_back (
1942 _("Move Range Start to Next Region Boundary"),
1943 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1947 edit_items.push_back (
1949 _("Move Range End to Previous Region Boundary"),
1950 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1954 edit_items.push_back (
1956 _("Move Range End to Next Region Boundary"),
1957 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1961 edit_items.push_back (SeparatorElem());
1962 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1963 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1965 edit_items.push_back (SeparatorElem());
1966 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1970 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1971 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1973 edit_items.push_back (SeparatorElem());
1974 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1976 edit_items.push_back (SeparatorElem());
1977 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1978 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1982 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1983 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1984 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1985 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1986 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1987 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1993 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1995 using namespace Menu_Helpers;
1999 Menu *play_menu = manage (new Menu);
2000 MenuList& play_items = play_menu->items();
2001 play_menu->set_name ("ArdourContextMenu");
2003 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2004 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2005 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2006 play_items.push_back (SeparatorElem());
2007 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2009 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2013 Menu *select_menu = manage (new Menu);
2014 MenuList& select_items = select_menu->items();
2015 select_menu->set_name ("ArdourContextMenu");
2017 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2018 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2019 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2020 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2021 select_items.push_back (SeparatorElem());
2022 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2023 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2024 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2025 select_items.push_back (SeparatorElem());
2026 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2027 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2028 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2029 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2030 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2031 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2032 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2034 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2038 Menu *cutnpaste_menu = manage (new Menu);
2039 MenuList& cutnpaste_items = cutnpaste_menu->items();
2040 cutnpaste_menu->set_name ("ArdourContextMenu");
2042 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2043 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2044 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2046 cutnpaste_items.push_back (SeparatorElem());
2048 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2049 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2051 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2053 /* Adding new material */
2055 edit_items.push_back (SeparatorElem());
2056 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2057 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2061 Menu *nudge_menu = manage (new Menu());
2062 MenuList& nudge_items = nudge_menu->items();
2063 nudge_menu->set_name ("ArdourContextMenu");
2065 edit_items.push_back (SeparatorElem());
2066 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2067 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2068 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2069 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2071 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2075 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2077 using namespace Menu_Helpers;
2081 Menu *play_menu = manage (new Menu);
2082 MenuList& play_items = play_menu->items();
2083 play_menu->set_name ("ArdourContextMenu");
2085 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2086 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2087 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2091 Menu *select_menu = manage (new Menu);
2092 MenuList& select_items = select_menu->items();
2093 select_menu->set_name ("ArdourContextMenu");
2095 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2096 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2097 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2098 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2099 select_items.push_back (SeparatorElem());
2100 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2101 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2102 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2103 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2105 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2109 Menu *cutnpaste_menu = manage (new Menu);
2110 MenuList& cutnpaste_items = cutnpaste_menu->items();
2111 cutnpaste_menu->set_name ("ArdourContextMenu");
2113 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2114 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2115 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2117 Menu *nudge_menu = manage (new Menu());
2118 MenuList& nudge_items = nudge_menu->items();
2119 nudge_menu->set_name ("ArdourContextMenu");
2121 edit_items.push_back (SeparatorElem());
2122 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2123 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2124 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2125 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2127 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2131 Editor::grid_type() const
2137 Editor::grid_musical() const
2139 switch (_grid_type) {
2140 case GridTypeBeatDiv32:
2141 case GridTypeBeatDiv28:
2142 case GridTypeBeatDiv24:
2143 case GridTypeBeatDiv20:
2144 case GridTypeBeatDiv16:
2145 case GridTypeBeatDiv14:
2146 case GridTypeBeatDiv12:
2147 case GridTypeBeatDiv10:
2148 case GridTypeBeatDiv8:
2149 case GridTypeBeatDiv7:
2150 case GridTypeBeatDiv6:
2151 case GridTypeBeatDiv5:
2152 case GridTypeBeatDiv4:
2153 case GridTypeBeatDiv3:
2154 case GridTypeBeatDiv2:
2159 case GridTypeTimecode:
2160 case GridTypeMinSec:
2161 case GridTypeCDFrame:
2168 Editor::grid_nonmusical() const
2170 switch (_grid_type) {
2171 case GridTypeTimecode:
2172 case GridTypeMinSec:
2173 case GridTypeCDFrame:
2175 case GridTypeBeatDiv32:
2176 case GridTypeBeatDiv28:
2177 case GridTypeBeatDiv24:
2178 case GridTypeBeatDiv20:
2179 case GridTypeBeatDiv16:
2180 case GridTypeBeatDiv14:
2181 case GridTypeBeatDiv12:
2182 case GridTypeBeatDiv10:
2183 case GridTypeBeatDiv8:
2184 case GridTypeBeatDiv7:
2185 case GridTypeBeatDiv6:
2186 case GridTypeBeatDiv5:
2187 case GridTypeBeatDiv4:
2188 case GridTypeBeatDiv3:
2189 case GridTypeBeatDiv2:
2198 Editor::snap_mode() const
2204 Editor::show_rulers_for_grid ()
2206 /* show appropriate rulers for this grid setting. */
2207 if (grid_musical()) {
2208 ruler_tempo_action->set_active(true);
2209 ruler_meter_action->set_active(true);
2210 ruler_bbt_action->set_active(true);
2212 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2213 ruler_timecode_action->set_active(false);
2214 ruler_minsec_action->set_active(false);
2215 ruler_samples_action->set_active(false);
2217 } else if (_grid_type == GridTypeTimecode) {
2218 ruler_timecode_action->set_active(true);
2220 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2221 ruler_tempo_action->set_active(false);
2222 ruler_meter_action->set_active(false);
2223 ruler_bbt_action->set_active(false);
2224 ruler_minsec_action->set_active(false);
2225 ruler_samples_action->set_active(false);
2227 } else if (_grid_type == GridTypeMinSec) {
2228 ruler_minsec_action->set_active(true);
2230 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2231 ruler_tempo_action->set_active(false);
2232 ruler_meter_action->set_active(false);
2233 ruler_bbt_action->set_active(false);
2234 ruler_timecode_action->set_active(false);
2235 ruler_samples_action->set_active(false);
2237 } else if (_grid_type == GridTypeCDFrame) {
2238 ruler_cd_marker_action->set_active(true);
2239 ruler_minsec_action->set_active(true);
2241 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2242 ruler_tempo_action->set_active(false);
2243 ruler_meter_action->set_active(false);
2244 ruler_bbt_action->set_active(false);
2245 ruler_timecode_action->set_active(false);
2246 ruler_samples_action->set_active(false);
2252 Editor::set_grid_to (GridType gt)
2254 if (_grid_type == gt) { // already set
2258 unsigned int grid_ind = (unsigned int)gt;
2260 if (internal_editing() && UIConfiguration::instance().get_grid_follows_internal()) {
2261 internal_grid_type = gt;
2263 pre_internal_grid_type = gt;
2268 if (grid_ind > grid_type_strings.size() - 1) {
2270 _grid_type = (GridType)grid_ind;
2273 string str = grid_type_strings[grid_ind];
2275 if (str != grid_type_selector.get_text()) {
2276 grid_type_selector.set_text (str);
2279 if (UIConfiguration::instance().get_show_grids_ruler()) {
2280 show_rulers_for_grid ();
2285 if (grid_musical()) {
2286 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2287 update_tempo_based_rulers ();
2290 mark_region_boundary_cache_dirty ();
2292 redisplay_grid (false);
2294 SnapChanged (); /* EMIT SIGNAL */
2298 Editor::set_snap_mode (SnapMode mode)
2300 if (internal_editing()) {
2301 internal_snap_mode = mode;
2303 pre_internal_snap_mode = mode;
2308 if (_snap_mode == SnapOff) {
2309 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2311 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2318 Editor::set_edit_point_preference (EditPoint ep, bool force)
2320 bool changed = (_edit_point != ep);
2323 if (Profile->get_mixbus())
2324 if (ep == EditAtSelectedMarker)
2325 ep = EditAtPlayhead;
2327 string str = edit_point_strings[(int)ep];
2328 if (str != edit_point_selector.get_text ()) {
2329 edit_point_selector.set_text (str);
2332 update_all_enter_cursors();
2334 if (!force && !changed) {
2338 const char* action=NULL;
2340 switch (_edit_point) {
2341 case EditAtPlayhead:
2342 action = "edit-at-playhead";
2344 case EditAtSelectedMarker:
2345 action = "edit-at-marker";
2348 action = "edit-at-mouse";
2352 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Editor", action);
2353 tact->set_active (true);
2356 bool in_track_canvas;
2358 if (!mouse_sample (foo, in_track_canvas)) {
2359 in_track_canvas = false;
2362 reset_canvas_action_sensitivity (in_track_canvas);
2363 sensitize_the_right_region_actions (false);
2369 Editor::set_state (const XMLNode& node, int version)
2372 PBD::Unwinder<bool> nsi (no_save_instant, true);
2375 Tabbable::set_state (node, version);
2378 if (_session && node.get_property ("playhead", ph_pos)) {
2380 playhead_cursor->set_position (ph_pos);
2382 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2383 playhead_cursor->set_position (0);
2386 playhead_cursor->set_position (0);
2389 node.get_property ("mixer-width", editor_mixer_strip_width);
2391 node.get_property ("zoom-focus", zoom_focus);
2392 zoom_focus_selection_done (zoom_focus);
2395 if (node.get_property ("zoom", z)) {
2396 /* older versions of ardour used floating point samples_per_pixel */
2397 reset_zoom (llrintf (z));
2399 reset_zoom (samples_per_pixel);
2403 if (node.get_property ("visible-track-count", cnt)) {
2404 set_visible_track_count (cnt);
2408 if (!node.get_property ("grid-type", grid_type)) {
2409 grid_type = _grid_type;
2411 set_grid_to (grid_type);
2414 if (node.get_property ("snap-mode", sm)) {
2415 snap_mode_selection_done(sm);
2416 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2417 * snap_mode_selection_done() will only mark an already active item as active
2418 * which does not trigger set_text().
2422 set_snap_mode (_snap_mode);
2425 node.get_property ("internal-grid-type", internal_grid_type);
2426 node.get_property ("internal-snap-mode", internal_snap_mode);
2427 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2428 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2431 if (node.get_property ("mouse-mode", mm_str)) {
2432 MouseMode m = str2mousemode(mm_str);
2433 set_mouse_mode (m, true);
2435 set_mouse_mode (MouseObject, true);
2439 if (node.get_property ("left-frame", lf_pos)) {
2443 reset_x_origin (lf_pos);
2447 if (node.get_property ("y-origin", y_origin)) {
2448 reset_y_origin (y_origin);
2451 if (node.get_property ("join-object-range", yn)) {
2452 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2454 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2455 tact->set_active (!yn);
2456 tact->set_active (yn);
2458 set_mouse_mode(mouse_mode, true);
2462 if (node.get_property ("edit-point", ep)) {
2463 set_edit_point_preference (ep, true);
2465 set_edit_point_preference (_edit_point);
2468 if (node.get_property ("follow-playhead", yn)) {
2469 set_follow_playhead (yn);
2472 if (node.get_property ("stationary-playhead", yn)) {
2473 set_stationary_playhead (yn);
2476 RegionListSortType sort_type;
2477 if (node.get_property ("region-list-sort-type", sort_type)) {
2478 _regions->reset_sort_type (sort_type, true);
2481 if (node.get_property ("show-editor-mixer", yn)) {
2483 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2485 /* do it twice to force the change */
2487 tact->set_active (!yn);
2488 tact->set_active (yn);
2491 if (node.get_property ("show-editor-list", yn)) {
2493 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2495 /* do it twice to force the change */
2497 tact->set_active (!yn);
2498 tact->set_active (yn);
2502 if (node.get_property (X_("editor-list-page"), el_page)) {
2503 _the_notebook.set_current_page (el_page);
2506 if (node.get_property (X_("show-marker-lines"), yn)) {
2507 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2509 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2511 tact->set_active (!yn);
2512 tact->set_active (yn);
2515 XMLNodeList children = node.children ();
2516 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2517 selection->set_state (**i, Stateful::current_state_version);
2518 _regions->set_state (**i);
2519 _locations->set_state (**i);
2522 if (node.get_property ("maximised", yn)) {
2523 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalEditor"));
2524 bool fs = tact->get_active();
2526 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2530 samplepos_t nudge_clock_value;
2531 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2532 nudge_clock->set (nudge_clock_value);
2534 nudge_clock->set_mode (AudioClock::Timecode);
2535 nudge_clock->set (_session->sample_rate() * 5, true);
2540 * Not all properties may have been in XML, but
2541 * those that are linked to a private variable may need changing
2543 RefPtr<ToggleAction> tact;
2545 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
2546 yn = _follow_playhead;
2547 if (tact->get_active() != yn) {
2548 tact->set_active (yn);
2551 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
2552 yn = _stationary_playhead;
2553 if (tact->get_active() != yn) {
2554 tact->set_active (yn);
2562 Editor::get_state ()
2564 XMLNode* node = new XMLNode (X_("Editor"));
2566 node->set_property ("id", id().to_s ());
2568 node->add_child_nocopy (Tabbable::get_state());
2570 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2571 node->set_property("notebook-shrunk", _notebook_shrunk);
2572 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2574 maybe_add_mixer_strip_width (*node);
2576 node->set_property ("zoom-focus", zoom_focus);
2578 node->set_property ("zoom", samples_per_pixel);
2579 node->set_property ("grid-type", _grid_type);
2580 node->set_property ("snap-mode", _snap_mode);
2581 node->set_property ("internal-grid-type", internal_grid_type);
2582 node->set_property ("internal-snap-mode", internal_snap_mode);
2583 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2584 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2585 node->set_property ("edit-point", _edit_point);
2586 node->set_property ("visible-track-count", _visible_track_count);
2588 node->set_property ("playhead", playhead_cursor->current_sample ());
2589 node->set_property ("left-frame", _leftmost_sample);
2590 node->set_property ("y-origin", vertical_adjustment.get_value ());
2592 node->set_property ("maximised", _maximised);
2593 node->set_property ("follow-playhead", _follow_playhead);
2594 node->set_property ("stationary-playhead", _stationary_playhead);
2595 node->set_property ("region-list-sort-type", _regions->sort_type ());
2596 node->set_property ("mouse-mode", mouse_mode);
2597 node->set_property ("join-object-range", smart_mode_action->get_active ());
2599 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2600 node->set_property (X_("show-editor-mixer"), tact->get_active());
2602 tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2603 node->set_property (X_("show-editor-list"), tact->get_active());
2605 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2607 if (button_bindings) {
2608 XMLNode* bb = new XMLNode (X_("Buttons"));
2609 button_bindings->save (*bb);
2610 node->add_child_nocopy (*bb);
2613 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2615 node->add_child_nocopy (selection->get_state ());
2616 node->add_child_nocopy (_regions->get_state ());
2618 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2620 node->add_child_nocopy (_locations->get_state ());
2625 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2626 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2628 * @return pair: TimeAxisView that y is over, layer index.
2630 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2631 * in stacked or expanded region display mode, otherwise 0.
2633 std::pair<TimeAxisView *, double>
2634 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2636 if (!trackview_relative_offset) {
2637 y -= _trackview_group->canvas_origin().y;
2641 return std::make_pair ((TimeAxisView *) 0, 0);
2644 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2646 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2653 return std::make_pair ((TimeAxisView *) 0, 0);
2657 Editor::set_snapped_cursor_position (samplepos_t pos)
2659 if (_edit_point == EditAtMouse) {
2660 snapped_cursor->set_position(pos);
2665 /** Snap a position to the grid, if appropriate, taking into account current
2666 * grid settings and also the state of any snap modifier keys that may be pressed.
2667 * @param start Position to snap.
2668 * @param event Event to get current key modifier information from, or 0.
2671 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
2673 if (!_session || !event) {
2677 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2678 if (_snap_mode == SnapOff) {
2679 snap_to_internal (start, direction, pref);
2681 start.set (start.sample, 0);
2684 if (_snap_mode != SnapOff) {
2685 snap_to_internal (start, direction, pref);
2686 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2687 /* SnapOff, but we pressed the snap_delta modifier */
2688 snap_to_internal (start, direction, pref);
2690 start.set (start.sample, 0);
2696 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2698 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2699 start.set (start.sample, 0);
2703 snap_to_internal (start, direction, pref, ensure_snap);
2707 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2709 samplepos_t diff = abs (test - presnap);
2715 test = max_samplepos; // reset this so it doesn't get accidentally reused
2719 Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
2721 samplepos_t start = presnap.sample;
2722 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2723 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2725 TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
2728 case timecode_show_bits:
2729 case timecode_show_samples:
2730 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2731 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2732 /* start is already on a whole timecode frame, do nothing */
2733 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2734 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2736 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2740 case timecode_show_seconds:
2741 if (_session->config.get_timecode_offset_negative()) {
2742 start += _session->config.get_timecode_offset ();
2744 start -= _session->config.get_timecode_offset ();
2746 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2747 (start % one_timecode_second == 0)) {
2748 /* start is already on a whole second, do nothing */
2749 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2750 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2752 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2755 if (_session->config.get_timecode_offset_negative()) {
2756 start -= _session->config.get_timecode_offset ();
2758 start += _session->config.get_timecode_offset ();
2762 case timecode_show_minutes:
2763 case timecode_show_hours:
2764 case timecode_show_many_hours:
2765 if (_session->config.get_timecode_offset_negative()) {
2766 start += _session->config.get_timecode_offset ();
2768 start -= _session->config.get_timecode_offset ();
2770 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2771 (start % one_timecode_minute == 0)) {
2772 /* start is already on a whole minute, do nothing */
2773 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2774 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2776 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2778 if (_session->config.get_timecode_offset_negative()) {
2779 start -= _session->config.get_timecode_offset ();
2781 start += _session->config.get_timecode_offset ();
2785 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2788 MusicSample ret(start,0);
2793 Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
2795 MusicSample ret(presnap);
2797 const samplepos_t one_second = _session->sample_rate();
2798 const samplepos_t one_minute = one_second * 60;
2799 const samplepos_t one_hour = one_minute * 60;
2801 MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
2804 case minsec_show_msecs:
2805 case minsec_show_seconds: {
2806 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2807 presnap.sample % one_second == 0) {
2808 /* start is already on a whole second, do nothing */
2809 } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
2810 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
2812 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
2816 case minsec_show_minutes: {
2817 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2818 presnap.sample % one_minute == 0) {
2819 /* start is already on a whole minute, do nothing */
2820 } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2821 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
2823 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
2828 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2829 presnap.sample % one_hour == 0) {
2830 /* start is already on a whole hour, do nothing */
2831 } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
2832 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
2834 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
2843 Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
2845 if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
2846 return snap_to_minsec (presnap, direction, gpref);
2849 const samplepos_t one_second = _session->sample_rate();
2851 MusicSample ret(presnap);
2853 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2854 presnap.sample % (one_second/75) == 0) {
2855 /* start is already on a whole CD sample, do nothing */
2856 } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2857 ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2859 ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2866 Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
2868 MusicSample ret(presnap);
2870 if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
2873 switch (_grid_type) {
2874 case GridTypeBeatDiv3:
2875 case GridTypeBeatDiv6:
2876 case GridTypeBeatDiv12:
2877 case GridTypeBeatDiv24:
2880 case GridTypeBeatDiv5:
2881 case GridTypeBeatDiv10:
2882 case GridTypeBeatDiv20:
2885 case GridTypeBeatDiv7:
2886 case GridTypeBeatDiv14:
2887 case GridTypeBeatDiv28:
2894 BBTRulerScale scale = bbt_ruler_scale;
2901 ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
2903 case bbt_show_quarters:
2904 ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
2906 case bbt_show_eighths:
2907 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
2909 case bbt_show_sixteenths:
2910 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
2912 case bbt_show_thirtyseconds:
2913 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
2917 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
2924 Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
2926 MusicSample ret(presnap);
2928 if (grid_musical()) {
2929 ret = snap_to_bbt (presnap, direction, gpref);
2932 switch (_grid_type) {
2933 case GridTypeTimecode:
2934 ret = snap_to_timecode(presnap, direction, gpref);
2936 case GridTypeMinSec:
2937 ret = snap_to_minsec(presnap, direction, gpref);
2939 case GridTypeCDFrame:
2940 ret = snap_to_cd_frames(presnap, direction, gpref);
2950 Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
2956 _session->locations()->marks_either_side (presnap, before, after);
2958 if (before == max_samplepos && after == max_samplepos) {
2959 /* No marks to snap to, so just don't snap */
2961 } else if (before == max_samplepos) {
2963 } else if (after == max_samplepos) {
2966 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2968 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2970 } else if (direction == 0) {
2971 if ((presnap - before) < (after - presnap)) {
2983 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2985 const samplepos_t presnap = start.sample;
2987 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2988 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2989 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2991 /* check snap-to-marker */
2992 if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
2993 test = snap_to_marker (presnap, direction);
2994 check_best_snap(presnap, test, dist, best);
2997 /* check snap-to-region-{start/end/sync} */
2999 (pref == SnapToAny_Visual) &&
3000 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
3002 if (!region_boundary_cache.empty()) {
3004 vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
3005 vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
3006 if (next != region_boundary_cache.begin ()) {
3011 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
3013 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
3015 else if (direction == 0) {
3016 if ((presnap - *prev) < (*next - presnap)) {
3025 check_best_snap(presnap, test, dist, best);
3029 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
3030 MusicSample pre(presnap, 0);
3031 MusicSample post = snap_to_grid (pre, direction, pref);
3032 check_best_snap(presnap, post.sample, dist, best);
3035 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
3036 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
3037 * ToDo: Perhaps this should only occur if EditPointMouse?
3039 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
3041 start.set (best, 0);
3043 } else if (presnap > best) {
3044 if (presnap > (best+ snap_threshold_s)) {
3047 } else if (presnap < best) {
3048 if (presnap < (best - snap_threshold_s)) {
3053 start.set (best, 0);
3058 Editor::setup_toolbar ()
3060 HBox* mode_box = manage(new HBox);
3061 mode_box->set_border_width (2);
3062 mode_box->set_spacing(2);
3064 HBox* mouse_mode_box = manage (new HBox);
3065 HBox* mouse_mode_hbox = manage (new HBox);
3066 VBox* mouse_mode_vbox = manage (new VBox);
3067 Alignment* mouse_mode_align = manage (new Alignment);
3069 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3070 mouse_mode_size_group->add_widget (smart_mode_button);
3071 mouse_mode_size_group->add_widget (mouse_move_button);
3072 mouse_mode_size_group->add_widget (mouse_cut_button);
3073 mouse_mode_size_group->add_widget (mouse_select_button);
3074 mouse_mode_size_group->add_widget (mouse_timefx_button);
3075 mouse_mode_size_group->add_widget (mouse_audition_button);
3076 mouse_mode_size_group->add_widget (mouse_draw_button);
3077 mouse_mode_size_group->add_widget (mouse_content_button);
3079 if (!Profile->get_mixbus()) {
3080 mouse_mode_size_group->add_widget (zoom_in_button);
3081 mouse_mode_size_group->add_widget (zoom_out_button);
3082 mouse_mode_size_group->add_widget (zoom_out_full_button);
3083 mouse_mode_size_group->add_widget (zoom_focus_selector);
3084 mouse_mode_size_group->add_widget (tav_shrink_button);
3085 mouse_mode_size_group->add_widget (tav_expand_button);
3087 mouse_mode_size_group->add_widget (zoom_preset_selector);
3088 mouse_mode_size_group->add_widget (visible_tracks_selector);
3091 mouse_mode_size_group->add_widget (grid_type_selector);
3092 mouse_mode_size_group->add_widget (snap_mode_button);
3094 mouse_mode_size_group->add_widget (edit_point_selector);
3095 mouse_mode_size_group->add_widget (edit_mode_selector);
3097 mouse_mode_size_group->add_widget (*nudge_clock);
3098 mouse_mode_size_group->add_widget (nudge_forward_button);
3099 mouse_mode_size_group->add_widget (nudge_backward_button);
3101 mouse_mode_hbox->set_spacing (2);
3103 if (!ARDOUR::Profile->get_trx()) {
3104 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3107 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3108 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3110 if (!ARDOUR::Profile->get_mixbus()) {
3111 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3112 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3115 if (!ARDOUR::Profile->get_trx()) {
3116 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3117 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3118 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3121 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3123 mouse_mode_align->add (*mouse_mode_vbox);
3124 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3126 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3128 edit_mode_selector.set_name ("mouse mode button");
3130 if (!ARDOUR::Profile->get_trx()) {
3131 mode_box->pack_start (edit_mode_selector, false, false);
3132 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3133 mode_box->pack_start (edit_point_selector, false, false);
3134 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3137 mode_box->pack_start (*mouse_mode_box, false, false);
3141 _zoom_box.set_spacing (2);
3142 _zoom_box.set_border_width (2);
3146 zoom_preset_selector.set_name ("zoom button");
3147 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3149 zoom_in_button.set_name ("zoom button");
3150 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3151 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3152 zoom_in_button.set_related_action (act);
3154 zoom_out_button.set_name ("zoom button");
3155 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3156 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3157 zoom_out_button.set_related_action (act);
3159 zoom_out_full_button.set_name ("zoom button");
3160 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3161 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3162 zoom_out_full_button.set_related_action (act);
3164 zoom_focus_selector.set_name ("zoom button");
3166 if (ARDOUR::Profile->get_mixbus()) {
3167 _zoom_box.pack_start (zoom_preset_selector, false, false);
3168 } else if (ARDOUR::Profile->get_trx()) {
3169 mode_box->pack_start (zoom_out_button, false, false);
3170 mode_box->pack_start (zoom_in_button, false, false);
3172 _zoom_box.pack_start (zoom_out_button, false, false);
3173 _zoom_box.pack_start (zoom_in_button, false, false);
3174 _zoom_box.pack_start (zoom_out_full_button, false, false);
3175 _zoom_box.pack_start (zoom_focus_selector, false, false);
3178 /* Track zoom buttons */
3179 _track_box.set_spacing (2);
3180 _track_box.set_border_width (2);
3182 visible_tracks_selector.set_name ("zoom button");
3183 if (Profile->get_mixbus()) {
3184 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3186 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3189 tav_expand_button.set_name ("zoom button");
3190 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3191 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3192 tav_expand_button.set_related_action (act);
3194 tav_shrink_button.set_name ("zoom button");
3195 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3196 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3197 tav_shrink_button.set_related_action (act);
3199 if (ARDOUR::Profile->get_mixbus()) {
3200 _track_box.pack_start (visible_tracks_selector);
3201 } else if (ARDOUR::Profile->get_trx()) {
3202 _track_box.pack_start (tav_shrink_button);
3203 _track_box.pack_start (tav_expand_button);
3205 _track_box.pack_start (visible_tracks_selector);
3206 _track_box.pack_start (tav_shrink_button);
3207 _track_box.pack_start (tav_expand_button);
3210 snap_box.set_spacing (2);
3211 snap_box.set_border_width (2);
3213 grid_type_selector.set_name ("mouse mode button");
3215 snap_mode_button.set_name ("mouse mode button");
3217 edit_point_selector.set_name ("mouse mode button");
3219 snap_box.pack_start (snap_mode_button, false, false);
3220 snap_box.pack_start (grid_type_selector, false, false);
3224 HBox *nudge_box = manage (new HBox);
3225 nudge_box->set_spacing (2);
3226 nudge_box->set_border_width (2);
3228 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3229 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3231 nudge_box->pack_start (nudge_backward_button, false, false);
3232 nudge_box->pack_start (nudge_forward_button, false, false);
3233 nudge_box->pack_start (*nudge_clock, false, false);
3236 /* Pack everything in... */
3238 toolbar_hbox.set_spacing (2);
3239 toolbar_hbox.set_border_width (2);
3241 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3242 tool_shadow->set_size_request (4, -1);
3243 tool_shadow->show();
3245 ebox_hpacker.pack_start (*tool_shadow, false, false);
3246 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3248 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3249 spacer->set_name("EditorWindow");
3250 spacer->set_size_request(-1,4);
3253 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3254 ebox_vpacker.pack_start(*spacer, false, false);
3255 ebox_vpacker.show();
3257 toolbar_hbox.pack_start (*mode_box, false, false);
3259 if (!ARDOUR::Profile->get_trx()) {
3261 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3263 toolbar_hbox.pack_start (snap_box, false, false);
3265 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3267 toolbar_hbox.pack_start (*nudge_box, false, false);
3269 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3271 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3273 toolbar_hbox.pack_end (_track_box, false, false);
3277 toolbar_hbox.show_all ();
3281 Editor::build_edit_point_menu ()
3283 using namespace Menu_Helpers;
3285 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3286 if(!Profile->get_mixbus())
3287 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3288 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3290 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3294 Editor::build_edit_mode_menu ()
3296 using namespace Menu_Helpers;
3298 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3299 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3300 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3301 /* Note: Splice was removed */
3303 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3307 Editor::build_grid_type_menu ()
3309 using namespace Menu_Helpers;
3311 /* main grid: bars, quarter-notes, etc */
3312 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3313 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3314 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3315 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3316 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3317 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3318 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3319 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3322 grid_type_selector.AddMenuElem(SeparatorElem());
3323 Gtk::Menu *_triplet_menu = manage (new Menu);
3324 MenuList& triplet_items (_triplet_menu->items());
3326 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3327 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3328 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3329 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3331 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3333 /* quintuplet grid */
3334 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3335 MenuList& quintuplet_items (_quintuplet_menu->items());
3337 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3338 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3339 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3341 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3343 /* septuplet grid */
3344 Gtk::Menu *_septuplet_menu = manage (new Menu);
3345 MenuList& septuplet_items (_septuplet_menu->items());
3347 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3348 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3349 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3351 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3353 grid_type_selector.AddMenuElem(SeparatorElem());
3354 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3355 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3356 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3360 Editor::setup_tooltips ()
3362 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3363 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3364 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3365 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3366 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3367 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3368 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3369 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3370 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3371 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3372 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3373 set_tooltip (zoom_in_button, _("Zoom In"));
3374 set_tooltip (zoom_out_button, _("Zoom Out"));
3375 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3376 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3377 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3378 set_tooltip (tav_expand_button, _("Expand Tracks"));
3379 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3380 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3381 set_tooltip (grid_type_selector, _("Grid Mode"));
3382 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3383 set_tooltip (edit_point_selector, _("Edit Point"));
3384 set_tooltip (edit_mode_selector, _("Edit Mode"));
3385 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3389 Editor::convert_drop_to_paths (
3390 vector<string>& paths,
3391 const RefPtr<Gdk::DragContext>& /*context*/,
3394 const SelectionData& data,
3398 if (_session == 0) {
3402 vector<string> uris = data.get_uris();
3406 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3407 are actually URI lists. So do it by hand.
3410 if (data.get_target() != "text/plain") {
3414 /* Parse the "uri-list" format that Nautilus provides,
3415 where each pathname is delimited by \r\n.
3417 THERE MAY BE NO NULL TERMINATING CHAR!!!
3420 string txt = data.get_text();
3424 p = (char *) malloc (txt.length() + 1);
3425 txt.copy (p, txt.length(), 0);
3426 p[txt.length()] = '\0';
3432 while (g_ascii_isspace (*p))
3436 while (*q && (*q != '\n') && (*q != '\r')) {
3443 while (q > p && g_ascii_isspace (*q))
3448 uris.push_back (string (p, q - p + 1));
3452 p = strchr (p, '\n');
3464 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3465 if ((*i).substr (0,7) == "file://") {
3466 paths.push_back (Glib::filename_from_uri (*i));
3474 Editor::new_tempo_section ()
3479 Editor::map_transport_state ()
3481 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3483 if (_session && _session->transport_stopped()) {
3484 have_pending_keyboard_selection = false;
3487 update_loop_range_view ();
3491 Editor::transport_looped ()
3493 /* reset Playhead position interpolation.
3494 * see Editor::super_rapid_screen_update
3496 _last_update_time = 0;
3502 Editor::begin_selection_op_history ()
3504 selection_op_cmd_depth = 0;
3505 selection_op_history_it = 0;
3507 while(!selection_op_history.empty()) {
3508 delete selection_op_history.front();
3509 selection_op_history.pop_front();
3512 selection_undo_action->set_sensitive (false);
3513 selection_redo_action->set_sensitive (false);
3514 selection_op_history.push_front (&_selection_memento->get_state ());
3518 Editor::begin_reversible_selection_op (string name)
3521 //cerr << name << endl;
3522 /* begin/commit pairs can be nested */
3523 selection_op_cmd_depth++;
3528 Editor::commit_reversible_selection_op ()
3531 if (selection_op_cmd_depth == 1) {
3533 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3534 /* The user has undone some selection ops and then made a new one,
3535 * making anything earlier in the list invalid.
3538 list<XMLNode *>::iterator it = selection_op_history.begin();
3539 list<XMLNode *>::iterator e_it = it;
3540 advance (e_it, selection_op_history_it);
3542 for (; it != e_it; ++it) {
3545 selection_op_history.erase (selection_op_history.begin(), e_it);
3548 selection_op_history.push_front (&_selection_memento->get_state ());
3549 selection_op_history_it = 0;
3551 selection_undo_action->set_sensitive (true);
3552 selection_redo_action->set_sensitive (false);
3555 if (selection_op_cmd_depth > 0) {
3556 selection_op_cmd_depth--;
3562 Editor::undo_selection_op ()
3565 selection_op_history_it++;
3567 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3568 if (n == selection_op_history_it) {
3569 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3570 selection_redo_action->set_sensitive (true);
3574 /* is there an earlier entry? */
3575 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3576 selection_undo_action->set_sensitive (false);
3582 Editor::redo_selection_op ()
3585 if (selection_op_history_it > 0) {
3586 selection_op_history_it--;
3589 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3590 if (n == selection_op_history_it) {
3591 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3592 selection_undo_action->set_sensitive (true);
3597 if (selection_op_history_it == 0) {
3598 selection_redo_action->set_sensitive (false);
3604 Editor::begin_reversible_command (string name)
3607 before.push_back (&_selection_memento->get_state ());
3608 _session->begin_reversible_command (name);
3613 Editor::begin_reversible_command (GQuark q)
3616 before.push_back (&_selection_memento->get_state ());
3617 _session->begin_reversible_command (q);
3622 Editor::abort_reversible_command ()
3625 while(!before.empty()) {
3626 delete before.front();
3629 _session->abort_reversible_command ();
3634 Editor::commit_reversible_command ()
3637 if (before.size() == 1) {
3638 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3639 redo_action->set_sensitive(false);
3640 undo_action->set_sensitive(true);
3641 begin_selection_op_history ();
3644 if (before.empty()) {
3645 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3650 _session->commit_reversible_command ();
3655 Editor::history_changed ()
3659 if (undo_action && _session) {
3660 if (_session->undo_depth() == 0) {
3661 label = S_("Command|Undo");
3663 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3665 undo_action->property_label() = label;
3668 if (redo_action && _session) {
3669 if (_session->redo_depth() == 0) {
3671 redo_action->set_sensitive (false);
3673 label = string_compose(_("Redo (%1)"), _session->next_redo());
3674 redo_action->set_sensitive (true);
3676 redo_action->property_label() = label;
3681 Editor::duplicate_range (bool with_dialog)
3685 RegionSelection rs = get_regions_from_selection_and_entered ();
3687 if (selection->time.length() == 0 && rs.empty()) {
3693 ArdourDialog win (_("Duplicate"));
3694 Label label (_("Number of duplications:"));
3695 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3696 SpinButton spinner (adjustment, 0.0, 1);
3699 win.get_vbox()->set_spacing (12);
3700 win.get_vbox()->pack_start (hbox);
3701 hbox.set_border_width (6);
3702 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3704 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3705 place, visually. so do this by hand.
3708 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3709 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3710 spinner.grab_focus();
3716 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3717 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3718 win.set_default_response (RESPONSE_ACCEPT);
3720 spinner.grab_focus ();
3722 switch (win.run ()) {
3723 case RESPONSE_ACCEPT:
3729 times = adjustment.get_value();
3732 if ((current_mouse_mode() == MouseRange)) {
3733 if (selection->time.length()) {
3734 duplicate_selection (times);
3736 } else if (get_smart_mode()) {
3737 if (selection->time.length()) {
3738 duplicate_selection (times);
3740 duplicate_some_regions (rs, times);
3742 duplicate_some_regions (rs, times);
3747 Editor::set_edit_mode (EditMode m)
3749 Config->set_edit_mode (m);
3753 Editor::cycle_edit_mode ()
3755 switch (Config->get_edit_mode()) {
3757 Config->set_edit_mode (Ripple);
3761 Config->set_edit_mode (Lock);
3764 Config->set_edit_mode (Slide);
3770 Editor::edit_mode_selection_done (EditMode m)
3772 Config->set_edit_mode (m);
3776 Editor::grid_type_selection_done (GridType gridtype)
3778 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3780 ract->set_active ();
3785 Editor::snap_mode_selection_done (SnapMode mode)
3787 RefPtr<RadioAction> ract = snap_mode_action (mode);
3790 ract->set_active (true);
3795 Editor::cycle_edit_point (bool with_marker)
3797 if(Profile->get_mixbus())
3798 with_marker = false;
3800 switch (_edit_point) {
3802 set_edit_point_preference (EditAtPlayhead);
3804 case EditAtPlayhead:
3806 set_edit_point_preference (EditAtSelectedMarker);
3808 set_edit_point_preference (EditAtMouse);
3811 case EditAtSelectedMarker:
3812 set_edit_point_preference (EditAtMouse);
3818 Editor::edit_point_selection_done (EditPoint ep)
3820 set_edit_point_preference (ep);
3824 Editor::build_zoom_focus_menu ()
3826 using namespace Menu_Helpers;
3828 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3829 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3830 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3831 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3832 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3833 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3835 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3839 Editor::zoom_focus_selection_done (ZoomFocus f)
3841 RefPtr<RadioAction> ract = zoom_focus_action (f);
3843 ract->set_active ();
3848 Editor::build_track_count_menu ()
3850 using namespace Menu_Helpers;
3852 if (!Profile->get_mixbus()) {
3853 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3854 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3855 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3856 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3857 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3858 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3859 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3860 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3861 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3862 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3863 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3864 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3865 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3867 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3868 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3869 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3870 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3871 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3872 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3873 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3874 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3875 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3876 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3878 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3879 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3880 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3881 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3882 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3883 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3884 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3885 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3886 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3887 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3888 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3889 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3894 Editor::set_zoom_preset (int64_t ms)
3897 temporal_zoom_session();
3901 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3902 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3906 Editor::set_visible_track_count (int32_t n)
3908 _visible_track_count = n;
3910 /* if the canvas hasn't really been allocated any size yet, just
3911 record the desired number of visible tracks and return. when canvas
3912 allocation happens, we will get called again and then we can do the
3916 if (_visible_canvas_height <= 1) {
3922 DisplaySuspender ds;
3924 if (_visible_track_count > 0) {
3925 h = trackviews_height() / _visible_track_count;
3926 std::ostringstream s;
3927 s << _visible_track_count;
3929 } else if (_visible_track_count == 0) {
3931 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3932 if ((*i)->marked_for_display()) {
3934 TimeAxisView::Children cl ((*i)->get_child_list ());
3935 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3936 if ((*j)->marked_for_display()) {
3943 visible_tracks_selector.set_text (X_("*"));
3946 h = trackviews_height() / n;
3949 /* negative value means that the visible track count has
3950 been overridden by explicit track height changes.
3952 visible_tracks_selector.set_text (X_("*"));
3956 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3957 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3960 if (str != visible_tracks_selector.get_text()) {
3961 visible_tracks_selector.set_text (str);
3966 Editor::override_visible_track_count ()
3968 _visible_track_count = -1;
3969 visible_tracks_selector.set_text (_("*"));
3973 Editor::edit_controls_button_release (GdkEventButton* ev)
3975 if (Keyboard::is_context_menu_event (ev)) {
3976 ARDOUR_UI::instance()->add_route ();
3977 } else if (ev->button == 1) {
3978 selection->clear_tracks ();
3985 Editor::mouse_select_button_release (GdkEventButton* ev)
3987 /* this handles just right-clicks */
3989 if (ev->button != 3) {
3997 Editor::set_zoom_focus (ZoomFocus f)
3999 string str = zoom_focus_strings[(int)f];
4001 if (str != zoom_focus_selector.get_text()) {
4002 zoom_focus_selector.set_text (str);
4005 if (zoom_focus != f) {
4012 Editor::cycle_zoom_focus ()
4014 switch (zoom_focus) {
4016 set_zoom_focus (ZoomFocusRight);
4018 case ZoomFocusRight:
4019 set_zoom_focus (ZoomFocusCenter);
4021 case ZoomFocusCenter:
4022 set_zoom_focus (ZoomFocusPlayhead);
4024 case ZoomFocusPlayhead:
4025 set_zoom_focus (ZoomFocusMouse);
4027 case ZoomFocusMouse:
4028 set_zoom_focus (ZoomFocusEdit);
4031 set_zoom_focus (ZoomFocusLeft);
4037 Editor::update_grid ()
4039 if (grid_musical()) {
4040 std::vector<TempoMap::BBTPoint> grid;
4041 if (bbt_ruler_scale != bbt_show_many) {
4042 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
4044 maybe_draw_grid_lines ();
4045 } else if (grid_nonmusical()) {
4046 maybe_draw_grid_lines ();
4053 Editor::toggle_follow_playhead ()
4055 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
4056 set_follow_playhead (tact->get_active());
4059 /** @param yn true to follow playhead, otherwise false.
4060 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4063 Editor::set_follow_playhead (bool yn, bool catch_up)
4065 if (_follow_playhead != yn) {
4066 if ((_follow_playhead = yn) == true && catch_up) {
4068 reset_x_origin_to_follow_playhead ();
4075 Editor::toggle_stationary_playhead ()
4077 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
4078 set_stationary_playhead (tact->get_active());
4082 Editor::set_stationary_playhead (bool yn)
4084 if (_stationary_playhead != yn) {
4085 if ((_stationary_playhead = yn) == true) {
4086 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
4087 // update_current_screen ();
4094 Editor::playlist_selector () const
4096 return *_playlist_selector;
4100 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4102 if (paste_count == 0) {
4103 /* don't bother calculating an offset that will be zero anyway */
4107 /* calculate basic unsnapped multi-paste offset */
4108 samplecnt_t offset = paste_count * duration;
4110 /* snap offset so pos + offset is aligned to the grid */
4111 MusicSample offset_pos (pos + offset, 0);
4112 snap_to(offset_pos, RoundUpMaybe);
4113 offset = offset_pos.sample - pos;
4119 Editor::get_grid_beat_divisions(samplepos_t position)
4121 switch (_grid_type) {
4122 case GridTypeBeatDiv32: return 32;
4123 case GridTypeBeatDiv28: return 28;
4124 case GridTypeBeatDiv24: return 24;
4125 case GridTypeBeatDiv20: return 20;
4126 case GridTypeBeatDiv16: return 16;
4127 case GridTypeBeatDiv14: return 14;
4128 case GridTypeBeatDiv12: return 12;
4129 case GridTypeBeatDiv10: return 10;
4130 case GridTypeBeatDiv8: return 8;
4131 case GridTypeBeatDiv7: return 7;
4132 case GridTypeBeatDiv6: return 6;
4133 case GridTypeBeatDiv5: return 5;
4134 case GridTypeBeatDiv4: return 4;
4135 case GridTypeBeatDiv3: return 3;
4136 case GridTypeBeatDiv2: return 2;
4137 case GridTypeBeat: return 1;
4138 case GridTypeBar: return 1;
4140 case GridTypeNone: return 0;
4141 case GridTypeTimecode: return 0;
4142 case GridTypeMinSec: return 0;
4143 case GridTypeCDFrame: return 0;
4149 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4150 if the grid is non-musical, returns 0.
4151 if the grid is snapped to bars, returns -1.
4152 @param event_state the current keyboard modifier mask.
4155 Editor::get_grid_music_divisions (uint32_t event_state)
4157 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4161 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4165 switch (_grid_type) {
4166 case GridTypeBeatDiv32: return 32;
4167 case GridTypeBeatDiv28: return 28;
4168 case GridTypeBeatDiv24: return 24;
4169 case GridTypeBeatDiv20: return 20;
4170 case GridTypeBeatDiv16: return 16;
4171 case GridTypeBeatDiv14: return 14;
4172 case GridTypeBeatDiv12: return 12;
4173 case GridTypeBeatDiv10: return 10;
4174 case GridTypeBeatDiv8: return 8;
4175 case GridTypeBeatDiv7: return 7;
4176 case GridTypeBeatDiv6: return 6;
4177 case GridTypeBeatDiv5: return 5;
4178 case GridTypeBeatDiv4: return 4;
4179 case GridTypeBeatDiv3: return 3;
4180 case GridTypeBeatDiv2: return 2;
4181 case GridTypeBeat: return 1;
4182 case GridTypeBar : return -1;
4184 case GridTypeNone: return 0;
4185 case GridTypeTimecode: return 0;
4186 case GridTypeMinSec: return 0;
4187 case GridTypeCDFrame: return 0;
4193 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4197 const unsigned divisions = get_grid_beat_divisions(position);
4199 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4202 switch (_grid_type) {
4204 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4207 const Meter& m = _session->tempo_map().meter_at_sample (position);
4208 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4216 return Temporal::Beats();
4220 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4224 ret = nudge_clock->current_duration (pos);
4225 next = ret + 1; /* XXXX fix me */
4231 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4233 ArdourDialog dialog (_("Playlist Deletion"));
4234 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4235 "If it is kept, its audio files will not be cleaned.\n"
4236 "If it is deleted, audio files used by it alone will be cleaned."),
4239 dialog.set_position (WIN_POS_CENTER);
4240 dialog.get_vbox()->pack_start (label);
4244 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4245 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4246 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4247 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4248 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4250 /* by default gtk uses the left most button */
4251 keep->grab_focus ();
4253 switch (dialog.run ()) {
4255 /* keep this and all remaining ones */
4260 /* delete this and all others */
4264 case RESPONSE_ACCEPT:
4265 /* delete the playlist */
4269 case RESPONSE_REJECT:
4270 /* keep the playlist */
4282 Editor::audio_region_selection_covers (samplepos_t where)
4284 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4285 if ((*a)->region()->covers (where)) {
4294 Editor::prepare_for_cleanup ()
4296 cut_buffer->clear_regions ();
4297 cut_buffer->clear_playlists ();
4299 selection->clear_regions ();
4300 selection->clear_playlists ();
4302 _regions->suspend_redisplay ();
4306 Editor::finish_cleanup ()
4308 _regions->resume_redisplay ();
4312 Editor::transport_loop_location()
4315 return _session->locations()->auto_loop_location();
4322 Editor::transport_punch_location()
4325 return _session->locations()->auto_punch_location();
4332 Editor::control_layout_scroll (GdkEventScroll* ev)
4334 /* Just forward to the normal canvas scroll method. The coordinate
4335 systems are different but since the canvas is always larger than the
4336 track headers, and aligned with the trackview area, this will work.
4338 In the not too distant future this layout is going away anyway and
4339 headers will be on the canvas.
4341 return canvas_scroll_event (ev, false);
4345 Editor::session_state_saved (string)
4348 _snapshots->redisplay ();
4352 Editor::maximise_editing_space ()
4358 Gtk::Window* toplevel = current_toplevel();
4361 toplevel->fullscreen ();
4367 Editor::restore_editing_space ()
4373 Gtk::Window* toplevel = current_toplevel();
4376 toplevel->unfullscreen();
4382 * Make new playlists for a given track and also any others that belong
4383 * to the same active route group with the `select' property.
4388 Editor::new_playlists (TimeAxisView* v)
4390 begin_reversible_command (_("new playlists"));
4391 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4392 _session->playlists->get (playlists);
4393 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4394 commit_reversible_command ();
4398 * Use a copy of the current playlist for a given track and also any others that belong
4399 * to the same active route group with the `select' property.
4404 Editor::copy_playlists (TimeAxisView* v)
4406 begin_reversible_command (_("copy playlists"));
4407 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4408 _session->playlists->get (playlists);
4409 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4410 commit_reversible_command ();
4413 /** Clear the current playlist for a given track and also any others that belong
4414 * to the same active route group with the `select' property.
4419 Editor::clear_playlists (TimeAxisView* v)
4421 begin_reversible_command (_("clear playlists"));
4422 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4423 _session->playlists->get (playlists);
4424 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4425 commit_reversible_command ();
4429 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4431 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4435 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4437 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4441 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4443 atv.clear_playlist ();
4447 Editor::get_y_origin () const
4449 return vertical_adjustment.get_value ();
4452 /** Queue up a change to the viewport x origin.
4453 * @param sample New x origin.
4456 Editor::reset_x_origin (samplepos_t sample)
4458 pending_visual_change.add (VisualChange::TimeOrigin);
4459 pending_visual_change.time_origin = sample;
4460 ensure_visual_change_idle_handler ();
4464 Editor::reset_y_origin (double y)
4466 pending_visual_change.add (VisualChange::YOrigin);
4467 pending_visual_change.y_origin = y;
4468 ensure_visual_change_idle_handler ();
4472 Editor::reset_zoom (samplecnt_t spp)
4474 if (spp == samples_per_pixel) {
4478 pending_visual_change.add (VisualChange::ZoomLevel);
4479 pending_visual_change.samples_per_pixel = spp;
4480 ensure_visual_change_idle_handler ();
4484 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4486 reset_x_origin (sample);
4489 if (!no_save_visual) {
4490 undo_visual_stack.push_back (current_visual_state(false));
4494 Editor::VisualState::VisualState (bool with_tracks)
4495 : gui_state (with_tracks ? new GUIObjectState : 0)
4499 Editor::VisualState::~VisualState ()
4504 Editor::VisualState*
4505 Editor::current_visual_state (bool with_tracks)
4507 VisualState* vs = new VisualState (with_tracks);
4508 vs->y_position = vertical_adjustment.get_value();
4509 vs->samples_per_pixel = samples_per_pixel;
4510 vs->_leftmost_sample = _leftmost_sample;
4511 vs->zoom_focus = zoom_focus;
4514 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4521 Editor::undo_visual_state ()
4523 if (undo_visual_stack.empty()) {
4527 VisualState* vs = undo_visual_stack.back();
4528 undo_visual_stack.pop_back();
4531 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4534 use_visual_state (*vs);
4539 Editor::redo_visual_state ()
4541 if (redo_visual_stack.empty()) {
4545 VisualState* vs = redo_visual_stack.back();
4546 redo_visual_stack.pop_back();
4548 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4549 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4552 use_visual_state (*vs);
4557 Editor::swap_visual_state ()
4559 if (undo_visual_stack.empty()) {
4560 redo_visual_state ();
4562 undo_visual_state ();
4567 Editor::use_visual_state (VisualState& vs)
4569 PBD::Unwinder<bool> nsv (no_save_visual, true);
4570 DisplaySuspender ds;
4572 vertical_adjustment.set_value (vs.y_position);
4574 set_zoom_focus (vs.zoom_focus);
4575 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4578 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4580 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4581 (*i)->clear_property_cache();
4582 (*i)->reset_visual_state ();
4586 _routes->update_visibility ();
4589 /** This is the core function that controls the zoom level of the canvas. It is called
4590 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4591 * @param spp new number of samples per pixel
4594 Editor::set_samples_per_pixel (samplecnt_t spp)
4600 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4601 const samplecnt_t lots_of_pixels = 4000;
4603 /* if the zoom level is greater than what you'd get trying to display 3
4604 * days of audio on a really big screen, then it's too big.
4607 if (spp * lots_of_pixels > three_days) {
4611 samples_per_pixel = spp;
4615 Editor::on_samples_per_pixel_changed ()
4617 bool const showing_time_selection = selection->time.length() > 0;
4619 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4620 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4621 (*i)->reshow_selection (selection->time);
4625 ZoomChanged (); /* EMIT_SIGNAL */
4627 ArdourCanvas::GtkCanvasViewport* c;
4629 c = get_track_canvas();
4631 c->canvas()->zoomed ();
4634 if (playhead_cursor) {
4635 playhead_cursor->set_position (playhead_cursor->current_sample ());
4638 refresh_location_display();
4639 _summary->set_overlays_dirty ();
4641 update_marker_labels ();
4647 Editor::playhead_cursor_sample () const
4649 return playhead_cursor->current_sample();
4653 Editor::queue_visual_videotimeline_update ()
4655 pending_visual_change.add (VisualChange::VideoTimeline);
4656 ensure_visual_change_idle_handler ();
4660 Editor::ensure_visual_change_idle_handler ()
4662 if (pending_visual_change.idle_handler_id < 0) {
4663 /* see comment in add_to_idle_resize above. */
4664 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4665 pending_visual_change.being_handled = false;
4670 Editor::_idle_visual_changer (void* arg)
4672 return static_cast<Editor*>(arg)->idle_visual_changer ();
4676 Editor::pre_render ()
4678 visual_change_queued = false;
4680 if (pending_visual_change.pending != 0) {
4681 ensure_visual_change_idle_handler();
4686 Editor::idle_visual_changer ()
4688 pending_visual_change.idle_handler_id = -1;
4690 if (pending_visual_change.pending == 0) {
4694 /* set_horizontal_position() below (and maybe other calls) call
4695 gtk_main_iteration(), so it's possible that a signal will be handled
4696 half-way through this method. If this signal wants an
4697 idle_visual_changer we must schedule another one after this one, so
4698 mark the idle_handler_id as -1 here to allow that. Also make a note
4699 that we are doing the visual change, so that changes in response to
4700 super-rapid-screen-update can be dropped if we are still processing
4704 if (visual_change_queued) {
4708 pending_visual_change.being_handled = true;
4710 VisualChange vc = pending_visual_change;
4712 pending_visual_change.pending = (VisualChange::Type) 0;
4714 visual_changer (vc);
4716 pending_visual_change.being_handled = false;
4718 visual_change_queued = true;
4720 return 0; /* this is always a one-shot call */
4724 Editor::visual_changer (const VisualChange& vc)
4727 * Changed first so the correct horizontal canvas position is calculated in
4728 * Editor::set_horizontal_position
4730 if (vc.pending & VisualChange::ZoomLevel) {
4731 set_samples_per_pixel (vc.samples_per_pixel);
4734 if (vc.pending & VisualChange::TimeOrigin) {
4735 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4736 set_horizontal_position (new_time_origin);
4739 if (vc.pending & VisualChange::YOrigin) {
4740 vertical_adjustment.set_value (vc.y_origin);
4744 * Now the canvas is in the final state before render the canvas items that
4745 * support the Item::prepare_for_render interface can calculate the correct
4746 * item to visible canvas intersection.
4748 if (vc.pending & VisualChange::ZoomLevel) {
4749 on_samples_per_pixel_changed ();
4751 compute_fixed_ruler_scale ();
4753 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4754 update_tempo_based_rulers ();
4757 if (!(vc.pending & VisualChange::ZoomLevel)) {
4758 /* If the canvas is not being zoomed then the canvas items will not change
4759 * and cause Item::prepare_for_render to be called so do it here manually.
4760 * Not ideal, but I can't think of a better solution atm.
4762 _track_canvas->prepare_for_render();
4765 /* If we are only scrolling vertically there is no need to update these */
4766 if (vc.pending != VisualChange::YOrigin) {
4767 update_fixed_rulers ();
4768 redisplay_grid (true);
4770 /* video frames & position need to be updated for zoom, horiz-scroll
4771 * and (explicitly) VisualChange::VideoTimeline.
4773 update_video_timeline();
4776 _summary->set_overlays_dirty ();
4779 struct EditorOrderTimeAxisSorter {
4780 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4781 return a->order () < b->order ();
4786 Editor::sort_track_selection (TrackViewList& sel)
4788 EditorOrderTimeAxisSorter cmp;
4793 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4796 samplepos_t where = 0;
4797 EditPoint ep = _edit_point;
4799 if (Profile->get_mixbus()) {
4800 if (ep == EditAtSelectedMarker) {
4801 ep = EditAtPlayhead;
4805 if (from_outside_canvas && (ep == EditAtMouse)) {
4806 ep = EditAtPlayhead;
4807 } else if (from_context_menu && (ep == EditAtMouse)) {
4808 return canvas_event_sample (&context_click_event, 0, 0);
4811 if (entered_marker) {
4812 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4813 return entered_marker->position();
4816 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4817 ep = EditAtSelectedMarker;
4820 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4821 ep = EditAtPlayhead;
4824 MusicSample snap_mf (0, 0);
4827 case EditAtPlayhead:
4828 if (_dragging_playhead) {
4829 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4830 where = playhead_cursor->current_sample();
4832 where = _session->audible_sample();
4834 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4837 case EditAtSelectedMarker:
4838 if (!selection->markers.empty()) {
4840 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4843 where = loc->start();
4847 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4855 if (!mouse_sample (where, ignored)) {
4856 /* XXX not right but what can we do ? */
4859 snap_mf.sample = where;
4861 where = snap_mf.sample;
4862 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4870 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4872 if (!_session) return;
4874 begin_reversible_command (cmd);
4878 if ((tll = transport_loop_location()) == 0) {
4879 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4880 XMLNode &before = _session->locations()->get_state();
4881 _session->locations()->add (loc, true);
4882 _session->set_auto_loop_location (loc);
4883 XMLNode &after = _session->locations()->get_state();
4884 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4886 XMLNode &before = tll->get_state();
4887 tll->set_hidden (false, this);
4888 tll->set (start, end);
4889 XMLNode &after = tll->get_state();
4890 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4893 commit_reversible_command ();
4897 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4899 if (!_session) return;
4901 begin_reversible_command (cmd);
4905 if ((tpl = transport_punch_location()) == 0) {
4906 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4907 XMLNode &before = _session->locations()->get_state();
4908 _session->locations()->add (loc, true);
4909 _session->set_auto_punch_location (loc);
4910 XMLNode &after = _session->locations()->get_state();
4911 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4913 XMLNode &before = tpl->get_state();
4914 tpl->set_hidden (false, this);
4915 tpl->set (start, end);
4916 XMLNode &after = tpl->get_state();
4917 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4920 commit_reversible_command ();
4923 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4924 * @param rs List to which found regions are added.
4925 * @param where Time to look at.
4926 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4929 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4931 const TrackViewList* tracks;
4934 tracks = &track_views;
4939 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4941 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4944 boost::shared_ptr<Track> tr;
4945 boost::shared_ptr<Playlist> pl;
4947 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4949 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4951 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4952 RegionView* rv = rtv->view()->find_view (*i);
4963 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4965 const TrackViewList* tracks;
4968 tracks = &track_views;
4973 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4974 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4976 boost::shared_ptr<Track> tr;
4977 boost::shared_ptr<Playlist> pl;
4979 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4981 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4983 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4985 RegionView* rv = rtv->view()->find_view (*i);
4996 /** Get regions using the following method:
4998 * Make a region list using:
4999 * (a) any selected regions
5000 * (b) the intersection of any selected tracks and the edit point(*)
5001 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
5003 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5005 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5009 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
5011 RegionSelection regions;
5013 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5014 regions.add (entered_regionview);
5016 regions = selection->regions;
5019 if (regions.empty()) {
5020 TrackViewList tracks = selection->tracks;
5022 if (!tracks.empty()) {
5023 /* no region selected or entered, but some selected tracks:
5024 * act on all regions on the selected tracks at the edit point
5026 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
5027 get_regions_at(regions, where, tracks);
5034 /** Get regions using the following method:
5036 * Make a region list using:
5037 * (a) any selected regions
5038 * (b) the intersection of any selected tracks and the edit point(*)
5039 * (c) if neither exists, then whatever region is under the mouse
5041 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5043 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5046 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
5048 RegionSelection regions;
5050 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5051 regions.add (entered_regionview);
5053 regions = selection->regions;
5056 if (regions.empty()) {
5057 TrackViewList tracks = selection->tracks;
5059 if (!tracks.empty()) {
5060 /* no region selected or entered, but some selected tracks:
5061 * act on all regions on the selected tracks at the edit point
5063 get_regions_at(regions, pos, tracks);
5070 /** Start with regions that are selected, or the entered regionview if none are selected.
5071 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5072 * of the regions that we started with.
5076 Editor::get_regions_from_selection_and_entered () const
5078 RegionSelection regions = selection->regions;
5080 if (regions.empty() && entered_regionview) {
5081 regions.add (entered_regionview);
5088 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5090 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5091 RouteTimeAxisView* rtav;
5093 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5094 boost::shared_ptr<Playlist> pl;
5095 std::vector<boost::shared_ptr<Region> > results;
5096 boost::shared_ptr<Track> tr;
5098 if ((tr = rtav->track()) == 0) {
5103 if ((pl = (tr->playlist())) != 0) {
5104 boost::shared_ptr<Region> r = pl->region_by_id (id);
5106 RegionView* rv = rtav->view()->find_view (r);
5108 regions.push_back (rv);
5117 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5120 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5121 MidiTimeAxisView* mtav;
5123 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5125 mtav->get_per_region_note_selection (selection);
5132 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5134 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5136 RouteTimeAxisView* tatv;
5138 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5140 boost::shared_ptr<Playlist> pl;
5141 vector<boost::shared_ptr<Region> > results;
5143 boost::shared_ptr<Track> tr;
5145 if ((tr = tatv->track()) == 0) {
5150 if ((pl = (tr->playlist())) != 0) {
5151 if (src_comparison) {
5152 pl->get_source_equivalent_regions (region, results);
5154 pl->get_region_list_equivalent_regions (region, results);
5158 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5159 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5160 regions.push_back (marv);
5169 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5171 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5172 RouteTimeAxisView* tatv;
5173 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5174 if (!tatv->track()) {
5177 RegionView* marv = tatv->view()->find_view (region);
5187 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5189 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5190 RouteTimeAxisView* rtav;
5191 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5192 if (rtav->route() == route) {
5201 Editor::show_rhythm_ferret ()
5203 if (rhythm_ferret == 0) {
5204 rhythm_ferret = new RhythmFerret(*this);
5207 rhythm_ferret->set_session (_session);
5208 rhythm_ferret->show ();
5209 rhythm_ferret->present ();
5213 Editor::first_idle ()
5215 MessageDialog* dialog = 0;
5217 if (track_views.size() > 1) {
5218 Timers::TimerSuspender t;
5219 dialog = new MessageDialog (
5220 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5224 ARDOUR_UI::instance()->flush_pending (60);
5227 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5231 /* now that all regionviews should exist, setup region selection */
5235 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5236 /* this is cumulative: rs is NOT cleared each time */
5237 get_regionviews_by_id (*pr, rs);
5240 selection->set (rs);
5242 /* first idle adds route children (automation tracks), so we need to redisplay here */
5243 _routes->redisplay ();
5247 if (_session->undo_depth() == 0) {
5248 undo_action->set_sensitive(false);
5250 redo_action->set_sensitive(false);
5251 begin_selection_op_history ();
5257 Editor::_idle_resize (gpointer arg)
5259 return ((Editor*)arg)->idle_resize ();
5263 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5265 if (resize_idle_id < 0) {
5266 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5267 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5268 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5270 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5271 _pending_resize_amount = 0;
5274 /* make a note of the smallest resulting height, so that we can clamp the
5275 lower limit at TimeAxisView::hSmall */
5277 int32_t min_resulting = INT32_MAX;
5279 _pending_resize_amount += h;
5280 _pending_resize_view = view;
5282 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5284 if (selection->tracks.contains (_pending_resize_view)) {
5285 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5286 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5290 if (min_resulting < 0) {
5295 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5296 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5300 /** Handle pending resizing of tracks */
5302 Editor::idle_resize ()
5304 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5306 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5307 selection->tracks.contains (_pending_resize_view)) {
5309 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5310 if (*i != _pending_resize_view) {
5311 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5316 _pending_resize_amount = 0;
5317 _group_tabs->set_dirty ();
5318 resize_idle_id = -1;
5326 ENSURE_GUI_THREAD (*this, &Editor::located);
5329 playhead_cursor->set_position (_session->audible_sample ());
5330 if (_follow_playhead && !_pending_initial_locate) {
5331 reset_x_origin_to_follow_playhead ();
5335 _pending_locate_request = false;
5336 _pending_initial_locate = false;
5337 _last_update_time = 0;
5341 Editor::region_view_added (RegionView * rv)
5343 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5345 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5346 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5347 if (rv->region()->id () == (*rnote).first) {
5348 mrv->select_notes ((*rnote).second);
5349 selection->pending_midi_note_selection.erase(rnote);
5355 _summary->set_background_dirty ();
5357 mark_region_boundary_cache_dirty ();
5361 Editor::region_view_removed ()
5363 _summary->set_background_dirty ();
5365 mark_region_boundary_cache_dirty ();
5369 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5371 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5372 if ((*j)->stripable() == s) {
5381 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5383 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5384 if ((*j)->control() == c) {
5388 TimeAxisView::Children kids = (*j)->get_child_list ();
5390 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5391 if ((*k)->control() == c) {
5401 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5405 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5406 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5416 Editor::suspend_route_redisplay ()
5419 _routes->suspend_redisplay();
5424 Editor::resume_route_redisplay ()
5427 _routes->redisplay(); // queue redisplay
5428 _routes->resume_redisplay();
5433 Editor::add_vcas (VCAList& vlist)
5437 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5438 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5441 add_stripables (sl);
5445 Editor::add_routes (RouteList& rlist)
5449 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5453 add_stripables (sl);
5457 Editor::add_stripables (StripableList& sl)
5459 list<TimeAxisView*> new_views;
5460 boost::shared_ptr<VCA> v;
5461 boost::shared_ptr<Route> r;
5462 TrackViewList new_selection;
5463 bool from_scratch = (track_views.size() == 0);
5465 sl.sort (Stripable::Sorter());
5467 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5469 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5471 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5473 new_views.push_back (vtv);
5475 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5477 if (r->is_auditioner() || r->is_monitor()) {
5481 RouteTimeAxisView* rtv;
5482 DataType dt = r->input()->default_type();
5484 if (dt == ARDOUR::DataType::AUDIO) {
5485 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5487 } else if (dt == ARDOUR::DataType::MIDI) {
5488 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5491 throw unknown_type();
5494 new_views.push_back (rtv);
5495 track_views.push_back (rtv);
5496 new_selection.push_back (rtv);
5498 rtv->effective_gain_display ();
5500 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5501 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5505 if (new_views.size() > 0) {
5506 _routes->time_axis_views_added (new_views);
5507 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5510 /* note: !new_selection.empty() means that we got some routes rather
5514 if (!from_scratch && !new_selection.empty()) {
5515 selection->set (new_selection);
5516 begin_selection_op_history();
5519 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5520 show_editor_mixer (true);
5523 editor_list_button.set_sensitive (true);
5527 Editor::timeaxisview_deleted (TimeAxisView *tv)
5529 if (tv == entered_track) {
5533 if (_session && _session->deletion_in_progress()) {
5534 /* the situation is under control */
5538 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5540 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5542 _routes->route_removed (tv);
5544 TimeAxisView::Children c = tv->get_child_list ();
5545 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5546 if (entered_track == i->get()) {
5551 /* remove it from the list of track views */
5553 TrackViewList::iterator i;
5555 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5556 i = track_views.erase (i);
5559 /* update whatever the current mixer strip is displaying, if revelant */
5561 boost::shared_ptr<Route> route;
5564 route = rtav->route ();
5567 if (current_mixer_strip && current_mixer_strip->route() == route) {
5569 TimeAxisView* next_tv;
5571 if (track_views.empty()) {
5573 } else if (i == track_views.end()) {
5574 next_tv = track_views.front();
5579 // skip VCAs (cannot be selected, n/a in editor-mixer)
5580 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5581 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5582 next_tv = track_views.front();
5584 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5585 /* just in case: no master, only a VCA remains */
5591 set_selected_mixer_strip (*next_tv);
5593 /* make the editor mixer strip go away setting the
5594 * button to inactive (which also unticks the menu option)
5597 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5603 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5609 DisplaySuspender ds;
5610 PresentationInfo::ChangeSuspender cs;
5612 if (apply_to_selection) {
5613 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5615 TrackSelection::iterator j = i;
5618 hide_track_in_display (*i, false);
5623 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5625 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5626 /* this will hide the mixer strip */
5627 set_selected_mixer_strip (*tv);
5630 _routes->hide_track_in_display (*tv);
5635 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5640 _routes->show_track_in_display (*tv);
5641 if (move_into_view) {
5642 ensure_time_axis_view_is_visible (*tv, false);
5647 Editor::sync_track_view_list_and_routes ()
5649 track_views = TrackViewList (_routes->views ());
5651 _summary->set_background_dirty();
5652 _group_tabs->set_dirty ();
5654 return false; // do not call again (until needed)
5658 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5660 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5665 /** Find a StripableTimeAxisView by the ID of its stripable */
5666 StripableTimeAxisView*
5667 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5669 StripableTimeAxisView* v;
5671 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5672 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5673 if(v->stripable()->id() == id) {
5683 Editor::fit_route_group (RouteGroup *g)
5685 TrackViewList ts = axis_views_from_routes (g->route_list ());
5690 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5692 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5695 _session->cancel_audition ();
5699 if (_session->is_auditioning()) {
5700 _session->cancel_audition ();
5701 if (r == last_audition_region) {
5706 _session->audition_region (r);
5707 last_audition_region = r;
5712 Editor::hide_a_region (boost::shared_ptr<Region> r)
5714 r->set_hidden (true);
5718 Editor::show_a_region (boost::shared_ptr<Region> r)
5720 r->set_hidden (false);
5724 Editor::audition_region_from_region_list ()
5726 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5730 Editor::hide_region_from_region_list ()
5732 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5736 Editor::show_region_in_region_list ()
5738 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5742 Editor::step_edit_status_change (bool yn)
5745 start_step_editing ();
5747 stop_step_editing ();
5752 Editor::start_step_editing ()
5754 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5758 Editor::stop_step_editing ()
5760 step_edit_connection.disconnect ();
5764 Editor::check_step_edit ()
5766 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5767 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5769 mtv->check_step_edit ();
5773 return true; // do it again, till we stop
5777 Editor::scroll_press (Direction dir)
5779 ++_scroll_callbacks;
5781 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5782 /* delay the first auto-repeat */
5788 scroll_backward (1);
5796 scroll_up_one_track ();
5800 scroll_down_one_track ();
5804 /* do hacky auto-repeat */
5805 if (!_scroll_connection.connected ()) {
5807 _scroll_connection = Glib::signal_timeout().connect (
5808 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5811 _scroll_callbacks = 0;
5818 Editor::scroll_release ()
5820 _scroll_connection.disconnect ();
5823 /** Queue a change for the Editor viewport x origin to follow the playhead */
5825 Editor::reset_x_origin_to_follow_playhead ()
5827 samplepos_t const sample = playhead_cursor->current_sample ();
5829 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5831 if (_session->transport_speed() < 0) {
5833 if (sample > (current_page_samples() / 2)) {
5834 center_screen (sample-(current_page_samples()/2));
5836 center_screen (current_page_samples()/2);
5843 if (sample < _leftmost_sample) {
5845 if (_session->transport_rolling()) {
5846 /* rolling; end up with the playhead at the right of the page */
5847 l = sample - current_page_samples ();
5849 /* not rolling: end up with the playhead 1/4 of the way along the page */
5850 l = sample - current_page_samples() / 4;
5854 if (_session->transport_rolling()) {
5855 /* rolling: end up with the playhead on the left of the page */
5858 /* not rolling: end up with the playhead 3/4 of the way along the page */
5859 l = sample - 3 * current_page_samples() / 4;
5867 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5873 Editor::super_rapid_screen_update ()
5875 if (!_session || !_session->engine().running()) {
5879 /* METERING / MIXER STRIPS */
5881 /* update track meters, if required */
5882 if (contents().is_mapped() && meters_running) {
5883 RouteTimeAxisView* rtv;
5884 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5885 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5886 rtv->fast_update ();
5891 /* and any current mixer strip */
5892 if (current_mixer_strip) {
5893 current_mixer_strip->fast_update ();
5896 bool latent_locate = false;
5897 samplepos_t sample = _session->audible_sample (&latent_locate);
5898 const int64_t now = g_get_monotonic_time ();
5901 if (_session->exporting ()) {
5902 /* freewheel/export may be faster or slower than transport_speed() / SR.
5903 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5905 _last_update_time = 0;
5908 if (!_session->transport_rolling () || _session->is_auditioning ()) {
5909 /* Do not interpolate the playhead position; just set it */
5910 _last_update_time = 0;
5913 if (_last_update_time > 0) {
5914 /* interpolate and smoothen playhead position */
5915 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5916 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5917 err = sample - guess;
5919 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5920 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5923 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5925 err, _err_screen_engine);
5930 _err_screen_engine = 0;
5933 if (err > 8192 || latent_locate) {
5934 // in case of x-runs or freewheeling
5935 _last_update_time = 0;
5936 sample = _session->audible_sample ();
5938 _last_update_time = now;
5941 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5943 MusicSample where (sample, 0);
5944 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5945 snapped_cursor->hide ();
5946 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5947 /* EditAtPlayhead does not snap */
5948 } else if (_edit_point == EditAtSelectedMarker) {
5949 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5950 * however, the current editing code -does- snap so I'll draw it that way for now.
5952 if (!selection->markers.empty()) {
5953 MusicSample ms (selection->markers.front()->position(), 0);
5954 snap_to (ms); // should use snap_to_with_modifier?
5955 snapped_cursor->set_position (ms.sample);
5956 snapped_cursor->show ();
5958 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5959 snapped_cursor->show ();
5960 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5961 snapped_cursor->hide ();
5964 /* There are a few reasons why we might not update the playhead / viewport stuff:
5966 * 1. we don't update things when there's a pending locate request, otherwise
5967 * when the editor requests a locate there is a chance that this method
5968 * will move the playhead before the locate request is processed, causing
5970 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5971 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5973 if (_pending_locate_request) {
5974 _last_update_time = 0;
5978 if (_dragging_playhead) {
5979 _last_update_time = 0;
5983 if (playhead_cursor->current_sample () == sample) {
5987 playhead_cursor->set_position (sample);
5989 if (_session->requested_return_sample() >= 0) {
5990 _last_update_time = 0;
5994 if (!_follow_playhead || pending_visual_change.being_handled) {
5995 /* We only do this if we aren't already
5996 * handling a visual change (ie if
5997 * pending_visual_change.being_handled is
5998 * false) so that these requests don't stack
5999 * up there are too many of them to handle in
6005 if (!_stationary_playhead) {
6006 reset_x_origin_to_follow_playhead ();
6008 samplepos_t const sample = playhead_cursor->current_sample ();
6009 double target = ((double)sample - (double)current_page_samples() / 2.0);
6010 if (target <= 0.0) {
6013 /* compare to EditorCursor::set_position() */
6014 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
6015 double const new_pos = sample_to_pixel_unrounded (target);
6016 if (rint (new_pos) != rint (old_pos)) {
6017 reset_x_origin (pixel_to_sample (new_pos));
6024 Editor::session_going_away ()
6026 _have_idled = false;
6028 _session_connections.drop_connections ();
6030 super_rapid_screen_update_connection.disconnect ();
6032 selection->clear ();
6033 cut_buffer->clear ();
6035 clicked_regionview = 0;
6036 clicked_axisview = 0;
6037 clicked_routeview = 0;
6038 entered_regionview = 0;
6040 _last_update_time = 0;
6043 playhead_cursor->hide ();
6045 /* rip everything out of the list displays */
6049 _route_groups->clear ();
6051 /* do this first so that deleting a track doesn't reset cms to null
6052 and thus cause a leak.
6055 if (current_mixer_strip) {
6056 if (current_mixer_strip->get_parent() != 0) {
6057 global_hpacker.remove (*current_mixer_strip);
6059 delete current_mixer_strip;
6060 current_mixer_strip = 0;
6063 /* delete all trackviews */
6065 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6068 track_views.clear ();
6070 nudge_clock->set_session (0);
6072 editor_list_button.set_active(false);
6073 editor_list_button.set_sensitive(false);
6075 /* clear tempo/meter rulers */
6076 remove_metric_marks ();
6077 clear_marker_display ();
6083 stop_step_editing ();
6087 /* get rid of any existing editor mixer strip */
6089 WindowTitle title(Glib::get_application_name());
6090 title += _("Editor");
6092 own_window()->set_title (title.get_string());
6095 SessionHandlePtr::session_going_away ();
6099 Editor::trigger_script (int i)
6101 LuaInstance::instance()-> call_action (i);
6105 Editor::show_editor_list (bool yn)
6108 _editor_list_vbox.show ();
6110 _editor_list_vbox.hide ();
6115 Editor::change_region_layering_order (bool from_context_menu)
6117 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6119 if (!clicked_routeview) {
6120 if (layering_order_editor) {
6121 layering_order_editor->hide ();
6126 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6132 boost::shared_ptr<Playlist> pl = track->playlist();
6138 if (layering_order_editor == 0) {
6139 layering_order_editor = new RegionLayeringOrderEditor (*this);
6142 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6143 layering_order_editor->maybe_present ();
6147 Editor::update_region_layering_order_editor ()
6149 if (layering_order_editor && layering_order_editor->is_visible ()) {
6150 change_region_layering_order (true);
6155 Editor::setup_fade_images ()
6157 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6158 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6159 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6160 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6161 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6163 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6164 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6165 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6166 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6167 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6171 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6173 Editor::action_menu_item (std::string const & name)
6175 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6178 return *manage (a->create_menu_item ());
6182 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6184 EventBox* b = manage (new EventBox);
6185 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6186 Label* l = manage (new Label (name));
6190 _the_notebook.append_page (widget, *b);
6194 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6196 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6197 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6200 if (ev->type == GDK_2BUTTON_PRESS) {
6202 /* double-click on a notebook tab shrinks or expands the notebook */
6204 if (_notebook_shrunk) {
6205 if (pre_notebook_shrink_pane_width) {
6206 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6208 _notebook_shrunk = false;
6210 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6212 /* this expands the LHS of the edit pane to cover the notebook
6213 PAGE but leaves the tabs visible.
6215 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6216 _notebook_shrunk = true;
6224 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6226 using namespace Menu_Helpers;
6228 MenuList& items = _control_point_context_menu.items ();
6231 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6232 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6233 if (!can_remove_control_point (item)) {
6234 items.back().set_sensitive (false);
6237 _control_point_context_menu.popup (event->button.button, event->button.time);
6241 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6243 using namespace Menu_Helpers;
6245 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6250 /* We need to get the selection here and pass it to the operations, since
6251 popping up the menu will cause a region leave event which clears
6252 entered_regionview. */
6254 MidiRegionView& mrv = note->region_view();
6255 const RegionSelection rs = get_regions_from_selection_and_entered ();
6256 const uint32_t sel_size = mrv.selection_size ();
6258 MenuList& items = _note_context_menu.items();
6262 items.push_back(MenuElem(_("Delete"),
6263 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6266 items.push_back(MenuElem(_("Edit..."),
6267 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6268 if (sel_size != 1) {
6269 items.back().set_sensitive (false);
6272 items.push_back(MenuElem(_("Transpose..."),
6273 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6276 items.push_back(MenuElem(_("Legatize"),
6277 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6279 items.back().set_sensitive (false);
6282 items.push_back(MenuElem(_("Quantize..."),
6283 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6285 items.push_back(MenuElem(_("Remove Overlap"),
6286 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6288 items.back().set_sensitive (false);
6291 items.push_back(MenuElem(_("Transform..."),
6292 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6294 _note_context_menu.popup (event->button.button, event->button.time);
6298 Editor::zoom_vertical_modifier_released()
6300 _stepping_axis_view = 0;
6304 Editor::ui_parameter_changed (string parameter)
6306 if (parameter == "icon-set") {
6307 while (!_cursor_stack.empty()) {
6308 _cursor_stack.pop_back();
6310 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6311 _cursor_stack.push_back(_cursors->grabber);
6312 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6313 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6315 } else if (parameter == "draggable-playhead") {
6316 if (_verbose_cursor) {
6317 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6319 } else if (parameter == "use-note-bars-for-velocity") {
6320 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6321 _track_canvas->request_redraw (_track_canvas->visible_area());
6322 } else if (parameter == "use-note-color-for-velocity") {
6323 /* handled individually by each MidiRegionView */
6328 Editor::use_own_window (bool and_fill_it)
6330 bool new_window = !own_window();
6332 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6334 if (win && new_window) {
6335 win->set_name ("EditorWindow");
6337 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6339 // win->signal_realize().connect (*this, &Editor::on_realize);
6340 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6341 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6342 win->set_data ("ardour-bindings", bindings);
6347 DisplaySuspender ds;
6348 contents().show_all ();
6350 /* XXX: this is a bit unfortunate; it would probably
6351 be nicer if we could just call show () above rather
6352 than needing the show_all ()
6355 /* re-hide stuff if necessary */
6356 editor_list_button_toggled ();
6357 parameter_changed ("show-summary");
6358 parameter_changed ("show-group-tabs");
6359 parameter_changed ("show-zoom-tools");
6361 /* now reset all audio_time_axis heights, because widgets might need
6367 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6368 tv = (static_cast<TimeAxisView*>(*i));
6369 tv->reset_height ();
6372 if (current_mixer_strip) {
6373 current_mixer_strip->hide_things ();
6374 current_mixer_strip->parameter_changed ("mixer-element-visibility");