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 , _popup_region_menu_item (0)
267 , _track_canvas_viewport (0)
268 , within_track_canvas (false)
269 , _verbose_cursor (0)
273 , range_marker_group (0)
274 , transport_marker_group (0)
275 , cd_marker_group (0)
276 , _time_markers_group (0)
277 , hv_scroll_group (0)
279 , cursor_scroll_group (0)
280 , no_scroll_group (0)
281 , _trackview_group (0)
282 , _drag_motion_group (0)
283 , _canvas_drop_zone (0)
284 , no_ruler_shown_update (false)
285 , ruler_grabbed_widget (0)
287 , minsec_mark_interval (0)
288 , minsec_mark_modulo (0)
290 , timecode_ruler_scale (timecode_show_many_hours)
291 , timecode_mark_modulo (0)
292 , timecode_nmarks (0)
293 , _samples_ruler_interval (0)
294 , bbt_ruler_scale (bbt_show_many)
297 , bbt_bar_helper_on (0)
298 , bbt_accent_modulo (0)
303 , visible_timebars (0)
304 , editor_ruler_menu (0)
308 , range_marker_bar (0)
309 , transport_marker_bar (0)
311 , minsec_label (_("Mins:Secs"))
312 , bbt_label (_("Bars:Beats"))
313 , timecode_label (_("Timecode"))
314 , samples_label (_("Samples"))
315 , tempo_label (_("Tempo"))
316 , meter_label (_("Meter"))
317 , mark_label (_("Location Markers"))
318 , range_mark_label (_("Range Markers"))
319 , transport_mark_label (_("Loop/Punch Ranges"))
320 , cd_mark_label (_("CD Markers"))
321 , videotl_label (_("Video Timeline"))
324 , playhead_cursor (0)
325 , _region_boundary_cache_dirty (true)
326 , edit_packer (4, 4, true)
327 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
328 , horizontal_adjustment (0.0, 0.0, 1e16)
329 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
330 , controls_layout (unused_adjustment, vertical_adjustment)
331 , _scroll_callbacks (0)
332 , _visible_canvas_width (0)
333 , _visible_canvas_height (0)
334 , _full_canvas_height (0)
335 , edit_controls_left_menu (0)
336 , edit_controls_right_menu (0)
337 , visual_change_queued(false)
338 , _last_update_time (0)
339 , _err_screen_engine (0)
340 , cut_buffer_start (0)
341 , cut_buffer_length (0)
342 , button_bindings (0)
343 , last_paste_pos (-1)
346 , current_interthread_info (0)
347 , analysis_window (0)
348 , select_new_marker (false)
350 , scrubbing_direction (0)
351 , scrub_reversals (0)
352 , scrub_reverse_distance (0)
353 , have_pending_keyboard_selection (false)
354 , pending_keyboard_selection_start (0)
355 , _grid_type (GridTypeBeat)
356 , _snap_mode (SnapOff)
357 , ignore_gui_changes (false)
358 , _drags (new DragManager (this))
360 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
361 , _dragging_playhead (false)
362 , _dragging_edit_point (false)
363 , _follow_playhead (true)
364 , _stationary_playhead (false)
367 , global_rect_group (0)
368 , time_line_group (0)
369 , tempo_marker_menu (0)
370 , meter_marker_menu (0)
372 , range_marker_menu (0)
373 , new_transport_marker_menu (0)
374 , marker_menu_item (0)
375 , bbt_beat_subdivision (4)
376 , _visible_track_count (-1)
377 , toolbar_selection_clock_table (2,3)
378 , automation_mode_button (_("mode"))
379 , selection (new Selection (this, true))
380 , cut_buffer (new Selection (this, false))
381 , _selection_memento (new SelectionMemento())
382 , _all_region_actions_sensitized (false)
383 , _ignore_region_action (false)
384 , _last_region_menu_was_main (false)
385 , _track_selection_change_without_scroll (false)
386 , _editor_track_selection_change_without_scroll (false)
387 , cd_marker_bar_drag_rect (0)
388 , range_bar_drag_rect (0)
389 , transport_bar_drag_rect (0)
390 , transport_bar_range_rect (0)
391 , transport_bar_preroll_rect (0)
392 , transport_bar_postroll_rect (0)
393 , transport_loop_range_rect (0)
394 , transport_punch_range_rect (0)
395 , transport_punchin_line (0)
396 , transport_punchout_line (0)
397 , transport_preroll_rect (0)
398 , transport_postroll_rect (0)
400 , rubberband_rect (0)
406 , autoscroll_horizontal_allowed (false)
407 , autoscroll_vertical_allowed (false)
409 , autoscroll_widget (0)
410 , show_gain_after_trim (false)
411 , selection_op_cmd_depth (0)
412 , selection_op_history_it (0)
413 , no_save_instant (false)
415 , current_mixer_strip (0)
416 , show_editor_mixer_when_tracks_arrive (false)
417 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
418 , current_stepping_trackview (0)
419 , last_track_height_step_timestamp (0)
421 , entered_regionview (0)
422 , clear_entered_track (false)
423 , _edit_point (EditAtMouse)
424 , meters_running (false)
426 , _have_idled (false)
427 , resize_idle_id (-1)
428 , _pending_resize_amount (0)
429 , _pending_resize_view (0)
430 , _pending_locate_request (false)
431 , _pending_initial_locate (false)
435 , layering_order_editor (0)
436 , _last_cut_copy_source_track (0)
437 , _region_selection_change_updates_region_list (true)
439 , _following_mixer_selection (false)
440 , _control_point_toggled_on_press (false)
441 , _stepping_axis_view (0)
442 , quantize_dialog (0)
443 , _main_menu_disabler (0)
445 /* we are a singleton */
447 PublicEditor::_instance = this;
451 last_event_time.tv_sec = 0;
452 last_event_time.tv_usec = 0;
454 selection_op_history.clear();
457 grid_type_strings = I18N (_grid_type_strings);
458 zoom_focus_strings = I18N (_zoom_focus_strings);
459 edit_mode_strings = I18N (_edit_mode_strings);
460 edit_point_strings = I18N (_edit_point_strings);
461 #ifdef USE_RUBBERBAND
462 rb_opt_strings = I18N (_rb_opt_strings);
466 build_edit_mode_menu();
467 build_zoom_focus_menu();
468 build_track_count_menu();
469 build_grid_type_menu();
470 build_edit_point_menu();
472 location_marker_color = UIConfiguration::instance().color ("location marker");
473 location_range_color = UIConfiguration::instance().color ("location range");
474 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
475 location_loop_color = UIConfiguration::instance().color ("location loop");
476 location_punch_color = UIConfiguration::instance().color ("location punch");
478 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
480 TimeAxisView::setup_sizes ();
481 ArdourMarker::setup_sizes (timebar_height);
482 TempoCurve::setup_sizes (timebar_height);
484 bbt_label.set_name ("EditorRulerLabel");
485 bbt_label.set_size_request (-1, (int)timebar_height);
486 bbt_label.set_alignment (1.0, 0.5);
487 bbt_label.set_padding (5,0);
489 bbt_label.set_no_show_all();
490 minsec_label.set_name ("EditorRulerLabel");
491 minsec_label.set_size_request (-1, (int)timebar_height);
492 minsec_label.set_alignment (1.0, 0.5);
493 minsec_label.set_padding (5,0);
494 minsec_label.hide ();
495 minsec_label.set_no_show_all();
496 timecode_label.set_name ("EditorRulerLabel");
497 timecode_label.set_size_request (-1, (int)timebar_height);
498 timecode_label.set_alignment (1.0, 0.5);
499 timecode_label.set_padding (5,0);
500 timecode_label.hide ();
501 timecode_label.set_no_show_all();
502 samples_label.set_name ("EditorRulerLabel");
503 samples_label.set_size_request (-1, (int)timebar_height);
504 samples_label.set_alignment (1.0, 0.5);
505 samples_label.set_padding (5,0);
506 samples_label.hide ();
507 samples_label.set_no_show_all();
509 tempo_label.set_name ("EditorRulerLabel");
510 tempo_label.set_size_request (-1, (int)timebar_height);
511 tempo_label.set_alignment (1.0, 0.5);
512 tempo_label.set_padding (5,0);
514 tempo_label.set_no_show_all();
516 meter_label.set_name ("EditorRulerLabel");
517 meter_label.set_size_request (-1, (int)timebar_height);
518 meter_label.set_alignment (1.0, 0.5);
519 meter_label.set_padding (5,0);
521 meter_label.set_no_show_all();
523 if (Profile->get_trx()) {
524 mark_label.set_text (_("Markers"));
526 mark_label.set_name ("EditorRulerLabel");
527 mark_label.set_size_request (-1, (int)timebar_height);
528 mark_label.set_alignment (1.0, 0.5);
529 mark_label.set_padding (5,0);
531 mark_label.set_no_show_all();
533 cd_mark_label.set_name ("EditorRulerLabel");
534 cd_mark_label.set_size_request (-1, (int)timebar_height);
535 cd_mark_label.set_alignment (1.0, 0.5);
536 cd_mark_label.set_padding (5,0);
537 cd_mark_label.hide();
538 cd_mark_label.set_no_show_all();
540 videotl_bar_height = 4;
541 videotl_label.set_name ("EditorRulerLabel");
542 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
543 videotl_label.set_alignment (1.0, 0.5);
544 videotl_label.set_padding (5,0);
545 videotl_label.hide();
546 videotl_label.set_no_show_all();
548 range_mark_label.set_name ("EditorRulerLabel");
549 range_mark_label.set_size_request (-1, (int)timebar_height);
550 range_mark_label.set_alignment (1.0, 0.5);
551 range_mark_label.set_padding (5,0);
552 range_mark_label.hide();
553 range_mark_label.set_no_show_all();
555 transport_mark_label.set_name ("EditorRulerLabel");
556 transport_mark_label.set_size_request (-1, (int)timebar_height);
557 transport_mark_label.set_alignment (1.0, 0.5);
558 transport_mark_label.set_padding (5,0);
559 transport_mark_label.hide();
560 transport_mark_label.set_no_show_all();
562 initialize_canvas ();
564 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
566 _summary = new EditorSummary (this);
568 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
569 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
571 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
573 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
574 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
576 edit_controls_vbox.set_spacing (0);
577 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
578 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
580 HBox* h = manage (new HBox);
581 _group_tabs = new EditorGroupTabs (this);
582 if (!ARDOUR::Profile->get_trx()) {
583 h->pack_start (*_group_tabs, PACK_SHRINK);
585 h->pack_start (edit_controls_vbox);
586 controls_layout.add (*h);
588 controls_layout.set_name ("EditControlsBase");
589 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
590 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
591 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
593 _cursors = new MouseCursors;
594 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
595 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
597 /* Push default cursor to ever-present bottom of cursor stack. */
598 push_canvas_cursor(_cursors->grabber);
600 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
602 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
603 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
604 pad_line_1->set_outline_color (0xFF0000FF);
610 edit_packer.set_col_spacings (0);
611 edit_packer.set_row_spacings (0);
612 edit_packer.set_homogeneous (false);
613 edit_packer.set_border_width (0);
614 edit_packer.set_name ("EditorWindow");
616 time_bars_event_box.add (time_bars_vbox);
617 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
618 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
620 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
621 axis_view_shadow->set_size_request (4, -1);
622 axis_view_shadow->set_name("EditorWindow");
623 axis_view_shadow->show();
625 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
627 /* labels for the time bars */
628 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
630 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
632 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
634 bottom_hbox.set_border_width (2);
635 bottom_hbox.set_spacing (3);
637 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
639 _route_groups = new EditorRouteGroups (this);
640 _routes = new EditorRoutes (this);
641 _regions = new EditorRegions (this);
642 _snapshots = new EditorSnapshots (this);
643 _locations = new EditorLocations (this);
644 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
646 /* these are static location signals */
648 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
649 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
650 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 add_notebook_page (_("Regions"), _regions->widget ());
653 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
654 add_notebook_page (_("Snapshots"), _snapshots->widget ());
655 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
656 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
658 _the_notebook.set_show_tabs (true);
659 _the_notebook.set_scrollable (true);
660 _the_notebook.popup_disable ();
661 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
662 _the_notebook.show_all ();
664 _notebook_shrunk = false;
667 /* Pick up some settings we need to cache, early */
669 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
672 settings->get_property ("notebook-shrunk", _notebook_shrunk);
675 editor_summary_pane.set_check_divider_position (true);
676 editor_summary_pane.add (edit_packer);
678 Button* summary_arrow_left = manage (new Button);
679 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
680 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
681 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
683 Button* summary_arrow_right = manage (new Button);
684 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
685 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
686 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
688 VBox* summary_arrows_left = manage (new VBox);
689 summary_arrows_left->pack_start (*summary_arrow_left);
691 VBox* summary_arrows_right = manage (new VBox);
692 summary_arrows_right->pack_start (*summary_arrow_right);
694 Frame* summary_frame = manage (new Frame);
695 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
697 summary_frame->add (*_summary);
698 summary_frame->show ();
700 _summary_hbox.pack_start (*summary_arrows_left, false, false);
701 _summary_hbox.pack_start (*summary_frame, true, true);
702 _summary_hbox.pack_start (*summary_arrows_right, false, false);
704 if (!ARDOUR::Profile->get_trx()) {
705 editor_summary_pane.add (_summary_hbox);
708 edit_pane.set_check_divider_position (true);
709 edit_pane.add (editor_summary_pane);
710 if (!ARDOUR::Profile->get_trx()) {
711 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
712 _editor_list_vbox.pack_start (_the_notebook);
713 edit_pane.add (_editor_list_vbox);
714 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
717 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
718 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
721 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
722 /* initial allocation is 90% to canvas, 10% to notebook */
725 edit_pane.set_divider (0, fract);
727 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
728 /* initial allocation is 90% to canvas, 10% to summary */
731 editor_summary_pane.set_divider (0, fract);
733 global_vpacker.set_spacing (0);
734 global_vpacker.set_border_width (0);
736 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
738 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
739 ebox->set_name("EditorWindow");
740 ebox->add (ebox_hpacker);
742 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
743 epane_box->set_name("EditorWindow");
744 epane_box->add (edit_pane);
746 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
747 epane_box2->set_name("EditorWindow");
748 epane_box2->add (global_vpacker);
750 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
751 toolbar_shadow->set_size_request (-1, 4);
752 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
753 toolbar_shadow->set_name("EditorWindow");
754 toolbar_shadow->show();
756 global_vpacker.pack_start (*toolbar_shadow, false, false);
757 global_vpacker.pack_start (*ebox, false, false);
758 global_vpacker.pack_start (*epane_box, true, true);
759 global_hpacker.pack_start (*epane_box2, true, true);
761 /* need to show the "contents" widget so that notebook will show if tab is switched to
764 global_hpacker.show ();
768 /* register actions now so that set_state() can find them and set toggles/checks etc */
775 _playlist_selector = new PlaylistSelector();
776 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
778 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
782 nudge_forward_button.set_name ("nudge button");
783 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
785 nudge_backward_button.set_name ("nudge button");
786 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
788 fade_context_menu.set_name ("ArdourContextMenu");
790 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
792 /* allow external control surfaces/protocols to do various things */
794 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
795 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
796 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
797 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
798 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
799 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
800 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
801 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
802 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
803 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
804 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
805 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
806 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
807 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
809 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
810 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
811 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
812 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
813 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
815 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
819 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
821 /* problematic: has to return a value and thus cannot be x-thread */
823 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
825 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
826 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
828 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
830 _ignore_region_action = false;
831 _last_region_menu_was_main = false;
833 _show_marker_lines = false;
835 /* Button bindings */
837 button_bindings = new Bindings ("editor-mouse");
839 XMLNode* node = button_settings();
841 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
842 button_bindings->load_operation (**i);
848 /* grab current parameter state */
849 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
850 UIConfiguration::instance().map_parameters (pc);
852 setup_fade_images ();
854 set_grid_to (GridTypeNone);
859 delete tempo_marker_menu;
860 delete meter_marker_menu;
862 delete range_marker_menu;
863 delete new_transport_marker_menu;
864 delete editor_ruler_menu;
865 delete _popup_region_menu_item;
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)
1146 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
1150 } catch ( ActionManager::MissingActionException const& e) {
1151 cerr << "MissingActionException:" << e.what () << endl;
1156 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1158 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1162 Editor::on_realize ()
1166 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1167 start_lock_event_timing ();
1172 Editor::start_lock_event_timing ()
1174 /* check if we should lock the GUI every 30 seconds */
1176 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1180 Editor::generic_event_handler (GdkEvent* ev)
1183 case GDK_BUTTON_PRESS:
1184 case GDK_BUTTON_RELEASE:
1185 case GDK_MOTION_NOTIFY:
1187 case GDK_KEY_RELEASE:
1188 if (contents().is_mapped()) {
1189 gettimeofday (&last_event_time, 0);
1193 case GDK_LEAVE_NOTIFY:
1194 switch (ev->crossing.detail) {
1195 case GDK_NOTIFY_UNKNOWN:
1196 case GDK_NOTIFY_INFERIOR:
1197 case GDK_NOTIFY_ANCESTOR:
1199 case GDK_NOTIFY_VIRTUAL:
1200 case GDK_NOTIFY_NONLINEAR:
1201 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1202 /* leaving window, so reset focus, thus ending any and
1203 all text entry operations.
1205 ARDOUR_UI::instance()->reset_focus (&contents());
1218 Editor::lock_timeout_callback ()
1220 struct timeval now, delta;
1222 gettimeofday (&now, 0);
1224 timersub (&now, &last_event_time, &delta);
1226 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1228 /* don't call again. Returning false will effectively
1229 disconnect us from the timer callback.
1231 unlock() will call start_lock_event_timing() to get things
1241 Editor::map_position_change (samplepos_t sample)
1243 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1245 if (_session == 0) {
1249 if (_follow_playhead) {
1250 center_screen (sample);
1253 playhead_cursor->set_position (sample);
1257 Editor::center_screen (samplepos_t sample)
1259 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1261 /* if we're off the page, then scroll.
1264 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1265 center_screen_internal (sample, page);
1270 Editor::center_screen_internal (samplepos_t sample, float page)
1274 if (sample > page) {
1275 sample -= (samplepos_t) page;
1280 reset_x_origin (sample);
1285 Editor::update_title ()
1287 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1289 if (!own_window()) {
1294 bool dirty = _session->dirty();
1296 string session_name;
1298 if (_session->snap_name() != _session->name()) {
1299 session_name = _session->snap_name();
1301 session_name = _session->name();
1305 session_name = "*" + session_name;
1308 WindowTitle title(session_name);
1309 title += S_("Window|Editor");
1310 title += Glib::get_application_name();
1311 own_window()->set_title (title.get_string());
1313 /* ::session_going_away() will have taken care of it */
1318 Editor::set_session (Session *t)
1320 SessionHandlePtr::set_session (t);
1326 /* initialize _leftmost_sample to the extents of the session
1327 * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
1328 * before the visible state has been loaded from instant.xml */
1329 _leftmost_sample = session_gui_extents().first;
1331 _playlist_selector->set_session (_session);
1332 nudge_clock->set_session (_session);
1333 _summary->set_session (_session);
1334 _group_tabs->set_session (_session);
1335 _route_groups->set_session (_session);
1336 _regions->set_session (_session);
1337 _snapshots->set_session (_session);
1338 _routes->set_session (_session);
1339 _locations->set_session (_session);
1340 _time_info_box->set_session (_session);
1342 if (rhythm_ferret) {
1343 rhythm_ferret->set_session (_session);
1346 if (analysis_window) {
1347 analysis_window->set_session (_session);
1351 sfbrowser->set_session (_session);
1354 compute_fixed_ruler_scale ();
1356 /* Make sure we have auto loop and auto punch ranges */
1358 Location* loc = _session->locations()->auto_loop_location();
1360 loc->set_name (_("Loop"));
1363 loc = _session->locations()->auto_punch_location();
1366 loc->set_name (_("Punch"));
1369 refresh_location_display ();
1371 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1372 * the selected Marker; this needs the LocationMarker list to be available.
1374 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1375 set_state (*node, Stateful::loading_state_version);
1377 /* catch up on selection state, etc. */
1380 sc.add (Properties::selected);
1381 presentation_info_changed (sc);
1383 /* catch up with the playhead */
1385 _session->request_locate (playhead_cursor->current_sample ());
1386 _pending_initial_locate = true;
1390 /* These signals can all be emitted by a non-GUI thread. Therefore the
1391 handlers for them must not attempt to directly interact with the GUI,
1392 but use PBD::Signal<T>::connect() which accepts an event loop
1393 ("context") where the handler will be asked to run.
1396 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1397 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1398 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1399 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1400 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1401 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1402 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1403 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1404 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1405 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1406 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1407 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1408 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1409 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1410 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1411 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1413 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1414 playhead_cursor->show ();
1416 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1417 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1418 snapped_cursor->show ();
1420 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1421 Config->map_parameters (pc);
1422 _session->config.map_parameters (pc);
1424 restore_ruler_visibility ();
1425 //tempo_map_changed (PropertyChange (0));
1426 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1428 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1429 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1432 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1433 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1436 /* register for undo history */
1437 _session->register_with_memento_command_factory(id(), this);
1438 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1440 LuaInstance::instance()->set_session(_session);
1442 start_updating_meters ();
1446 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1448 using namespace Menu_Helpers;
1450 void (Editor::*emf)(FadeShape);
1451 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1454 images = &_xfade_in_images;
1455 emf = &Editor::set_fade_in_shape;
1457 images = &_xfade_out_images;
1458 emf = &Editor::set_fade_out_shape;
1463 _("Linear (for highly correlated material)"),
1464 *(*images)[FadeLinear],
1465 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1469 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1473 _("Constant power"),
1474 *(*images)[FadeConstantPower],
1475 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1483 *(*images)[FadeSymmetric],
1484 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1493 *(*images)[FadeSlow],
1494 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1497 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1502 *(*images)[FadeFast],
1503 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1509 /** Pop up a context menu for when the user clicks on a start crossfade */
1511 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1513 using namespace Menu_Helpers;
1514 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1519 MenuList& items (xfade_in_context_menu.items());
1522 if (arv->audio_region()->fade_in_active()) {
1523 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1525 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1528 items.push_back (SeparatorElem());
1529 fill_xfade_menu (items, true);
1531 xfade_in_context_menu.popup (button, time);
1534 /** Pop up a context menu for when the user clicks on an end crossfade */
1536 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1538 using namespace Menu_Helpers;
1539 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1544 MenuList& items (xfade_out_context_menu.items());
1547 if (arv->audio_region()->fade_out_active()) {
1548 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1550 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1553 items.push_back (SeparatorElem());
1554 fill_xfade_menu (items, false);
1556 xfade_out_context_menu.popup (button, time);
1560 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1562 using namespace Menu_Helpers;
1563 Menu* (Editor::*build_menu_function)();
1566 switch (item_type) {
1568 case RegionViewName:
1569 case RegionViewNameHighlight:
1570 case LeftFrameHandle:
1571 case RightFrameHandle:
1572 if (with_selection) {
1573 build_menu_function = &Editor::build_track_selection_context_menu;
1575 build_menu_function = &Editor::build_track_region_context_menu;
1580 if (with_selection) {
1581 build_menu_function = &Editor::build_track_selection_context_menu;
1583 build_menu_function = &Editor::build_track_context_menu;
1588 if (clicked_routeview->track()) {
1589 build_menu_function = &Editor::build_track_context_menu;
1591 build_menu_function = &Editor::build_track_bus_context_menu;
1596 /* probably shouldn't happen but if it does, we don't care */
1600 menu = (this->*build_menu_function)();
1601 menu->set_name ("ArdourContextMenu");
1603 /* now handle specific situations */
1605 switch (item_type) {
1607 case RegionViewName:
1608 case RegionViewNameHighlight:
1609 case LeftFrameHandle:
1610 case RightFrameHandle:
1620 /* probably shouldn't happen but if it does, we don't care */
1624 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1626 /* Bounce to disk */
1628 using namespace Menu_Helpers;
1629 MenuList& edit_items = menu->items();
1631 edit_items.push_back (SeparatorElem());
1633 switch (clicked_routeview->audio_track()->freeze_state()) {
1634 case AudioTrack::NoFreeze:
1635 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1638 case AudioTrack::Frozen:
1639 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1642 case AudioTrack::UnFrozen:
1643 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1649 if (item_type == StreamItem && clicked_routeview) {
1650 clicked_routeview->build_underlay_menu(menu);
1653 /* When the region menu is opened, we setup the actions so that they look right
1656 sensitize_the_right_region_actions (false);
1657 _last_region_menu_was_main = false;
1659 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1660 menu->popup (button, time);
1664 Editor::build_track_context_menu ()
1666 using namespace Menu_Helpers;
1668 MenuList& edit_items = track_context_menu.items();
1671 add_dstream_context_items (edit_items);
1672 return &track_context_menu;
1676 Editor::build_track_bus_context_menu ()
1678 using namespace Menu_Helpers;
1680 MenuList& edit_items = track_context_menu.items();
1683 add_bus_context_items (edit_items);
1684 return &track_context_menu;
1688 Editor::build_track_region_context_menu ()
1690 using namespace Menu_Helpers;
1691 MenuList& edit_items = track_region_context_menu.items();
1694 /* we've just cleared the track region context menu, so the menu that these
1695 two items were on will have disappeared; stop them dangling.
1697 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1700 boost::shared_ptr<Track> tr;
1701 boost::shared_ptr<Playlist> pl;
1703 if ((tr = rtv->track())) {
1704 add_region_context_items (edit_items, tr);
1708 add_dstream_context_items (edit_items);
1710 return &track_region_context_menu;
1714 Editor::loudness_analyze_region_selection ()
1719 Selection& s (PublicEditor::instance ().get_selection ());
1720 RegionSelection ars = s.regions;
1721 ARDOUR::AnalysisGraph ag (_session);
1722 samplecnt_t total_work = 0;
1724 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1725 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1729 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1732 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1733 total_work += arv->region ()->length ();
1736 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1738 ag.set_total_samples (total_work);
1739 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1742 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1743 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1747 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1751 ag.analyze_region (ar);
1754 if (!ag.canceled ()) {
1755 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1761 Editor::loudness_analyze_range_selection ()
1766 Selection& s (PublicEditor::instance ().get_selection ());
1767 TimeSelection ts = s.time;
1768 ARDOUR::AnalysisGraph ag (_session);
1769 samplecnt_t total_work = 0;
1771 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1772 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1776 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1780 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1781 total_work += j->length ();
1785 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1787 ag.set_total_samples (total_work);
1788 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1791 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1792 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1796 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1800 ag.analyze_range (rui->route (), pl, ts);
1803 if (!ag.canceled ()) {
1804 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1810 Editor::spectral_analyze_region_selection ()
1812 if (analysis_window == 0) {
1813 analysis_window = new AnalysisWindow();
1816 analysis_window->set_session(_session);
1818 analysis_window->show_all();
1821 analysis_window->set_regionmode();
1822 analysis_window->analyze();
1824 analysis_window->present();
1828 Editor::spectral_analyze_range_selection()
1830 if (analysis_window == 0) {
1831 analysis_window = new AnalysisWindow();
1834 analysis_window->set_session(_session);
1836 analysis_window->show_all();
1839 analysis_window->set_rangemode();
1840 analysis_window->analyze();
1842 analysis_window->present();
1846 Editor::build_track_selection_context_menu ()
1848 using namespace Menu_Helpers;
1849 MenuList& edit_items = track_selection_context_menu.items();
1850 edit_items.clear ();
1852 add_selection_context_items (edit_items);
1853 // edit_items.push_back (SeparatorElem());
1854 // add_dstream_context_items (edit_items);
1856 return &track_selection_context_menu;
1860 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1862 using namespace Menu_Helpers;
1864 /* OK, stick the region submenu at the top of the list, and then add
1868 RegionSelection rs = get_regions_from_selection_and_entered ();
1870 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1872 if (_popup_region_menu_item == 0) {
1873 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1874 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1875 _popup_region_menu_item->show ();
1877 _popup_region_menu_item->set_label (menu_item_name);
1880 /* No layering allowed in later is higher layering model */
1881 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1882 if (act && Config->get_layer_model() == LaterHigher) {
1883 act->set_sensitive (false);
1885 act->set_sensitive (true);
1888 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1890 edit_items.push_back (*_popup_region_menu_item);
1891 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1892 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1894 edit_items.push_back (SeparatorElem());
1897 /** Add context menu items relevant to selection ranges.
1898 * @param edit_items List to add the items to.
1901 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1903 using namespace Menu_Helpers;
1905 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1906 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1908 edit_items.push_back (SeparatorElem());
1909 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1913 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1915 edit_items.push_back (SeparatorElem());
1917 edit_items.push_back (
1919 _("Move Range Start to Previous Region Boundary"),
1920 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1924 edit_items.push_back (
1926 _("Move Range Start to Next Region Boundary"),
1927 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1931 edit_items.push_back (
1933 _("Move Range End to Previous Region Boundary"),
1934 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1938 edit_items.push_back (
1940 _("Move Range End to Next Region Boundary"),
1941 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1945 edit_items.push_back (SeparatorElem());
1946 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1947 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1949 edit_items.push_back (SeparatorElem());
1950 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1952 edit_items.push_back (SeparatorElem());
1953 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1954 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1955 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1957 edit_items.push_back (SeparatorElem());
1958 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1960 edit_items.push_back (SeparatorElem());
1961 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1962 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1964 edit_items.push_back (SeparatorElem());
1965 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1966 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1967 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1968 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1969 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1970 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1971 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1977 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1979 using namespace Menu_Helpers;
1983 Menu *play_menu = manage (new Menu);
1984 MenuList& play_items = play_menu->items();
1985 play_menu->set_name ("ArdourContextMenu");
1987 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1988 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1989 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1990 play_items.push_back (SeparatorElem());
1991 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1993 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1997 Menu *select_menu = manage (new Menu);
1998 MenuList& select_items = select_menu->items();
1999 select_menu->set_name ("ArdourContextMenu");
2001 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2002 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2003 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2004 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2005 select_items.push_back (SeparatorElem());
2006 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2007 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2008 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2009 select_items.push_back (SeparatorElem());
2010 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2011 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2012 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2013 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2014 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2015 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2016 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2018 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2022 Menu *cutnpaste_menu = manage (new Menu);
2023 MenuList& cutnpaste_items = cutnpaste_menu->items();
2024 cutnpaste_menu->set_name ("ArdourContextMenu");
2026 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2027 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2028 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2030 cutnpaste_items.push_back (SeparatorElem());
2032 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2033 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2035 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2037 /* Adding new material */
2039 edit_items.push_back (SeparatorElem());
2040 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2041 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2045 Menu *nudge_menu = manage (new Menu());
2046 MenuList& nudge_items = nudge_menu->items();
2047 nudge_menu->set_name ("ArdourContextMenu");
2049 edit_items.push_back (SeparatorElem());
2050 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2051 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2052 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2053 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2055 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2059 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2061 using namespace Menu_Helpers;
2065 Menu *play_menu = manage (new Menu);
2066 MenuList& play_items = play_menu->items();
2067 play_menu->set_name ("ArdourContextMenu");
2069 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2070 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2071 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2075 Menu *select_menu = manage (new Menu);
2076 MenuList& select_items = select_menu->items();
2077 select_menu->set_name ("ArdourContextMenu");
2079 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2080 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2081 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2082 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2083 select_items.push_back (SeparatorElem());
2084 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2085 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2086 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2087 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2089 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2092 #if 0 // unused, why?
2093 Menu *cutnpaste_menu = manage (new Menu);
2094 MenuList& cutnpaste_items = cutnpaste_menu->items();
2095 cutnpaste_menu->set_name ("ArdourContextMenu");
2097 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2098 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2099 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2102 Menu *nudge_menu = manage (new Menu());
2103 MenuList& nudge_items = nudge_menu->items();
2104 nudge_menu->set_name ("ArdourContextMenu");
2106 edit_items.push_back (SeparatorElem());
2107 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2108 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2109 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2110 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2112 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2116 Editor::grid_type() const
2122 Editor::grid_musical() const
2124 switch (_grid_type) {
2125 case GridTypeBeatDiv32:
2126 case GridTypeBeatDiv28:
2127 case GridTypeBeatDiv24:
2128 case GridTypeBeatDiv20:
2129 case GridTypeBeatDiv16:
2130 case GridTypeBeatDiv14:
2131 case GridTypeBeatDiv12:
2132 case GridTypeBeatDiv10:
2133 case GridTypeBeatDiv8:
2134 case GridTypeBeatDiv7:
2135 case GridTypeBeatDiv6:
2136 case GridTypeBeatDiv5:
2137 case GridTypeBeatDiv4:
2138 case GridTypeBeatDiv3:
2139 case GridTypeBeatDiv2:
2144 case GridTypeTimecode:
2145 case GridTypeMinSec:
2146 case GridTypeCDFrame:
2153 Editor::grid_nonmusical() const
2155 switch (_grid_type) {
2156 case GridTypeTimecode:
2157 case GridTypeMinSec:
2158 case GridTypeCDFrame:
2160 case GridTypeBeatDiv32:
2161 case GridTypeBeatDiv28:
2162 case GridTypeBeatDiv24:
2163 case GridTypeBeatDiv20:
2164 case GridTypeBeatDiv16:
2165 case GridTypeBeatDiv14:
2166 case GridTypeBeatDiv12:
2167 case GridTypeBeatDiv10:
2168 case GridTypeBeatDiv8:
2169 case GridTypeBeatDiv7:
2170 case GridTypeBeatDiv6:
2171 case GridTypeBeatDiv5:
2172 case GridTypeBeatDiv4:
2173 case GridTypeBeatDiv3:
2174 case GridTypeBeatDiv2:
2183 Editor::snap_mode() const
2189 Editor::show_rulers_for_grid ()
2191 /* show appropriate rulers for this grid setting. */
2192 if (grid_musical()) {
2193 ruler_tempo_action->set_active(true);
2194 ruler_meter_action->set_active(true);
2195 ruler_bbt_action->set_active(true);
2197 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2198 ruler_timecode_action->set_active(false);
2199 ruler_minsec_action->set_active(false);
2200 ruler_samples_action->set_active(false);
2202 } else if (_grid_type == GridTypeTimecode) {
2203 ruler_timecode_action->set_active(true);
2205 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2206 ruler_tempo_action->set_active(false);
2207 ruler_meter_action->set_active(false);
2208 ruler_bbt_action->set_active(false);
2209 ruler_minsec_action->set_active(false);
2210 ruler_samples_action->set_active(false);
2212 } else if (_grid_type == GridTypeMinSec) {
2213 ruler_minsec_action->set_active(true);
2215 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2216 ruler_tempo_action->set_active(false);
2217 ruler_meter_action->set_active(false);
2218 ruler_bbt_action->set_active(false);
2219 ruler_timecode_action->set_active(false);
2220 ruler_samples_action->set_active(false);
2222 } else if (_grid_type == GridTypeCDFrame) {
2223 ruler_cd_marker_action->set_active(true);
2224 ruler_minsec_action->set_active(true);
2226 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2227 ruler_tempo_action->set_active(false);
2228 ruler_meter_action->set_active(false);
2229 ruler_bbt_action->set_active(false);
2230 ruler_timecode_action->set_active(false);
2231 ruler_samples_action->set_active(false);
2237 Editor::set_grid_to (GridType gt)
2239 if (_grid_type == gt) { // already set
2243 unsigned int grid_ind = (unsigned int)gt;
2245 if (internal_editing() && UIConfiguration::instance().get_grid_follows_internal()) {
2246 internal_grid_type = gt;
2248 pre_internal_grid_type = gt;
2253 if (grid_ind > grid_type_strings.size() - 1) {
2255 _grid_type = (GridType)grid_ind;
2258 string str = grid_type_strings[grid_ind];
2260 if (str != grid_type_selector.get_text()) {
2261 grid_type_selector.set_text (str);
2264 if (UIConfiguration::instance().get_show_grids_ruler()) {
2265 show_rulers_for_grid ();
2270 if (grid_musical()) {
2271 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2272 update_tempo_based_rulers ();
2275 mark_region_boundary_cache_dirty ();
2277 redisplay_grid (false);
2279 SnapChanged (); /* EMIT SIGNAL */
2283 Editor::set_snap_mode (SnapMode mode)
2285 if (internal_editing()) {
2286 internal_snap_mode = mode;
2288 pre_internal_snap_mode = mode;
2293 if (_snap_mode == SnapOff) {
2294 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2296 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2303 Editor::set_edit_point_preference (EditPoint ep, bool force)
2305 bool changed = (_edit_point != ep);
2308 if (Profile->get_mixbus())
2309 if (ep == EditAtSelectedMarker)
2310 ep = EditAtPlayhead;
2312 string str = edit_point_strings[(int)ep];
2313 if (str != edit_point_selector.get_text ()) {
2314 edit_point_selector.set_text (str);
2317 update_all_enter_cursors();
2319 if (!force && !changed) {
2323 const char* action=NULL;
2325 switch (_edit_point) {
2326 case EditAtPlayhead:
2327 action = "edit-at-playhead";
2329 case EditAtSelectedMarker:
2330 action = "edit-at-marker";
2333 action = "edit-at-mouse";
2337 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Editor", action);
2338 tact->set_active (true);
2341 bool in_track_canvas;
2343 if (!mouse_sample (foo, in_track_canvas)) {
2344 in_track_canvas = false;
2347 reset_canvas_action_sensitivity (in_track_canvas);
2348 sensitize_the_right_region_actions (false);
2354 Editor::set_state (const XMLNode& node, int version)
2357 PBD::Unwinder<bool> nsi (no_save_instant, true);
2360 Tabbable::set_state (node, version);
2363 if (_session && node.get_property ("playhead", ph_pos)) {
2365 playhead_cursor->set_position (ph_pos);
2367 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2368 playhead_cursor->set_position (0);
2371 playhead_cursor->set_position (0);
2374 node.get_property ("mixer-width", editor_mixer_strip_width);
2376 node.get_property ("zoom-focus", zoom_focus);
2377 zoom_focus_selection_done (zoom_focus);
2380 if (node.get_property ("zoom", z)) {
2381 /* older versions of ardour used floating point samples_per_pixel */
2382 reset_zoom (llrintf (z));
2384 reset_zoom (samples_per_pixel);
2388 if (node.get_property ("visible-track-count", cnt)) {
2389 set_visible_track_count (cnt);
2393 if (!node.get_property ("grid-type", grid_type)) {
2394 grid_type = _grid_type;
2396 set_grid_to (grid_type);
2399 if (node.get_property ("snap-mode", sm)) {
2400 snap_mode_selection_done(sm);
2401 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2402 * snap_mode_selection_done() will only mark an already active item as active
2403 * which does not trigger set_text().
2407 set_snap_mode (_snap_mode);
2410 node.get_property ("internal-grid-type", internal_grid_type);
2411 node.get_property ("internal-snap-mode", internal_snap_mode);
2412 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2413 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2416 if (node.get_property ("mouse-mode", mm_str)) {
2417 MouseMode m = str2mousemode(mm_str);
2418 set_mouse_mode (m, true);
2420 set_mouse_mode (MouseObject, true);
2424 if (node.get_property ("left-frame", lf_pos)) {
2428 reset_x_origin (lf_pos);
2432 if (node.get_property ("y-origin", y_origin)) {
2433 reset_y_origin (y_origin);
2437 node.get_property ("join-object-range", yn);
2439 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2440 /* do it twice to force the change */
2441 tact->set_active (!yn);
2442 tact->set_active (yn);
2443 set_mouse_mode(mouse_mode, true);
2447 if (node.get_property ("edit-point", ep)) {
2448 set_edit_point_preference (ep, true);
2450 set_edit_point_preference (_edit_point);
2453 if (node.get_property ("follow-playhead", yn)) {
2454 set_follow_playhead (yn);
2457 if (node.get_property ("stationary-playhead", yn)) {
2458 set_stationary_playhead (yn);
2461 RegionListSortType sort_type;
2462 if (node.get_property ("region-list-sort-type", sort_type)) {
2463 _regions->reset_sort_type (sort_type, true);
2467 node.get_property ("show-editor-mixer", yn);
2469 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2470 /* do it twice to force the change */
2471 tact->set_active (!yn);
2472 tact->set_active (yn);
2476 node.get_property ("show-editor-list", yn);
2478 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2479 /* do it twice to force the change */
2480 tact->set_active (!yn);
2481 tact->set_active (yn);
2485 if (node.get_property (X_("editor-list-page"), el_page)) {
2486 _the_notebook.set_current_page (el_page);
2490 node.get_property (X_("show-marker-lines"), yn);
2492 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-marker-lines"));
2493 /* do it twice to force the change */
2494 tact->set_active (!yn);
2495 tact->set_active (yn);
2498 XMLNodeList children = node.children ();
2499 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2500 selection->set_state (**i, Stateful::current_state_version);
2501 _regions->set_state (**i);
2502 _locations->set_state (**i);
2505 if (node.get_property ("maximised", yn)) {
2506 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalEditor"));
2507 bool fs = tact->get_active();
2509 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2513 samplepos_t nudge_clock_value;
2514 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2515 nudge_clock->set (nudge_clock_value);
2517 nudge_clock->set_mode (AudioClock::Timecode);
2518 nudge_clock->set (_session->sample_rate() * 5, true);
2523 * Not all properties may have been in XML, but
2524 * those that are linked to a private variable may need changing
2526 RefPtr<ToggleAction> tact;
2528 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
2529 yn = _follow_playhead;
2530 if (tact->get_active() != yn) {
2531 tact->set_active (yn);
2534 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
2535 yn = _stationary_playhead;
2536 if (tact->get_active() != yn) {
2537 tact->set_active (yn);
2545 Editor::get_state ()
2547 XMLNode* node = new XMLNode (X_("Editor"));
2549 node->set_property ("id", id().to_s ());
2551 node->add_child_nocopy (Tabbable::get_state());
2553 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2554 node->set_property("notebook-shrunk", _notebook_shrunk);
2555 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2557 maybe_add_mixer_strip_width (*node);
2559 node->set_property ("zoom-focus", zoom_focus);
2561 node->set_property ("zoom", samples_per_pixel);
2562 node->set_property ("grid-type", _grid_type);
2563 node->set_property ("snap-mode", _snap_mode);
2564 node->set_property ("internal-grid-type", internal_grid_type);
2565 node->set_property ("internal-snap-mode", internal_snap_mode);
2566 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2567 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2568 node->set_property ("edit-point", _edit_point);
2569 node->set_property ("visible-track-count", _visible_track_count);
2571 node->set_property ("playhead", playhead_cursor->current_sample ());
2572 node->set_property ("left-frame", _leftmost_sample);
2573 node->set_property ("y-origin", vertical_adjustment.get_value ());
2575 node->set_property ("maximised", _maximised);
2576 node->set_property ("follow-playhead", _follow_playhead);
2577 node->set_property ("stationary-playhead", _stationary_playhead);
2578 node->set_property ("region-list-sort-type", _regions->sort_type ());
2579 node->set_property ("mouse-mode", mouse_mode);
2580 node->set_property ("join-object-range", smart_mode_action->get_active ());
2582 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2583 node->set_property (X_("show-editor-mixer"), tact->get_active());
2585 tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2586 node->set_property (X_("show-editor-list"), tact->get_active());
2588 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2590 if (button_bindings) {
2591 XMLNode* bb = new XMLNode (X_("Buttons"));
2592 button_bindings->save (*bb);
2593 node->add_child_nocopy (*bb);
2596 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2598 node->add_child_nocopy (selection->get_state ());
2599 node->add_child_nocopy (_regions->get_state ());
2601 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2603 node->add_child_nocopy (_locations->get_state ());
2608 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2609 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2611 * @return pair: TimeAxisView that y is over, layer index.
2613 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2614 * in stacked or expanded region display mode, otherwise 0.
2616 std::pair<TimeAxisView *, double>
2617 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2619 if (!trackview_relative_offset) {
2620 y -= _trackview_group->canvas_origin().y;
2624 return std::make_pair ((TimeAxisView *) 0, 0);
2627 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2629 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2636 return std::make_pair ((TimeAxisView *) 0, 0);
2640 Editor::set_snapped_cursor_position (samplepos_t pos)
2642 if (_edit_point == EditAtMouse) {
2643 snapped_cursor->set_position(pos);
2648 /** Snap a position to the grid, if appropriate, taking into account current
2649 * grid settings and also the state of any snap modifier keys that may be pressed.
2650 * @param start Position to snap.
2651 * @param event Event to get current key modifier information from, or 0.
2654 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
2656 if (!_session || !event) {
2660 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2661 if (_snap_mode == SnapOff) {
2662 snap_to_internal (start, direction, pref);
2664 start.set (start.sample, 0);
2667 if (_snap_mode != SnapOff) {
2668 snap_to_internal (start, direction, pref);
2669 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2670 /* SnapOff, but we pressed the snap_delta modifier */
2671 snap_to_internal (start, direction, pref);
2673 start.set (start.sample, 0);
2679 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2681 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2682 start.set (start.sample, 0);
2686 snap_to_internal (start, direction, pref, ensure_snap);
2690 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2692 samplepos_t diff = abs (test - presnap);
2698 test = max_samplepos; // reset this so it doesn't get accidentally reused
2702 Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
2704 samplepos_t start = presnap.sample;
2705 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2706 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2708 TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
2711 case timecode_show_bits:
2712 case timecode_show_samples:
2713 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2714 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2715 /* start is already on a whole timecode frame, do nothing */
2716 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2717 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2719 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2723 case timecode_show_seconds:
2724 if (_session->config.get_timecode_offset_negative()) {
2725 start += _session->config.get_timecode_offset ();
2727 start -= _session->config.get_timecode_offset ();
2729 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2730 (start % one_timecode_second == 0)) {
2731 /* start is already on a whole second, do nothing */
2732 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2733 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2735 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2738 if (_session->config.get_timecode_offset_negative()) {
2739 start -= _session->config.get_timecode_offset ();
2741 start += _session->config.get_timecode_offset ();
2745 case timecode_show_minutes:
2746 case timecode_show_hours:
2747 case timecode_show_many_hours:
2748 if (_session->config.get_timecode_offset_negative()) {
2749 start += _session->config.get_timecode_offset ();
2751 start -= _session->config.get_timecode_offset ();
2753 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2754 (start % one_timecode_minute == 0)) {
2755 /* start is already on a whole minute, do nothing */
2756 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2757 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2759 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2761 if (_session->config.get_timecode_offset_negative()) {
2762 start -= _session->config.get_timecode_offset ();
2764 start += _session->config.get_timecode_offset ();
2768 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2771 MusicSample ret(start,0);
2776 Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
2778 MusicSample ret(presnap);
2780 const samplepos_t one_second = _session->sample_rate();
2781 const samplepos_t one_minute = one_second * 60;
2782 const samplepos_t one_hour = one_minute * 60;
2784 MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
2787 case minsec_show_msecs:
2788 case minsec_show_seconds: {
2789 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2790 presnap.sample % one_second == 0) {
2791 /* start is already on a whole second, do nothing */
2792 } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
2793 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
2795 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
2799 case minsec_show_minutes: {
2800 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2801 presnap.sample % one_minute == 0) {
2802 /* start is already on a whole minute, do nothing */
2803 } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2804 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
2806 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
2811 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2812 presnap.sample % one_hour == 0) {
2813 /* start is already on a whole hour, do nothing */
2814 } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
2815 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
2817 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
2826 Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
2828 if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
2829 return snap_to_minsec (presnap, direction, gpref);
2832 const samplepos_t one_second = _session->sample_rate();
2834 MusicSample ret(presnap);
2836 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2837 presnap.sample % (one_second/75) == 0) {
2838 /* start is already on a whole CD sample, do nothing */
2839 } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2840 ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2842 ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2849 Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
2851 MusicSample ret(presnap);
2853 if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
2856 switch (_grid_type) {
2857 case GridTypeBeatDiv3:
2858 case GridTypeBeatDiv6:
2859 case GridTypeBeatDiv12:
2860 case GridTypeBeatDiv24:
2863 case GridTypeBeatDiv5:
2864 case GridTypeBeatDiv10:
2865 case GridTypeBeatDiv20:
2868 case GridTypeBeatDiv7:
2869 case GridTypeBeatDiv14:
2870 case GridTypeBeatDiv28:
2877 BBTRulerScale scale = bbt_ruler_scale;
2884 ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
2886 case bbt_show_quarters:
2887 ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
2889 case bbt_show_eighths:
2890 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
2892 case bbt_show_sixteenths:
2893 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
2895 case bbt_show_thirtyseconds:
2896 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
2900 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
2907 Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
2909 MusicSample ret(presnap);
2911 if (grid_musical()) {
2912 ret = snap_to_bbt (presnap, direction, gpref);
2915 switch (_grid_type) {
2916 case GridTypeTimecode:
2917 ret = snap_to_timecode(presnap, direction, gpref);
2919 case GridTypeMinSec:
2920 ret = snap_to_minsec(presnap, direction, gpref);
2922 case GridTypeCDFrame:
2923 ret = snap_to_cd_frames(presnap, direction, gpref);
2933 Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
2939 _session->locations()->marks_either_side (presnap, before, after);
2941 if (before == max_samplepos && after == max_samplepos) {
2942 /* No marks to snap to, so just don't snap */
2944 } else if (before == max_samplepos) {
2946 } else if (after == max_samplepos) {
2949 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2951 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2953 } else if (direction == 0) {
2954 if ((presnap - before) < (after - presnap)) {
2966 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2968 const samplepos_t presnap = start.sample;
2970 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2971 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2972 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2974 /* check snap-to-marker */
2975 if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
2976 test = snap_to_marker (presnap, direction);
2977 check_best_snap(presnap, test, dist, best);
2980 /* check snap-to-region-{start/end/sync} */
2982 (pref == SnapToAny_Visual) &&
2983 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
2985 if (!region_boundary_cache.empty()) {
2987 vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
2988 vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2989 if (next != region_boundary_cache.begin ()) {
2994 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2996 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2998 else if (direction == 0) {
2999 if ((presnap - *prev) < (*next - presnap)) {
3008 check_best_snap(presnap, test, dist, best);
3012 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
3013 MusicSample pre(presnap, 0);
3014 MusicSample post = snap_to_grid (pre, direction, pref);
3015 check_best_snap(presnap, post.sample, dist, best);
3018 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
3019 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
3020 * ToDo: Perhaps this should only occur if EditPointMouse?
3022 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
3024 start.set (best, 0);
3026 } else if (presnap > best) {
3027 if (presnap > (best+ snap_threshold_s)) {
3030 } else if (presnap < best) {
3031 if (presnap < (best - snap_threshold_s)) {
3036 start.set (best, 0);
3041 Editor::setup_toolbar ()
3043 HBox* mode_box = manage(new HBox);
3044 mode_box->set_border_width (2);
3045 mode_box->set_spacing(2);
3047 HBox* mouse_mode_box = manage (new HBox);
3048 HBox* mouse_mode_hbox = manage (new HBox);
3049 VBox* mouse_mode_vbox = manage (new VBox);
3050 Alignment* mouse_mode_align = manage (new Alignment);
3052 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3053 mouse_mode_size_group->add_widget (smart_mode_button);
3054 mouse_mode_size_group->add_widget (mouse_move_button);
3055 mouse_mode_size_group->add_widget (mouse_cut_button);
3056 mouse_mode_size_group->add_widget (mouse_select_button);
3057 mouse_mode_size_group->add_widget (mouse_timefx_button);
3058 mouse_mode_size_group->add_widget (mouse_audition_button);
3059 mouse_mode_size_group->add_widget (mouse_draw_button);
3060 mouse_mode_size_group->add_widget (mouse_content_button);
3062 if (!Profile->get_mixbus()) {
3063 mouse_mode_size_group->add_widget (zoom_in_button);
3064 mouse_mode_size_group->add_widget (zoom_out_button);
3065 mouse_mode_size_group->add_widget (zoom_out_full_button);
3066 mouse_mode_size_group->add_widget (zoom_focus_selector);
3067 mouse_mode_size_group->add_widget (tav_shrink_button);
3068 mouse_mode_size_group->add_widget (tav_expand_button);
3070 mouse_mode_size_group->add_widget (zoom_preset_selector);
3071 mouse_mode_size_group->add_widget (visible_tracks_selector);
3074 mouse_mode_size_group->add_widget (grid_type_selector);
3075 mouse_mode_size_group->add_widget (snap_mode_button);
3077 mouse_mode_size_group->add_widget (edit_point_selector);
3078 mouse_mode_size_group->add_widget (edit_mode_selector);
3080 mouse_mode_size_group->add_widget (*nudge_clock);
3081 mouse_mode_size_group->add_widget (nudge_forward_button);
3082 mouse_mode_size_group->add_widget (nudge_backward_button);
3084 mouse_mode_hbox->set_spacing (2);
3086 if (!ARDOUR::Profile->get_trx()) {
3087 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3090 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3091 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3093 if (!ARDOUR::Profile->get_mixbus()) {
3094 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3095 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3098 if (!ARDOUR::Profile->get_trx()) {
3099 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3100 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3101 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3104 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3106 mouse_mode_align->add (*mouse_mode_vbox);
3107 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3109 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3111 edit_mode_selector.set_name ("mouse mode button");
3113 if (!ARDOUR::Profile->get_trx()) {
3114 mode_box->pack_start (edit_mode_selector, false, false);
3115 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3116 mode_box->pack_start (edit_point_selector, false, false);
3117 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3120 mode_box->pack_start (*mouse_mode_box, false, false);
3124 _zoom_box.set_spacing (2);
3125 _zoom_box.set_border_width (2);
3129 zoom_preset_selector.set_name ("zoom button");
3130 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3132 zoom_in_button.set_name ("zoom button");
3133 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3134 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3135 zoom_in_button.set_related_action (act);
3137 zoom_out_button.set_name ("zoom button");
3138 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3139 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3140 zoom_out_button.set_related_action (act);
3142 zoom_out_full_button.set_name ("zoom button");
3143 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3144 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3145 zoom_out_full_button.set_related_action (act);
3147 zoom_focus_selector.set_name ("zoom button");
3149 if (ARDOUR::Profile->get_mixbus()) {
3150 _zoom_box.pack_start (zoom_preset_selector, false, false);
3151 } else if (ARDOUR::Profile->get_trx()) {
3152 mode_box->pack_start (zoom_out_button, false, false);
3153 mode_box->pack_start (zoom_in_button, false, false);
3155 _zoom_box.pack_start (zoom_out_button, false, false);
3156 _zoom_box.pack_start (zoom_in_button, false, false);
3157 _zoom_box.pack_start (zoom_out_full_button, false, false);
3158 _zoom_box.pack_start (zoom_focus_selector, false, false);
3161 /* Track zoom buttons */
3162 _track_box.set_spacing (2);
3163 _track_box.set_border_width (2);
3165 visible_tracks_selector.set_name ("zoom button");
3166 if (Profile->get_mixbus()) {
3167 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3169 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3172 tav_expand_button.set_name ("zoom button");
3173 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3174 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3175 tav_expand_button.set_related_action (act);
3177 tav_shrink_button.set_name ("zoom button");
3178 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3179 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3180 tav_shrink_button.set_related_action (act);
3182 if (ARDOUR::Profile->get_mixbus()) {
3183 _track_box.pack_start (visible_tracks_selector);
3184 } else if (ARDOUR::Profile->get_trx()) {
3185 _track_box.pack_start (tav_shrink_button);
3186 _track_box.pack_start (tav_expand_button);
3188 _track_box.pack_start (visible_tracks_selector);
3189 _track_box.pack_start (tav_shrink_button);
3190 _track_box.pack_start (tav_expand_button);
3193 snap_box.set_spacing (2);
3194 snap_box.set_border_width (2);
3196 grid_type_selector.set_name ("mouse mode button");
3198 snap_mode_button.set_name ("mouse mode button");
3200 edit_point_selector.set_name ("mouse mode button");
3202 snap_box.pack_start (snap_mode_button, false, false);
3203 snap_box.pack_start (grid_type_selector, false, false);
3207 HBox *nudge_box = manage (new HBox);
3208 nudge_box->set_spacing (2);
3209 nudge_box->set_border_width (2);
3211 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3212 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3214 nudge_box->pack_start (nudge_backward_button, false, false);
3215 nudge_box->pack_start (nudge_forward_button, false, false);
3216 nudge_box->pack_start (*nudge_clock, false, false);
3219 /* Pack everything in... */
3221 toolbar_hbox.set_spacing (2);
3222 toolbar_hbox.set_border_width (2);
3224 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3225 tool_shadow->set_size_request (4, -1);
3226 tool_shadow->show();
3228 ebox_hpacker.pack_start (*tool_shadow, false, false);
3229 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3231 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3232 spacer->set_name("EditorWindow");
3233 spacer->set_size_request(-1,4);
3236 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3237 ebox_vpacker.pack_start(*spacer, false, false);
3238 ebox_vpacker.show();
3240 toolbar_hbox.pack_start (*mode_box, false, false);
3242 if (!ARDOUR::Profile->get_trx()) {
3244 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3246 toolbar_hbox.pack_start (snap_box, false, false);
3248 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3250 toolbar_hbox.pack_start (*nudge_box, false, false);
3252 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3254 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3256 toolbar_hbox.pack_end (_track_box, false, false);
3260 toolbar_hbox.show_all ();
3264 Editor::build_edit_point_menu ()
3266 using namespace Menu_Helpers;
3268 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3269 if(!Profile->get_mixbus())
3270 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3271 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3273 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3277 Editor::build_edit_mode_menu ()
3279 using namespace Menu_Helpers;
3281 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3282 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3283 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3284 /* Note: Splice was removed */
3286 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3290 Editor::build_grid_type_menu ()
3292 using namespace Menu_Helpers;
3294 /* main grid: bars, quarter-notes, etc */
3295 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3296 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3297 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3298 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3299 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3300 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3301 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3302 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3305 grid_type_selector.AddMenuElem(SeparatorElem());
3306 Gtk::Menu *_triplet_menu = manage (new Menu);
3307 MenuList& triplet_items (_triplet_menu->items());
3309 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3310 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3311 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3312 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3314 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3316 /* quintuplet grid */
3317 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3318 MenuList& quintuplet_items (_quintuplet_menu->items());
3320 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3321 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3322 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3324 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3326 /* septuplet grid */
3327 Gtk::Menu *_septuplet_menu = manage (new Menu);
3328 MenuList& septuplet_items (_septuplet_menu->items());
3330 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3331 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3332 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3334 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3336 grid_type_selector.AddMenuElem(SeparatorElem());
3337 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3338 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3339 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3343 Editor::setup_tooltips ()
3345 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3346 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3347 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3348 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3349 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3350 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3351 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3352 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3353 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3354 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3355 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3356 set_tooltip (zoom_in_button, _("Zoom In"));
3357 set_tooltip (zoom_out_button, _("Zoom Out"));
3358 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3359 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3360 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3361 set_tooltip (tav_expand_button, _("Expand Tracks"));
3362 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3363 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3364 set_tooltip (grid_type_selector, _("Grid Mode"));
3365 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3366 set_tooltip (edit_point_selector, _("Edit Point"));
3367 set_tooltip (edit_mode_selector, _("Edit Mode"));
3368 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3372 Editor::convert_drop_to_paths (
3373 vector<string>& paths,
3374 const RefPtr<Gdk::DragContext>& /*context*/,
3377 const SelectionData& data,
3381 if (_session == 0) {
3385 vector<string> uris = data.get_uris();
3389 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3390 are actually URI lists. So do it by hand.
3393 if (data.get_target() != "text/plain") {
3397 /* Parse the "uri-list" format that Nautilus provides,
3398 where each pathname is delimited by \r\n.
3400 THERE MAY BE NO NULL TERMINATING CHAR!!!
3403 string txt = data.get_text();
3407 p = (char *) malloc (txt.length() + 1);
3408 txt.copy (p, txt.length(), 0);
3409 p[txt.length()] = '\0';
3415 while (g_ascii_isspace (*p))
3419 while (*q && (*q != '\n') && (*q != '\r')) {
3426 while (q > p && g_ascii_isspace (*q))
3431 uris.push_back (string (p, q - p + 1));
3435 p = strchr (p, '\n');
3447 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3448 if ((*i).substr (0,7) == "file://") {
3449 paths.push_back (Glib::filename_from_uri (*i));
3457 Editor::new_tempo_section ()
3462 Editor::map_transport_state ()
3464 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3466 if (_session && _session->transport_stopped()) {
3467 have_pending_keyboard_selection = false;
3470 update_loop_range_view ();
3474 Editor::transport_looped ()
3476 /* reset Playhead position interpolation.
3477 * see Editor::super_rapid_screen_update
3479 _last_update_time = 0;
3485 Editor::begin_selection_op_history ()
3487 selection_op_cmd_depth = 0;
3488 selection_op_history_it = 0;
3490 while(!selection_op_history.empty()) {
3491 delete selection_op_history.front();
3492 selection_op_history.pop_front();
3495 selection_undo_action->set_sensitive (false);
3496 selection_redo_action->set_sensitive (false);
3497 selection_op_history.push_front (&_selection_memento->get_state ());
3501 Editor::begin_reversible_selection_op (string name)
3504 //cerr << name << endl;
3505 /* begin/commit pairs can be nested */
3506 selection_op_cmd_depth++;
3511 Editor::commit_reversible_selection_op ()
3514 if (selection_op_cmd_depth == 1) {
3516 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3517 /* The user has undone some selection ops and then made a new one,
3518 * making anything earlier in the list invalid.
3521 list<XMLNode *>::iterator it = selection_op_history.begin();
3522 list<XMLNode *>::iterator e_it = it;
3523 advance (e_it, selection_op_history_it);
3525 for (; it != e_it; ++it) {
3528 selection_op_history.erase (selection_op_history.begin(), e_it);
3531 selection_op_history.push_front (&_selection_memento->get_state ());
3532 selection_op_history_it = 0;
3534 selection_undo_action->set_sensitive (true);
3535 selection_redo_action->set_sensitive (false);
3538 if (selection_op_cmd_depth > 0) {
3539 selection_op_cmd_depth--;
3545 Editor::undo_selection_op ()
3548 selection_op_history_it++;
3550 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3551 if (n == selection_op_history_it) {
3552 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3553 selection_redo_action->set_sensitive (true);
3557 /* is there an earlier entry? */
3558 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3559 selection_undo_action->set_sensitive (false);
3565 Editor::redo_selection_op ()
3568 if (selection_op_history_it > 0) {
3569 selection_op_history_it--;
3572 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3573 if (n == selection_op_history_it) {
3574 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3575 selection_undo_action->set_sensitive (true);
3580 if (selection_op_history_it == 0) {
3581 selection_redo_action->set_sensitive (false);
3587 Editor::begin_reversible_command (string name)
3590 before.push_back (&_selection_memento->get_state ());
3591 _session->begin_reversible_command (name);
3596 Editor::begin_reversible_command (GQuark q)
3599 before.push_back (&_selection_memento->get_state ());
3600 _session->begin_reversible_command (q);
3605 Editor::abort_reversible_command ()
3608 while(!before.empty()) {
3609 delete before.front();
3612 _session->abort_reversible_command ();
3617 Editor::commit_reversible_command ()
3620 if (before.size() == 1) {
3621 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3622 redo_action->set_sensitive(false);
3623 undo_action->set_sensitive(true);
3624 begin_selection_op_history ();
3627 if (before.empty()) {
3628 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3633 _session->commit_reversible_command ();
3638 Editor::history_changed ()
3642 if (undo_action && _session) {
3643 if (_session->undo_depth() == 0) {
3644 label = S_("Command|Undo");
3646 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3648 undo_action->property_label() = label;
3651 if (redo_action && _session) {
3652 if (_session->redo_depth() == 0) {
3654 redo_action->set_sensitive (false);
3656 label = string_compose(_("Redo (%1)"), _session->next_redo());
3657 redo_action->set_sensitive (true);
3659 redo_action->property_label() = label;
3664 Editor::duplicate_range (bool with_dialog)
3668 RegionSelection rs = get_regions_from_selection_and_entered ();
3670 if (selection->time.length() == 0 && rs.empty()) {
3676 ArdourDialog win (_("Duplicate"));
3677 Label label (_("Number of duplications:"));
3678 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3679 SpinButton spinner (adjustment, 0.0, 1);
3682 win.get_vbox()->set_spacing (12);
3683 win.get_vbox()->pack_start (hbox);
3684 hbox.set_border_width (6);
3685 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3687 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3688 place, visually. so do this by hand.
3691 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3692 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3693 spinner.grab_focus();
3699 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3700 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3701 win.set_default_response (RESPONSE_ACCEPT);
3703 spinner.grab_focus ();
3705 switch (win.run ()) {
3706 case RESPONSE_ACCEPT:
3712 times = adjustment.get_value();
3715 if ((current_mouse_mode() == MouseRange)) {
3716 if (selection->time.length()) {
3717 duplicate_selection (times);
3719 } else if (get_smart_mode()) {
3720 if (selection->time.length()) {
3721 duplicate_selection (times);
3723 duplicate_some_regions (rs, times);
3725 duplicate_some_regions (rs, times);
3730 Editor::set_edit_mode (EditMode m)
3732 Config->set_edit_mode (m);
3736 Editor::cycle_edit_mode ()
3738 switch (Config->get_edit_mode()) {
3740 Config->set_edit_mode (Ripple);
3744 Config->set_edit_mode (Lock);
3747 Config->set_edit_mode (Slide);
3753 Editor::edit_mode_selection_done (EditMode m)
3755 Config->set_edit_mode (m);
3759 Editor::grid_type_selection_done (GridType gridtype)
3761 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3763 ract->set_active ();
3768 Editor::snap_mode_selection_done (SnapMode mode)
3770 RefPtr<RadioAction> ract = snap_mode_action (mode);
3773 ract->set_active (true);
3778 Editor::cycle_edit_point (bool with_marker)
3780 if(Profile->get_mixbus())
3781 with_marker = false;
3783 switch (_edit_point) {
3785 set_edit_point_preference (EditAtPlayhead);
3787 case EditAtPlayhead:
3789 set_edit_point_preference (EditAtSelectedMarker);
3791 set_edit_point_preference (EditAtMouse);
3794 case EditAtSelectedMarker:
3795 set_edit_point_preference (EditAtMouse);
3801 Editor::edit_point_selection_done (EditPoint ep)
3803 set_edit_point_preference (ep);
3807 Editor::build_zoom_focus_menu ()
3809 using namespace Menu_Helpers;
3811 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3812 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3813 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3814 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3815 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3816 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3818 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3822 Editor::zoom_focus_selection_done (ZoomFocus f)
3824 RefPtr<RadioAction> ract = zoom_focus_action (f);
3826 ract->set_active ();
3831 Editor::build_track_count_menu ()
3833 using namespace Menu_Helpers;
3835 if (!Profile->get_mixbus()) {
3836 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3837 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3838 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3839 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3840 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3841 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3842 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3843 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3844 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3845 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3846 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3847 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3848 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3850 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3851 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3852 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3853 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3854 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3855 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3856 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3857 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3858 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3859 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3861 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3862 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3863 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3864 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3865 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3866 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3867 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3868 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3869 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3870 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3871 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3872 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3877 Editor::set_zoom_preset (int64_t ms)
3880 temporal_zoom_session();
3884 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3885 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3889 Editor::set_visible_track_count (int32_t n)
3891 _visible_track_count = n;
3893 /* if the canvas hasn't really been allocated any size yet, just
3894 record the desired number of visible tracks and return. when canvas
3895 allocation happens, we will get called again and then we can do the
3899 if (_visible_canvas_height <= 1) {
3905 DisplaySuspender ds;
3907 if (_visible_track_count > 0) {
3908 h = trackviews_height() / _visible_track_count;
3909 std::ostringstream s;
3910 s << _visible_track_count;
3912 } else if (_visible_track_count == 0) {
3914 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3915 if ((*i)->marked_for_display()) {
3917 TimeAxisView::Children cl ((*i)->get_child_list ());
3918 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3919 if ((*j)->marked_for_display()) {
3926 visible_tracks_selector.set_text (X_("*"));
3929 h = trackviews_height() / n;
3932 /* negative value means that the visible track count has
3933 been overridden by explicit track height changes.
3935 visible_tracks_selector.set_text (X_("*"));
3939 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3940 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3943 if (str != visible_tracks_selector.get_text()) {
3944 visible_tracks_selector.set_text (str);
3949 Editor::override_visible_track_count ()
3951 _visible_track_count = -1;
3952 visible_tracks_selector.set_text (_("*"));
3956 Editor::edit_controls_button_release (GdkEventButton* ev)
3958 if (Keyboard::is_context_menu_event (ev)) {
3959 ARDOUR_UI::instance()->add_route ();
3960 } else if (ev->button == 1) {
3961 selection->clear_tracks ();
3968 Editor::mouse_select_button_release (GdkEventButton* ev)
3970 /* this handles just right-clicks */
3972 if (ev->button != 3) {
3980 Editor::set_zoom_focus (ZoomFocus f)
3982 string str = zoom_focus_strings[(int)f];
3984 if (str != zoom_focus_selector.get_text()) {
3985 zoom_focus_selector.set_text (str);
3988 if (zoom_focus != f) {
3995 Editor::cycle_zoom_focus ()
3997 switch (zoom_focus) {
3999 set_zoom_focus (ZoomFocusRight);
4001 case ZoomFocusRight:
4002 set_zoom_focus (ZoomFocusCenter);
4004 case ZoomFocusCenter:
4005 set_zoom_focus (ZoomFocusPlayhead);
4007 case ZoomFocusPlayhead:
4008 set_zoom_focus (ZoomFocusMouse);
4010 case ZoomFocusMouse:
4011 set_zoom_focus (ZoomFocusEdit);
4014 set_zoom_focus (ZoomFocusLeft);
4020 Editor::update_grid ()
4022 if (grid_musical()) {
4023 std::vector<TempoMap::BBTPoint> grid;
4024 if (bbt_ruler_scale != bbt_show_many) {
4025 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
4027 maybe_draw_grid_lines ();
4028 } else if (grid_nonmusical()) {
4029 maybe_draw_grid_lines ();
4036 Editor::toggle_follow_playhead ()
4038 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
4039 set_follow_playhead (tact->get_active());
4042 /** @param yn true to follow playhead, otherwise false.
4043 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4046 Editor::set_follow_playhead (bool yn, bool catch_up)
4048 if (_follow_playhead != yn) {
4049 if ((_follow_playhead = yn) == true && catch_up) {
4051 reset_x_origin_to_follow_playhead ();
4058 Editor::toggle_stationary_playhead ()
4060 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
4061 set_stationary_playhead (tact->get_active());
4065 Editor::set_stationary_playhead (bool yn)
4067 if (_stationary_playhead != yn) {
4068 if ((_stationary_playhead = yn) == true) {
4069 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
4070 // update_current_screen ();
4077 Editor::playlist_selector () const
4079 return *_playlist_selector;
4083 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4085 if (paste_count == 0) {
4086 /* don't bother calculating an offset that will be zero anyway */
4090 /* calculate basic unsnapped multi-paste offset */
4091 samplecnt_t offset = paste_count * duration;
4093 /* snap offset so pos + offset is aligned to the grid */
4094 MusicSample offset_pos (pos + offset, 0);
4095 snap_to(offset_pos, RoundUpMaybe);
4096 offset = offset_pos.sample - pos;
4102 Editor::get_grid_beat_divisions(samplepos_t position)
4104 switch (_grid_type) {
4105 case GridTypeBeatDiv32: return 32;
4106 case GridTypeBeatDiv28: return 28;
4107 case GridTypeBeatDiv24: return 24;
4108 case GridTypeBeatDiv20: return 20;
4109 case GridTypeBeatDiv16: return 16;
4110 case GridTypeBeatDiv14: return 14;
4111 case GridTypeBeatDiv12: return 12;
4112 case GridTypeBeatDiv10: return 10;
4113 case GridTypeBeatDiv8: return 8;
4114 case GridTypeBeatDiv7: return 7;
4115 case GridTypeBeatDiv6: return 6;
4116 case GridTypeBeatDiv5: return 5;
4117 case GridTypeBeatDiv4: return 4;
4118 case GridTypeBeatDiv3: return 3;
4119 case GridTypeBeatDiv2: return 2;
4120 case GridTypeBeat: return 1;
4121 case GridTypeBar: return 1;
4123 case GridTypeNone: return 0;
4124 case GridTypeTimecode: return 0;
4125 case GridTypeMinSec: return 0;
4126 case GridTypeCDFrame: return 0;
4132 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4133 if the grid is non-musical, returns 0.
4134 if the grid is snapped to bars, returns -1.
4135 @param event_state the current keyboard modifier mask.
4138 Editor::get_grid_music_divisions (uint32_t event_state)
4140 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4144 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4148 switch (_grid_type) {
4149 case GridTypeBeatDiv32: return 32;
4150 case GridTypeBeatDiv28: return 28;
4151 case GridTypeBeatDiv24: return 24;
4152 case GridTypeBeatDiv20: return 20;
4153 case GridTypeBeatDiv16: return 16;
4154 case GridTypeBeatDiv14: return 14;
4155 case GridTypeBeatDiv12: return 12;
4156 case GridTypeBeatDiv10: return 10;
4157 case GridTypeBeatDiv8: return 8;
4158 case GridTypeBeatDiv7: return 7;
4159 case GridTypeBeatDiv6: return 6;
4160 case GridTypeBeatDiv5: return 5;
4161 case GridTypeBeatDiv4: return 4;
4162 case GridTypeBeatDiv3: return 3;
4163 case GridTypeBeatDiv2: return 2;
4164 case GridTypeBeat: return 1;
4165 case GridTypeBar : return -1;
4167 case GridTypeNone: return 0;
4168 case GridTypeTimecode: return 0;
4169 case GridTypeMinSec: return 0;
4170 case GridTypeCDFrame: return 0;
4176 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4180 const unsigned divisions = get_grid_beat_divisions(position);
4182 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4185 switch (_grid_type) {
4187 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4190 const Meter& m = _session->tempo_map().meter_at_sample (position);
4191 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4199 return Temporal::Beats();
4203 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4207 ret = nudge_clock->current_duration (pos);
4208 next = ret + 1; /* XXXX fix me */
4214 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4216 ArdourDialog dialog (_("Playlist Deletion"));
4217 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4218 "If it is kept, its audio files will not be cleaned.\n"
4219 "If it is deleted, audio files used by it alone will be cleaned."),
4222 dialog.set_position (WIN_POS_CENTER);
4223 dialog.get_vbox()->pack_start (label);
4227 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4228 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4229 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4230 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4231 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4233 /* by default gtk uses the left most button */
4234 keep->grab_focus ();
4236 switch (dialog.run ()) {
4238 /* keep this and all remaining ones */
4243 /* delete this and all others */
4247 case RESPONSE_ACCEPT:
4248 /* delete the playlist */
4252 case RESPONSE_REJECT:
4253 /* keep the playlist */
4265 Editor::audio_region_selection_covers (samplepos_t where)
4267 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4268 if ((*a)->region()->covers (where)) {
4277 Editor::prepare_for_cleanup ()
4279 cut_buffer->clear_regions ();
4280 cut_buffer->clear_playlists ();
4282 selection->clear_regions ();
4283 selection->clear_playlists ();
4285 _regions->suspend_redisplay ();
4289 Editor::finish_cleanup ()
4291 _regions->resume_redisplay ();
4295 Editor::transport_loop_location()
4298 return _session->locations()->auto_loop_location();
4305 Editor::transport_punch_location()
4308 return _session->locations()->auto_punch_location();
4315 Editor::control_layout_scroll (GdkEventScroll* ev)
4317 /* Just forward to the normal canvas scroll method. The coordinate
4318 systems are different but since the canvas is always larger than the
4319 track headers, and aligned with the trackview area, this will work.
4321 In the not too distant future this layout is going away anyway and
4322 headers will be on the canvas.
4324 return canvas_scroll_event (ev, false);
4328 Editor::session_state_saved (string)
4331 _snapshots->redisplay ();
4335 Editor::maximise_editing_space ()
4341 Gtk::Window* toplevel = current_toplevel();
4344 toplevel->fullscreen ();
4350 Editor::restore_editing_space ()
4356 Gtk::Window* toplevel = current_toplevel();
4359 toplevel->unfullscreen();
4365 * Make new playlists for a given track and also any others that belong
4366 * to the same active route group with the `select' property.
4371 Editor::new_playlists (TimeAxisView* v)
4373 begin_reversible_command (_("new playlists"));
4374 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4375 _session->playlists()->get (playlists);
4376 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4377 commit_reversible_command ();
4381 * Use a copy of the current playlist for a given track and also any others that belong
4382 * to the same active route group with the `select' property.
4387 Editor::copy_playlists (TimeAxisView* v)
4389 begin_reversible_command (_("copy playlists"));
4390 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4391 _session->playlists()->get (playlists);
4392 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4393 commit_reversible_command ();
4396 /** Clear the current playlist for a given track and also any others that belong
4397 * to the same active route group with the `select' property.
4402 Editor::clear_playlists (TimeAxisView* v)
4404 begin_reversible_command (_("clear playlists"));
4405 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4406 _session->playlists()->get (playlists);
4407 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4408 commit_reversible_command ();
4412 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4414 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4418 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4420 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4424 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4426 atv.clear_playlist ();
4430 Editor::get_y_origin () const
4432 return vertical_adjustment.get_value ();
4435 /** Queue up a change to the viewport x origin.
4436 * @param sample New x origin.
4439 Editor::reset_x_origin (samplepos_t sample)
4441 pending_visual_change.add (VisualChange::TimeOrigin);
4442 pending_visual_change.time_origin = sample;
4443 ensure_visual_change_idle_handler ();
4447 Editor::reset_y_origin (double y)
4449 pending_visual_change.add (VisualChange::YOrigin);
4450 pending_visual_change.y_origin = y;
4451 ensure_visual_change_idle_handler ();
4455 Editor::reset_zoom (samplecnt_t spp)
4457 if (spp == samples_per_pixel) {
4461 pending_visual_change.add (VisualChange::ZoomLevel);
4462 pending_visual_change.samples_per_pixel = spp;
4463 ensure_visual_change_idle_handler ();
4467 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4469 reset_x_origin (sample);
4472 if (!no_save_visual) {
4473 undo_visual_stack.push_back (current_visual_state(false));
4477 Editor::VisualState::VisualState (bool with_tracks)
4478 : gui_state (with_tracks ? new GUIObjectState : 0)
4482 Editor::VisualState::~VisualState ()
4487 Editor::VisualState*
4488 Editor::current_visual_state (bool with_tracks)
4490 VisualState* vs = new VisualState (with_tracks);
4491 vs->y_position = vertical_adjustment.get_value();
4492 vs->samples_per_pixel = samples_per_pixel;
4493 vs->_leftmost_sample = _leftmost_sample;
4494 vs->zoom_focus = zoom_focus;
4497 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4504 Editor::undo_visual_state ()
4506 if (undo_visual_stack.empty()) {
4510 VisualState* vs = undo_visual_stack.back();
4511 undo_visual_stack.pop_back();
4514 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4517 use_visual_state (*vs);
4522 Editor::redo_visual_state ()
4524 if (redo_visual_stack.empty()) {
4528 VisualState* vs = redo_visual_stack.back();
4529 redo_visual_stack.pop_back();
4531 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4532 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4535 use_visual_state (*vs);
4540 Editor::swap_visual_state ()
4542 if (undo_visual_stack.empty()) {
4543 redo_visual_state ();
4545 undo_visual_state ();
4550 Editor::use_visual_state (VisualState& vs)
4552 PBD::Unwinder<bool> nsv (no_save_visual, true);
4553 DisplaySuspender ds;
4555 vertical_adjustment.set_value (vs.y_position);
4557 set_zoom_focus (vs.zoom_focus);
4558 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4561 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4563 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4564 (*i)->clear_property_cache();
4565 (*i)->reset_visual_state ();
4569 _routes->update_visibility ();
4572 /** This is the core function that controls the zoom level of the canvas. It is called
4573 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4574 * @param spp new number of samples per pixel
4577 Editor::set_samples_per_pixel (samplecnt_t spp)
4583 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4584 const samplecnt_t lots_of_pixels = 4000;
4586 /* if the zoom level is greater than what you'd get trying to display 3
4587 * days of audio on a really big screen, then it's too big.
4590 if (spp * lots_of_pixels > three_days) {
4594 samples_per_pixel = spp;
4598 Editor::on_samples_per_pixel_changed ()
4600 bool const showing_time_selection = selection->time.length() > 0;
4602 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4603 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4604 (*i)->reshow_selection (selection->time);
4608 ZoomChanged (); /* EMIT_SIGNAL */
4610 ArdourCanvas::GtkCanvasViewport* c;
4612 c = get_track_canvas();
4614 c->canvas()->zoomed ();
4617 if (playhead_cursor) {
4618 playhead_cursor->set_position (playhead_cursor->current_sample ());
4621 refresh_location_display();
4622 _summary->set_overlays_dirty ();
4624 update_marker_labels ();
4630 Editor::playhead_cursor_sample () const
4632 return playhead_cursor->current_sample();
4636 Editor::queue_visual_videotimeline_update ()
4638 pending_visual_change.add (VisualChange::VideoTimeline);
4639 ensure_visual_change_idle_handler ();
4643 Editor::ensure_visual_change_idle_handler ()
4645 if (pending_visual_change.idle_handler_id < 0) {
4646 /* see comment in add_to_idle_resize above. */
4647 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4648 pending_visual_change.being_handled = false;
4653 Editor::_idle_visual_changer (void* arg)
4655 return static_cast<Editor*>(arg)->idle_visual_changer ();
4659 Editor::pre_render ()
4661 visual_change_queued = false;
4663 if (pending_visual_change.pending != 0) {
4664 ensure_visual_change_idle_handler();
4669 Editor::idle_visual_changer ()
4671 pending_visual_change.idle_handler_id = -1;
4673 if (pending_visual_change.pending == 0) {
4677 /* set_horizontal_position() below (and maybe other calls) call
4678 gtk_main_iteration(), so it's possible that a signal will be handled
4679 half-way through this method. If this signal wants an
4680 idle_visual_changer we must schedule another one after this one, so
4681 mark the idle_handler_id as -1 here to allow that. Also make a note
4682 that we are doing the visual change, so that changes in response to
4683 super-rapid-screen-update can be dropped if we are still processing
4687 if (visual_change_queued) {
4691 pending_visual_change.being_handled = true;
4693 VisualChange vc = pending_visual_change;
4695 pending_visual_change.pending = (VisualChange::Type) 0;
4697 visual_changer (vc);
4699 pending_visual_change.being_handled = false;
4701 visual_change_queued = true;
4703 return 0; /* this is always a one-shot call */
4707 Editor::visual_changer (const VisualChange& vc)
4710 * Changed first so the correct horizontal canvas position is calculated in
4711 * Editor::set_horizontal_position
4713 if (vc.pending & VisualChange::ZoomLevel) {
4714 set_samples_per_pixel (vc.samples_per_pixel);
4717 if (vc.pending & VisualChange::TimeOrigin) {
4718 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4719 set_horizontal_position (new_time_origin);
4722 if (vc.pending & VisualChange::YOrigin) {
4723 vertical_adjustment.set_value (vc.y_origin);
4727 * Now the canvas is in the final state before render the canvas items that
4728 * support the Item::prepare_for_render interface can calculate the correct
4729 * item to visible canvas intersection.
4731 if (vc.pending & VisualChange::ZoomLevel) {
4732 on_samples_per_pixel_changed ();
4734 compute_fixed_ruler_scale ();
4736 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4737 update_tempo_based_rulers ();
4740 if (!(vc.pending & VisualChange::ZoomLevel)) {
4741 /* If the canvas is not being zoomed then the canvas items will not change
4742 * and cause Item::prepare_for_render to be called so do it here manually.
4743 * Not ideal, but I can't think of a better solution atm.
4745 _track_canvas->prepare_for_render();
4748 /* If we are only scrolling vertically there is no need to update these */
4749 if (vc.pending != VisualChange::YOrigin) {
4750 update_fixed_rulers ();
4751 redisplay_grid (true);
4753 /* video frames & position need to be updated for zoom, horiz-scroll
4754 * and (explicitly) VisualChange::VideoTimeline.
4756 update_video_timeline();
4759 _summary->set_overlays_dirty ();
4762 struct EditorOrderTimeAxisSorter {
4763 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4764 return a->order () < b->order ();
4769 Editor::sort_track_selection (TrackViewList& sel)
4771 EditorOrderTimeAxisSorter cmp;
4776 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4779 samplepos_t where = 0;
4780 EditPoint ep = _edit_point;
4782 if (Profile->get_mixbus()) {
4783 if (ep == EditAtSelectedMarker) {
4784 ep = EditAtPlayhead;
4788 if (from_outside_canvas && (ep == EditAtMouse)) {
4789 ep = EditAtPlayhead;
4790 } else if (from_context_menu && (ep == EditAtMouse)) {
4791 return canvas_event_sample (&context_click_event, 0, 0);
4794 if (entered_marker) {
4795 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4796 return entered_marker->position();
4799 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4800 ep = EditAtSelectedMarker;
4803 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4804 ep = EditAtPlayhead;
4807 MusicSample snap_mf (0, 0);
4810 case EditAtPlayhead:
4811 if (_dragging_playhead) {
4812 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4813 where = playhead_cursor->current_sample();
4815 where = _session->audible_sample();
4817 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4820 case EditAtSelectedMarker:
4821 if (!selection->markers.empty()) {
4823 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4826 where = loc->start();
4830 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4838 if (!mouse_sample (where, ignored)) {
4839 /* XXX not right but what can we do ? */
4842 snap_mf.sample = where;
4844 where = snap_mf.sample;
4845 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4853 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4855 if (!_session) return;
4857 begin_reversible_command (cmd);
4861 if ((tll = transport_loop_location()) == 0) {
4862 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4863 XMLNode &before = _session->locations()->get_state();
4864 _session->locations()->add (loc, true);
4865 _session->set_auto_loop_location (loc);
4866 XMLNode &after = _session->locations()->get_state();
4867 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4869 XMLNode &before = tll->get_state();
4870 tll->set_hidden (false, this);
4871 tll->set (start, end);
4872 XMLNode &after = tll->get_state();
4873 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4876 commit_reversible_command ();
4880 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4882 if (!_session) return;
4884 begin_reversible_command (cmd);
4888 if ((tpl = transport_punch_location()) == 0) {
4889 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4890 XMLNode &before = _session->locations()->get_state();
4891 _session->locations()->add (loc, true);
4892 _session->set_auto_punch_location (loc);
4893 XMLNode &after = _session->locations()->get_state();
4894 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4896 XMLNode &before = tpl->get_state();
4897 tpl->set_hidden (false, this);
4898 tpl->set (start, end);
4899 XMLNode &after = tpl->get_state();
4900 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4903 commit_reversible_command ();
4906 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4907 * @param rs List to which found regions are added.
4908 * @param where Time to look at.
4909 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4912 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4914 const TrackViewList* tracks;
4917 tracks = &track_views;
4922 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4924 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4927 boost::shared_ptr<Track> tr;
4928 boost::shared_ptr<Playlist> pl;
4930 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4932 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4934 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4935 RegionView* rv = rtv->view()->find_view (*i);
4946 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4948 const TrackViewList* tracks;
4951 tracks = &track_views;
4956 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4957 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4959 boost::shared_ptr<Track> tr;
4960 boost::shared_ptr<Playlist> pl;
4962 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4964 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4966 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4968 RegionView* rv = rtv->view()->find_view (*i);
4979 /** Get regions using the following method:
4981 * Make a region list using:
4982 * (a) any selected regions
4983 * (b) the intersection of any selected tracks and the edit point(*)
4984 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4986 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4988 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4992 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4994 RegionSelection regions;
4996 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4997 regions.add (entered_regionview);
4999 regions = selection->regions;
5002 if (regions.empty()) {
5003 TrackViewList tracks = selection->tracks;
5005 if (!tracks.empty()) {
5006 /* no region selected or entered, but some selected tracks:
5007 * act on all regions on the selected tracks at the edit point
5009 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
5010 get_regions_at(regions, where, tracks);
5017 /** Get regions using the following method:
5019 * Make a region list using:
5020 * (a) any selected regions
5021 * (b) the intersection of any selected tracks and the edit point(*)
5022 * (c) if neither exists, then whatever region is under the mouse
5024 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5026 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5029 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
5031 RegionSelection regions;
5033 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5034 regions.add (entered_regionview);
5036 regions = selection->regions;
5039 if (regions.empty()) {
5040 TrackViewList tracks = selection->tracks;
5042 if (!tracks.empty()) {
5043 /* no region selected or entered, but some selected tracks:
5044 * act on all regions on the selected tracks at the edit point
5046 get_regions_at(regions, pos, tracks);
5053 /** Start with regions that are selected, or the entered regionview if none are selected.
5054 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5055 * of the regions that we started with.
5059 Editor::get_regions_from_selection_and_entered () const
5061 RegionSelection regions = selection->regions;
5063 if (regions.empty() && entered_regionview) {
5064 regions.add (entered_regionview);
5071 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5073 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5074 RouteTimeAxisView* rtav;
5076 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5077 boost::shared_ptr<Playlist> pl;
5078 std::vector<boost::shared_ptr<Region> > results;
5079 boost::shared_ptr<Track> tr;
5081 if ((tr = rtav->track()) == 0) {
5086 if ((pl = (tr->playlist())) != 0) {
5087 boost::shared_ptr<Region> r = pl->region_by_id (id);
5089 RegionView* rv = rtav->view()->find_view (r);
5091 regions.push_back (rv);
5100 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5103 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5104 MidiTimeAxisView* mtav;
5106 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5108 mtav->get_per_region_note_selection (selection);
5115 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5117 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5119 RouteTimeAxisView* tatv;
5121 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5123 boost::shared_ptr<Playlist> pl;
5124 vector<boost::shared_ptr<Region> > results;
5126 boost::shared_ptr<Track> tr;
5128 if ((tr = tatv->track()) == 0) {
5133 if ((pl = (tr->playlist())) != 0) {
5134 if (src_comparison) {
5135 pl->get_source_equivalent_regions (region, results);
5137 pl->get_region_list_equivalent_regions (region, results);
5141 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5142 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5143 regions.push_back (marv);
5152 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5154 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5155 RouteTimeAxisView* tatv;
5156 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5157 if (!tatv->track()) {
5160 RegionView* marv = tatv->view()->find_view (region);
5170 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5172 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5173 RouteTimeAxisView* rtav;
5174 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5175 if (rtav->route() == route) {
5184 Editor::show_rhythm_ferret ()
5186 if (rhythm_ferret == 0) {
5187 rhythm_ferret = new RhythmFerret(*this);
5190 rhythm_ferret->set_session (_session);
5191 rhythm_ferret->show ();
5192 rhythm_ferret->present ();
5196 Editor::first_idle ()
5198 MessageDialog* dialog = 0;
5200 if (track_views.size() > 1) {
5201 Timers::TimerSuspender t;
5202 dialog = new MessageDialog (
5203 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5207 ARDOUR_UI::instance()->flush_pending (60);
5210 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5214 /* now that all regionviews should exist, setup region selection */
5218 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5219 /* this is cumulative: rs is NOT cleared each time */
5220 get_regionviews_by_id (*pr, rs);
5223 selection->set (rs);
5225 /* first idle adds route children (automation tracks), so we need to redisplay here */
5226 _routes->redisplay ();
5230 if (_session->undo_depth() == 0) {
5231 undo_action->set_sensitive(false);
5233 redo_action->set_sensitive(false);
5234 begin_selection_op_history ();
5240 Editor::_idle_resize (gpointer arg)
5242 return ((Editor*)arg)->idle_resize ();
5246 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5248 if (resize_idle_id < 0) {
5249 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5250 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5251 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5253 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5254 _pending_resize_amount = 0;
5257 /* make a note of the smallest resulting height, so that we can clamp the
5258 lower limit at TimeAxisView::hSmall */
5260 int32_t min_resulting = INT32_MAX;
5262 _pending_resize_amount += h;
5263 _pending_resize_view = view;
5265 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5267 if (selection->tracks.contains (_pending_resize_view)) {
5268 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5269 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5273 if (min_resulting < 0) {
5278 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5279 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5283 /** Handle pending resizing of tracks */
5285 Editor::idle_resize ()
5287 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5289 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5290 selection->tracks.contains (_pending_resize_view)) {
5292 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5293 if (*i != _pending_resize_view) {
5294 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5299 _pending_resize_amount = 0;
5300 _group_tabs->set_dirty ();
5301 resize_idle_id = -1;
5309 ENSURE_GUI_THREAD (*this, &Editor::located);
5312 playhead_cursor->set_position (_session->audible_sample ());
5313 if (_follow_playhead && !_pending_initial_locate) {
5314 reset_x_origin_to_follow_playhead ();
5318 _pending_locate_request = false;
5319 _pending_initial_locate = false;
5320 _last_update_time = 0;
5324 Editor::region_view_added (RegionView * rv)
5326 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5328 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5329 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5330 if (rv->region()->id () == (*rnote).first) {
5331 mrv->select_notes ((*rnote).second);
5332 selection->pending_midi_note_selection.erase(rnote);
5338 _summary->set_background_dirty ();
5340 mark_region_boundary_cache_dirty ();
5344 Editor::region_view_removed ()
5346 _summary->set_background_dirty ();
5348 mark_region_boundary_cache_dirty ();
5352 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5354 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5355 if ((*j)->stripable() == s) {
5364 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5366 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5367 if ((*j)->control() == c) {
5371 TimeAxisView::Children kids = (*j)->get_child_list ();
5373 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5374 if ((*k)->control() == c) {
5384 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5388 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5389 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5399 Editor::suspend_route_redisplay ()
5402 _routes->suspend_redisplay();
5407 Editor::resume_route_redisplay ()
5410 _routes->redisplay(); // queue redisplay
5411 _routes->resume_redisplay();
5416 Editor::add_vcas (VCAList& vlist)
5420 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5421 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5424 add_stripables (sl);
5428 Editor::add_routes (RouteList& rlist)
5432 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5436 add_stripables (sl);
5440 Editor::add_stripables (StripableList& sl)
5442 list<TimeAxisView*> new_views;
5443 boost::shared_ptr<VCA> v;
5444 boost::shared_ptr<Route> r;
5445 TrackViewList new_selection;
5446 bool from_scratch = (track_views.size() == 0);
5448 sl.sort (Stripable::Sorter());
5450 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5452 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5454 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5456 new_views.push_back (vtv);
5458 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5460 if (r->is_auditioner() || r->is_monitor()) {
5464 RouteTimeAxisView* rtv;
5465 DataType dt = r->input()->default_type();
5467 if (dt == ARDOUR::DataType::AUDIO) {
5468 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5470 } else if (dt == ARDOUR::DataType::MIDI) {
5471 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5474 throw unknown_type();
5477 new_views.push_back (rtv);
5478 track_views.push_back (rtv);
5479 new_selection.push_back (rtv);
5481 rtv->effective_gain_display ();
5483 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5484 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5488 if (new_views.size() > 0) {
5489 _routes->time_axis_views_added (new_views);
5490 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5493 /* note: !new_selection.empty() means that we got some routes rather
5497 if (!from_scratch && !new_selection.empty()) {
5498 selection->set (new_selection);
5499 begin_selection_op_history();
5502 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5503 show_editor_mixer (true);
5506 editor_list_button.set_sensitive (true);
5510 Editor::timeaxisview_deleted (TimeAxisView *tv)
5512 if (tv == entered_track) {
5516 if (_session && _session->deletion_in_progress()) {
5517 /* the situation is under control */
5521 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5523 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5525 _routes->route_removed (tv);
5527 TimeAxisView::Children c = tv->get_child_list ();
5528 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5529 if (entered_track == i->get()) {
5534 /* remove it from the list of track views */
5536 TrackViewList::iterator i;
5538 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5539 i = track_views.erase (i);
5542 /* update whatever the current mixer strip is displaying, if revelant */
5544 boost::shared_ptr<Route> route;
5547 route = rtav->route ();
5550 if (current_mixer_strip && current_mixer_strip->route() == route) {
5552 TimeAxisView* next_tv;
5554 if (track_views.empty()) {
5556 } else if (i == track_views.end()) {
5557 next_tv = track_views.front();
5562 // skip VCAs (cannot be selected, n/a in editor-mixer)
5563 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5564 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5565 next_tv = track_views.front();
5567 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5568 /* just in case: no master, only a VCA remains */
5574 set_selected_mixer_strip (*next_tv);
5576 /* make the editor mixer strip go away setting the
5577 * button to inactive (which also unticks the menu option)
5580 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5586 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5592 DisplaySuspender ds;
5593 PresentationInfo::ChangeSuspender cs;
5595 if (apply_to_selection) {
5596 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5598 TrackSelection::iterator j = i;
5601 hide_track_in_display (*i, false);
5606 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5608 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5609 /* this will hide the mixer strip */
5610 set_selected_mixer_strip (*tv);
5613 _routes->hide_track_in_display (*tv);
5618 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5623 _routes->show_track_in_display (*tv);
5624 if (move_into_view) {
5625 ensure_time_axis_view_is_visible (*tv, false);
5630 Editor::sync_track_view_list_and_routes ()
5632 track_views = TrackViewList (_routes->views ());
5634 _summary->set_background_dirty();
5635 _group_tabs->set_dirty ();
5637 return false; // do not call again (until needed)
5641 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5643 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5648 /** Find a StripableTimeAxisView by the ID of its stripable */
5649 StripableTimeAxisView*
5650 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5652 StripableTimeAxisView* v;
5654 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5655 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5656 if(v->stripable()->id() == id) {
5666 Editor::fit_route_group (RouteGroup *g)
5668 TrackViewList ts = axis_views_from_routes (g->route_list ());
5673 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5675 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5678 _session->cancel_audition ();
5682 if (_session->is_auditioning()) {
5683 _session->cancel_audition ();
5684 if (r == last_audition_region) {
5689 _session->audition_region (r);
5690 last_audition_region = r;
5695 Editor::hide_a_region (boost::shared_ptr<Region> r)
5697 r->set_hidden (true);
5701 Editor::show_a_region (boost::shared_ptr<Region> r)
5703 r->set_hidden (false);
5707 Editor::audition_region_from_region_list ()
5709 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5713 Editor::hide_region_from_region_list ()
5715 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5719 Editor::show_region_in_region_list ()
5721 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5725 Editor::step_edit_status_change (bool yn)
5728 start_step_editing ();
5730 stop_step_editing ();
5735 Editor::start_step_editing ()
5737 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5741 Editor::stop_step_editing ()
5743 step_edit_connection.disconnect ();
5747 Editor::check_step_edit ()
5749 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5750 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5752 mtv->check_step_edit ();
5756 return true; // do it again, till we stop
5760 Editor::scroll_press (Direction dir)
5762 ++_scroll_callbacks;
5764 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5765 /* delay the first auto-repeat */
5771 scroll_backward (1);
5779 scroll_up_one_track ();
5783 scroll_down_one_track ();
5787 /* do hacky auto-repeat */
5788 if (!_scroll_connection.connected ()) {
5790 _scroll_connection = Glib::signal_timeout().connect (
5791 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5794 _scroll_callbacks = 0;
5801 Editor::scroll_release ()
5803 _scroll_connection.disconnect ();
5806 /** Queue a change for the Editor viewport x origin to follow the playhead */
5808 Editor::reset_x_origin_to_follow_playhead ()
5810 samplepos_t const sample = playhead_cursor->current_sample ();
5812 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5814 if (_session->transport_speed() < 0) {
5816 if (sample > (current_page_samples() / 2)) {
5817 center_screen (sample-(current_page_samples()/2));
5819 center_screen (current_page_samples()/2);
5826 if (sample < _leftmost_sample) {
5828 if (_session->transport_rolling()) {
5829 /* rolling; end up with the playhead at the right of the page */
5830 l = sample - current_page_samples ();
5832 /* not rolling: end up with the playhead 1/4 of the way along the page */
5833 l = sample - current_page_samples() / 4;
5837 if (_session->transport_rolling()) {
5838 /* rolling: end up with the playhead on the left of the page */
5841 /* not rolling: end up with the playhead 3/4 of the way along the page */
5842 l = sample - 3 * current_page_samples() / 4;
5850 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5856 Editor::super_rapid_screen_update ()
5858 if (!_session || !_session->engine().running()) {
5862 /* METERING / MIXER STRIPS */
5864 /* update track meters, if required */
5865 if (contents().is_mapped() && meters_running) {
5866 RouteTimeAxisView* rtv;
5867 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5868 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5869 rtv->fast_update ();
5874 /* and any current mixer strip */
5875 if (current_mixer_strip) {
5876 current_mixer_strip->fast_update ();
5879 bool latent_locate = false;
5880 samplepos_t sample = _session->audible_sample (&latent_locate);
5881 const int64_t now = g_get_monotonic_time ();
5884 if (_session->exporting ()) {
5885 /* freewheel/export may be faster or slower than transport_speed() / SR.
5886 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5888 _last_update_time = 0;
5891 if (!_session->transport_rolling () || _session->is_auditioning ()) {
5892 /* Do not interpolate the playhead position; just set it */
5893 _last_update_time = 0;
5896 if (_last_update_time > 0) {
5897 /* interpolate and smoothen playhead position */
5898 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5899 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5900 err = sample - guess;
5902 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5903 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5906 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5908 err, _err_screen_engine);
5913 _err_screen_engine = 0;
5916 if (err > 8192 || latent_locate) {
5917 // in case of x-runs or freewheeling
5918 _last_update_time = 0;
5919 sample = _session->audible_sample ();
5921 _last_update_time = now;
5924 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5926 MusicSample where (sample, 0);
5927 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5928 snapped_cursor->hide ();
5929 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5930 /* EditAtPlayhead does not snap */
5931 } else if (_edit_point == EditAtSelectedMarker) {
5932 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5933 * however, the current editing code -does- snap so I'll draw it that way for now.
5935 if (!selection->markers.empty()) {
5936 MusicSample ms (selection->markers.front()->position(), 0);
5937 snap_to (ms); // should use snap_to_with_modifier?
5938 snapped_cursor->set_position (ms.sample);
5939 snapped_cursor->show ();
5941 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5942 snapped_cursor->show ();
5943 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5944 snapped_cursor->hide ();
5947 /* There are a few reasons why we might not update the playhead / viewport stuff:
5949 * 1. we don't update things when there's a pending locate request, otherwise
5950 * when the editor requests a locate there is a chance that this method
5951 * will move the playhead before the locate request is processed, causing
5953 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5954 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5956 if (_pending_locate_request) {
5957 _last_update_time = 0;
5961 if (_dragging_playhead) {
5962 _last_update_time = 0;
5966 if (playhead_cursor->current_sample () == sample) {
5970 playhead_cursor->set_position (sample);
5972 if (_session->requested_return_sample() >= 0) {
5973 _last_update_time = 0;
5977 if (!_follow_playhead || pending_visual_change.being_handled) {
5978 /* We only do this if we aren't already
5979 * handling a visual change (ie if
5980 * pending_visual_change.being_handled is
5981 * false) so that these requests don't stack
5982 * up there are too many of them to handle in
5988 if (!_stationary_playhead) {
5989 reset_x_origin_to_follow_playhead ();
5991 samplepos_t const sample = playhead_cursor->current_sample ();
5992 double target = ((double)sample - (double)current_page_samples() / 2.0);
5993 if (target <= 0.0) {
5996 /* compare to EditorCursor::set_position() */
5997 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5998 double const new_pos = sample_to_pixel_unrounded (target);
5999 if (rint (new_pos) != rint (old_pos)) {
6000 reset_x_origin (pixel_to_sample (new_pos));
6007 Editor::session_going_away ()
6009 _have_idled = false;
6011 _session_connections.drop_connections ();
6013 super_rapid_screen_update_connection.disconnect ();
6015 selection->clear ();
6016 cut_buffer->clear ();
6018 clicked_regionview = 0;
6019 clicked_axisview = 0;
6020 clicked_routeview = 0;
6021 entered_regionview = 0;
6023 _last_update_time = 0;
6026 playhead_cursor->hide ();
6028 /* rip everything out of the list displays */
6032 _route_groups->clear ();
6034 /* do this first so that deleting a track doesn't reset cms to null
6035 and thus cause a leak.
6038 if (current_mixer_strip) {
6039 if (current_mixer_strip->get_parent() != 0) {
6040 global_hpacker.remove (*current_mixer_strip);
6042 delete current_mixer_strip;
6043 current_mixer_strip = 0;
6046 /* delete all trackviews */
6048 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6051 track_views.clear ();
6053 nudge_clock->set_session (0);
6055 editor_list_button.set_active(false);
6056 editor_list_button.set_sensitive(false);
6058 /* clear tempo/meter rulers */
6059 remove_metric_marks ();
6060 clear_marker_display ();
6066 stop_step_editing ();
6070 /* get rid of any existing editor mixer strip */
6072 WindowTitle title(Glib::get_application_name());
6073 title += _("Editor");
6075 own_window()->set_title (title.get_string());
6078 SessionHandlePtr::session_going_away ();
6082 Editor::trigger_script (int i)
6084 LuaInstance::instance()-> call_action (i);
6088 Editor::show_editor_list (bool yn)
6091 _editor_list_vbox.show ();
6093 _editor_list_vbox.hide ();
6098 Editor::change_region_layering_order (bool from_context_menu)
6100 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6102 if (!clicked_routeview) {
6103 if (layering_order_editor) {
6104 layering_order_editor->hide ();
6109 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6115 boost::shared_ptr<Playlist> pl = track->playlist();
6121 if (layering_order_editor == 0) {
6122 layering_order_editor = new RegionLayeringOrderEditor (*this);
6125 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6126 layering_order_editor->maybe_present ();
6130 Editor::update_region_layering_order_editor ()
6132 if (layering_order_editor && layering_order_editor->is_visible ()) {
6133 change_region_layering_order (true);
6138 Editor::setup_fade_images ()
6140 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6141 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6142 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6143 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6144 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6146 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6147 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6148 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6149 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6150 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6154 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6156 Editor::action_menu_item (std::string const & name)
6158 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6161 return *manage (a->create_menu_item ());
6165 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6167 EventBox* b = manage (new EventBox);
6168 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6169 Label* l = manage (new Label (name));
6173 _the_notebook.append_page (widget, *b);
6177 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6179 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6180 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6183 if (ev->type == GDK_2BUTTON_PRESS) {
6185 /* double-click on a notebook tab shrinks or expands the notebook */
6187 if (_notebook_shrunk) {
6188 if (pre_notebook_shrink_pane_width) {
6189 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6191 _notebook_shrunk = false;
6193 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6195 /* this expands the LHS of the edit pane to cover the notebook
6196 PAGE but leaves the tabs visible.
6198 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6199 _notebook_shrunk = true;
6207 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6209 using namespace Menu_Helpers;
6211 MenuList& items = _control_point_context_menu.items ();
6214 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6215 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6216 if (!can_remove_control_point (item)) {
6217 items.back().set_sensitive (false);
6220 _control_point_context_menu.popup (event->button.button, event->button.time);
6224 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6226 using namespace Menu_Helpers;
6228 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6233 /* We need to get the selection here and pass it to the operations, since
6234 popping up the menu will cause a region leave event which clears
6235 entered_regionview. */
6237 MidiRegionView& mrv = note->region_view();
6238 const RegionSelection rs = get_regions_from_selection_and_entered ();
6239 const uint32_t sel_size = mrv.selection_size ();
6241 MenuList& items = _note_context_menu.items();
6245 items.push_back(MenuElem(_("Delete"),
6246 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6249 items.push_back(MenuElem(_("Edit..."),
6250 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6251 if (sel_size != 1) {
6252 items.back().set_sensitive (false);
6255 items.push_back(MenuElem(_("Transpose..."),
6256 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6259 items.push_back(MenuElem(_("Legatize"),
6260 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6262 items.back().set_sensitive (false);
6265 items.push_back(MenuElem(_("Quantize..."),
6266 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6268 items.push_back(MenuElem(_("Remove Overlap"),
6269 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6271 items.back().set_sensitive (false);
6274 items.push_back(MenuElem(_("Transform..."),
6275 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6277 _note_context_menu.popup (event->button.button, event->button.time);
6281 Editor::zoom_vertical_modifier_released()
6283 _stepping_axis_view = 0;
6287 Editor::ui_parameter_changed (string parameter)
6289 if (parameter == "icon-set") {
6290 while (!_cursor_stack.empty()) {
6291 _cursor_stack.pop_back();
6293 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6294 _cursor_stack.push_back(_cursors->grabber);
6295 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6296 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6298 } else if (parameter == "draggable-playhead") {
6299 if (_verbose_cursor) {
6300 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6302 } else if (parameter == "use-note-bars-for-velocity") {
6303 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6304 _track_canvas->request_redraw (_track_canvas->visible_area());
6305 } else if (parameter == "use-note-color-for-velocity") {
6306 /* handled individually by each MidiRegionView */
6311 Editor::use_own_window (bool and_fill_it)
6313 bool new_window = !own_window();
6315 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6317 if (win && new_window) {
6318 win->set_name ("EditorWindow");
6320 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6322 // win->signal_realize().connect (*this, &Editor::on_realize);
6323 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6324 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6325 win->set_data ("ardour-bindings", bindings);
6330 DisplaySuspender ds;
6331 contents().show_all ();
6333 /* XXX: this is a bit unfortunate; it would probably
6334 be nicer if we could just call show () above rather
6335 than needing the show_all ()
6338 /* re-hide stuff if necessary */
6339 editor_list_button_toggled ();
6340 parameter_changed ("show-summary");
6341 parameter_changed ("show-group-tabs");
6342 parameter_changed ("show-zoom-tools");
6344 /* now reset all audio_time_axis heights, because widgets might need
6350 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6351 tv = (static_cast<TimeAxisView*>(*i));
6352 tv->reset_height ();
6355 if (current_mixer_strip) {
6356 current_mixer_strip->hide_things ();
6357 current_mixer_strip->parameter_changed ("mixer-element-visibility");