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 if (Profile->get_mixbus()) {
2306 if (ep == EditAtSelectedMarker) {
2307 ep = EditAtPlayhead;
2311 bool changed = (_edit_point != ep);
2315 string str = edit_point_strings[(int)ep];
2316 if (str != edit_point_selector.get_text ()) {
2317 edit_point_selector.set_text (str);
2320 update_all_enter_cursors();
2322 if (!force && !changed) {
2326 const char* action=NULL;
2328 switch (_edit_point) {
2329 case EditAtPlayhead:
2330 action = "edit-at-playhead";
2332 case EditAtSelectedMarker:
2333 action = "edit-at-selected-marker";
2336 action = "edit-at-mouse";
2340 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Editor", action);
2341 tact->set_active (true);
2344 bool in_track_canvas;
2346 if (!mouse_sample (foo, in_track_canvas)) {
2347 in_track_canvas = false;
2350 reset_canvas_action_sensitivity (in_track_canvas);
2351 sensitize_the_right_region_actions (false);
2357 Editor::set_state (const XMLNode& node, int version)
2360 PBD::Unwinder<bool> nsi (no_save_instant, true);
2363 Tabbable::set_state (node, version);
2366 if (_session && node.get_property ("playhead", ph_pos)) {
2368 playhead_cursor->set_position (ph_pos);
2370 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2371 playhead_cursor->set_position (0);
2374 playhead_cursor->set_position (0);
2377 node.get_property ("mixer-width", editor_mixer_strip_width);
2379 node.get_property ("zoom-focus", zoom_focus);
2380 zoom_focus_selection_done (zoom_focus);
2383 if (node.get_property ("zoom", z)) {
2384 /* older versions of ardour used floating point samples_per_pixel */
2385 reset_zoom (llrintf (z));
2387 reset_zoom (samples_per_pixel);
2391 if (node.get_property ("visible-track-count", cnt)) {
2392 set_visible_track_count (cnt);
2396 if (!node.get_property ("grid-type", grid_type)) {
2397 grid_type = _grid_type;
2399 set_grid_to (grid_type);
2402 if (node.get_property ("snap-mode", sm)) {
2403 snap_mode_selection_done(sm);
2404 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2405 * snap_mode_selection_done() will only mark an already active item as active
2406 * which does not trigger set_text().
2410 set_snap_mode (_snap_mode);
2413 node.get_property ("internal-grid-type", internal_grid_type);
2414 node.get_property ("internal-snap-mode", internal_snap_mode);
2415 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2416 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2419 if (node.get_property ("mouse-mode", mm_str)) {
2420 MouseMode m = str2mousemode(mm_str);
2421 set_mouse_mode (m, true);
2423 set_mouse_mode (MouseObject, true);
2427 if (node.get_property ("left-frame", lf_pos)) {
2431 reset_x_origin (lf_pos);
2435 if (node.get_property ("y-origin", y_origin)) {
2436 reset_y_origin (y_origin);
2440 node.get_property ("join-object-range", yn);
2442 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2443 /* do it twice to force the change */
2444 tact->set_active (!yn);
2445 tact->set_active (yn);
2446 set_mouse_mode(mouse_mode, true);
2450 if (node.get_property ("edit-point", ep)) {
2451 set_edit_point_preference (ep, true);
2453 set_edit_point_preference (_edit_point);
2456 if (node.get_property ("follow-playhead", yn)) {
2457 set_follow_playhead (yn);
2460 if (node.get_property ("stationary-playhead", yn)) {
2461 set_stationary_playhead (yn);
2464 RegionListSortType sort_type;
2465 if (node.get_property ("region-list-sort-type", sort_type)) {
2466 _regions->reset_sort_type (sort_type, true);
2470 node.get_property ("show-editor-mixer", yn);
2472 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2473 /* do it twice to force the change */
2474 tact->set_active (!yn);
2475 tact->set_active (yn);
2479 node.get_property ("show-editor-list", yn);
2481 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2482 /* do it twice to force the change */
2483 tact->set_active (!yn);
2484 tact->set_active (yn);
2488 if (node.get_property (X_("editor-list-page"), el_page)) {
2489 _the_notebook.set_current_page (el_page);
2493 node.get_property (X_("show-marker-lines"), yn);
2495 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-marker-lines"));
2496 /* do it twice to force the change */
2497 tact->set_active (!yn);
2498 tact->set_active (yn);
2501 XMLNodeList children = node.children ();
2502 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2503 selection->set_state (**i, Stateful::current_state_version);
2504 _regions->set_state (**i);
2505 _locations->set_state (**i);
2508 if (node.get_property ("maximised", yn)) {
2509 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalEditor"));
2510 bool fs = tact->get_active();
2512 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2516 samplepos_t nudge_clock_value;
2517 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2518 nudge_clock->set (nudge_clock_value);
2520 nudge_clock->set_mode (AudioClock::Timecode);
2521 nudge_clock->set (_session->sample_rate() * 5, true);
2526 * Not all properties may have been in XML, but
2527 * those that are linked to a private variable may need changing
2529 RefPtr<ToggleAction> tact;
2531 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
2532 yn = _follow_playhead;
2533 if (tact->get_active() != yn) {
2534 tact->set_active (yn);
2537 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
2538 yn = _stationary_playhead;
2539 if (tact->get_active() != yn) {
2540 tact->set_active (yn);
2548 Editor::get_state ()
2550 XMLNode* node = new XMLNode (X_("Editor"));
2552 node->set_property ("id", id().to_s ());
2554 node->add_child_nocopy (Tabbable::get_state());
2556 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2557 node->set_property("notebook-shrunk", _notebook_shrunk);
2558 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2560 maybe_add_mixer_strip_width (*node);
2562 node->set_property ("zoom-focus", zoom_focus);
2564 node->set_property ("zoom", samples_per_pixel);
2565 node->set_property ("grid-type", _grid_type);
2566 node->set_property ("snap-mode", _snap_mode);
2567 node->set_property ("internal-grid-type", internal_grid_type);
2568 node->set_property ("internal-snap-mode", internal_snap_mode);
2569 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2570 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2571 node->set_property ("edit-point", _edit_point);
2572 node->set_property ("visible-track-count", _visible_track_count);
2574 node->set_property ("playhead", playhead_cursor->current_sample ());
2575 node->set_property ("left-frame", _leftmost_sample);
2576 node->set_property ("y-origin", vertical_adjustment.get_value ());
2578 node->set_property ("maximised", _maximised);
2579 node->set_property ("follow-playhead", _follow_playhead);
2580 node->set_property ("stationary-playhead", _stationary_playhead);
2581 node->set_property ("region-list-sort-type", _regions->sort_type ());
2582 node->set_property ("mouse-mode", mouse_mode);
2583 node->set_property ("join-object-range", smart_mode_action->get_active ());
2585 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2586 node->set_property (X_("show-editor-mixer"), tact->get_active());
2588 tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2589 node->set_property (X_("show-editor-list"), tact->get_active());
2591 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2593 if (button_bindings) {
2594 XMLNode* bb = new XMLNode (X_("Buttons"));
2595 button_bindings->save (*bb);
2596 node->add_child_nocopy (*bb);
2599 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2601 node->add_child_nocopy (selection->get_state ());
2602 node->add_child_nocopy (_regions->get_state ());
2604 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2606 node->add_child_nocopy (_locations->get_state ());
2611 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2612 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2614 * @return pair: TimeAxisView that y is over, layer index.
2616 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2617 * in stacked or expanded region display mode, otherwise 0.
2619 std::pair<TimeAxisView *, double>
2620 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2622 if (!trackview_relative_offset) {
2623 y -= _trackview_group->canvas_origin().y;
2627 return std::make_pair ((TimeAxisView *) 0, 0);
2630 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2632 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2639 return std::make_pair ((TimeAxisView *) 0, 0);
2643 Editor::set_snapped_cursor_position (samplepos_t pos)
2645 if (_edit_point == EditAtMouse) {
2646 snapped_cursor->set_position(pos);
2651 /** Snap a position to the grid, if appropriate, taking into account current
2652 * grid settings and also the state of any snap modifier keys that may be pressed.
2653 * @param start Position to snap.
2654 * @param event Event to get current key modifier information from, or 0.
2657 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
2659 if (!_session || !event) {
2663 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2664 if (_snap_mode == SnapOff) {
2665 snap_to_internal (start, direction, pref);
2667 start.set (start.sample, 0);
2670 if (_snap_mode != SnapOff) {
2671 snap_to_internal (start, direction, pref);
2672 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2673 /* SnapOff, but we pressed the snap_delta modifier */
2674 snap_to_internal (start, direction, pref);
2676 start.set (start.sample, 0);
2682 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2684 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2685 start.set (start.sample, 0);
2689 snap_to_internal (start, direction, pref, ensure_snap);
2693 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2695 samplepos_t diff = abs (test - presnap);
2701 test = max_samplepos; // reset this so it doesn't get accidentally reused
2705 Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
2707 samplepos_t start = presnap.sample;
2708 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2709 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2711 TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
2714 case timecode_show_bits:
2715 case timecode_show_samples:
2716 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2717 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2718 /* start is already on a whole timecode frame, do nothing */
2719 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2720 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2722 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2726 case timecode_show_seconds:
2727 if (_session->config.get_timecode_offset_negative()) {
2728 start += _session->config.get_timecode_offset ();
2730 start -= _session->config.get_timecode_offset ();
2732 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2733 (start % one_timecode_second == 0)) {
2734 /* start is already on a whole second, do nothing */
2735 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2736 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2738 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2741 if (_session->config.get_timecode_offset_negative()) {
2742 start -= _session->config.get_timecode_offset ();
2744 start += _session->config.get_timecode_offset ();
2748 case timecode_show_minutes:
2749 case timecode_show_hours:
2750 case timecode_show_many_hours:
2751 if (_session->config.get_timecode_offset_negative()) {
2752 start += _session->config.get_timecode_offset ();
2754 start -= _session->config.get_timecode_offset ();
2756 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2757 (start % one_timecode_minute == 0)) {
2758 /* start is already on a whole minute, do nothing */
2759 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2760 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2762 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2764 if (_session->config.get_timecode_offset_negative()) {
2765 start -= _session->config.get_timecode_offset ();
2767 start += _session->config.get_timecode_offset ();
2771 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2774 MusicSample ret(start,0);
2779 Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
2781 MusicSample ret(presnap);
2783 const samplepos_t one_second = _session->sample_rate();
2784 const samplepos_t one_minute = one_second * 60;
2785 const samplepos_t one_hour = one_minute * 60;
2787 MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
2790 case minsec_show_msecs:
2791 case minsec_show_seconds: {
2792 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2793 presnap.sample % one_second == 0) {
2794 /* start is already on a whole second, do nothing */
2795 } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
2796 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
2798 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
2802 case minsec_show_minutes: {
2803 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2804 presnap.sample % one_minute == 0) {
2805 /* start is already on a whole minute, do nothing */
2806 } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2807 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
2809 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
2814 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2815 presnap.sample % one_hour == 0) {
2816 /* start is already on a whole hour, do nothing */
2817 } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
2818 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
2820 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
2829 Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
2831 if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
2832 return snap_to_minsec (presnap, direction, gpref);
2835 const samplepos_t one_second = _session->sample_rate();
2837 MusicSample ret(presnap);
2839 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2840 presnap.sample % (one_second/75) == 0) {
2841 /* start is already on a whole CD sample, do nothing */
2842 } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2843 ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2845 ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2852 Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
2854 MusicSample ret(presnap);
2856 if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
2859 switch (_grid_type) {
2860 case GridTypeBeatDiv3:
2861 case GridTypeBeatDiv6:
2862 case GridTypeBeatDiv12:
2863 case GridTypeBeatDiv24:
2866 case GridTypeBeatDiv5:
2867 case GridTypeBeatDiv10:
2868 case GridTypeBeatDiv20:
2871 case GridTypeBeatDiv7:
2872 case GridTypeBeatDiv14:
2873 case GridTypeBeatDiv28:
2880 BBTRulerScale scale = bbt_ruler_scale;
2887 ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
2889 case bbt_show_quarters:
2890 ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
2892 case bbt_show_eighths:
2893 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
2895 case bbt_show_sixteenths:
2896 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
2898 case bbt_show_thirtyseconds:
2899 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
2903 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
2910 Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
2912 MusicSample ret(presnap);
2914 if (grid_musical()) {
2915 ret = snap_to_bbt (presnap, direction, gpref);
2918 switch (_grid_type) {
2919 case GridTypeTimecode:
2920 ret = snap_to_timecode(presnap, direction, gpref);
2922 case GridTypeMinSec:
2923 ret = snap_to_minsec(presnap, direction, gpref);
2925 case GridTypeCDFrame:
2926 ret = snap_to_cd_frames(presnap, direction, gpref);
2936 Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
2942 _session->locations()->marks_either_side (presnap, before, after);
2944 if (before == max_samplepos && after == max_samplepos) {
2945 /* No marks to snap to, so just don't snap */
2947 } else if (before == max_samplepos) {
2949 } else if (after == max_samplepos) {
2952 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2954 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2956 } else if (direction == 0) {
2957 if ((presnap - before) < (after - presnap)) {
2969 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2971 const samplepos_t presnap = start.sample;
2973 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2974 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2975 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2977 /* check snap-to-marker */
2978 if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
2979 test = snap_to_marker (presnap, direction);
2980 check_best_snap(presnap, test, dist, best);
2983 /* check snap-to-region-{start/end/sync} */
2985 (pref == SnapToAny_Visual) &&
2986 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
2988 if (!region_boundary_cache.empty()) {
2990 vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
2991 vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2992 if (next != region_boundary_cache.begin ()) {
2997 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2999 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
3001 else if (direction == 0) {
3002 if ((presnap - *prev) < (*next - presnap)) {
3011 check_best_snap(presnap, test, dist, best);
3015 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
3016 MusicSample pre(presnap, 0);
3017 MusicSample post = snap_to_grid (pre, direction, pref);
3018 check_best_snap(presnap, post.sample, dist, best);
3021 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
3022 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
3023 * ToDo: Perhaps this should only occur if EditPointMouse?
3025 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
3027 start.set (best, 0);
3029 } else if (presnap > best) {
3030 if (presnap > (best+ snap_threshold_s)) {
3033 } else if (presnap < best) {
3034 if (presnap < (best - snap_threshold_s)) {
3039 start.set (best, 0);
3044 Editor::setup_toolbar ()
3046 HBox* mode_box = manage(new HBox);
3047 mode_box->set_border_width (2);
3048 mode_box->set_spacing(2);
3050 HBox* mouse_mode_box = manage (new HBox);
3051 HBox* mouse_mode_hbox = manage (new HBox);
3052 VBox* mouse_mode_vbox = manage (new VBox);
3053 Alignment* mouse_mode_align = manage (new Alignment);
3055 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3056 mouse_mode_size_group->add_widget (smart_mode_button);
3057 mouse_mode_size_group->add_widget (mouse_move_button);
3058 if (!Profile->get_mixbus()) {
3059 mouse_mode_size_group->add_widget (mouse_cut_button);
3061 mouse_mode_size_group->add_widget (mouse_select_button);
3062 mouse_mode_size_group->add_widget (mouse_timefx_button);
3063 if (!Profile->get_mixbus()) {
3064 mouse_mode_size_group->add_widget (mouse_audition_button);
3066 mouse_mode_size_group->add_widget (mouse_draw_button);
3067 mouse_mode_size_group->add_widget (mouse_content_button);
3069 if (!Profile->get_mixbus()) {
3070 mouse_mode_size_group->add_widget (zoom_in_button);
3071 mouse_mode_size_group->add_widget (zoom_out_button);
3072 mouse_mode_size_group->add_widget (zoom_out_full_button);
3073 mouse_mode_size_group->add_widget (zoom_focus_selector);
3074 mouse_mode_size_group->add_widget (tav_shrink_button);
3075 mouse_mode_size_group->add_widget (tav_expand_button);
3077 mouse_mode_size_group->add_widget (zoom_preset_selector);
3078 mouse_mode_size_group->add_widget (visible_tracks_selector);
3081 mouse_mode_size_group->add_widget (grid_type_selector);
3082 mouse_mode_size_group->add_widget (snap_mode_button);
3084 mouse_mode_size_group->add_widget (edit_point_selector);
3085 mouse_mode_size_group->add_widget (edit_mode_selector);
3087 mouse_mode_size_group->add_widget (*nudge_clock);
3088 mouse_mode_size_group->add_widget (nudge_forward_button);
3089 mouse_mode_size_group->add_widget (nudge_backward_button);
3091 mouse_mode_hbox->set_spacing (2);
3093 if (!ARDOUR::Profile->get_trx()) {
3094 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3097 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3098 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3100 if (!ARDOUR::Profile->get_mixbus()) {
3101 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3102 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3105 if (!ARDOUR::Profile->get_trx()) {
3106 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3107 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3108 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3111 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3113 mouse_mode_align->add (*mouse_mode_vbox);
3114 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3116 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3118 edit_mode_selector.set_name ("mouse mode button");
3120 if (!ARDOUR::Profile->get_trx()) {
3121 mode_box->pack_start (edit_mode_selector, false, false);
3122 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3123 mode_box->pack_start (edit_point_selector, false, false);
3124 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3127 mode_box->pack_start (*mouse_mode_box, false, false);
3131 _zoom_box.set_spacing (2);
3132 _zoom_box.set_border_width (2);
3136 zoom_preset_selector.set_name ("zoom button");
3137 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3139 zoom_in_button.set_name ("zoom button");
3140 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3141 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3142 zoom_in_button.set_related_action (act);
3144 zoom_out_button.set_name ("zoom button");
3145 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3146 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3147 zoom_out_button.set_related_action (act);
3149 zoom_out_full_button.set_name ("zoom button");
3150 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3151 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3152 zoom_out_full_button.set_related_action (act);
3154 zoom_focus_selector.set_name ("zoom button");
3156 if (ARDOUR::Profile->get_mixbus()) {
3157 _zoom_box.pack_start (zoom_preset_selector, false, false);
3158 } else if (ARDOUR::Profile->get_trx()) {
3159 mode_box->pack_start (zoom_out_button, false, false);
3160 mode_box->pack_start (zoom_in_button, false, false);
3162 _zoom_box.pack_start (zoom_out_button, false, false);
3163 _zoom_box.pack_start (zoom_in_button, false, false);
3164 _zoom_box.pack_start (zoom_out_full_button, false, false);
3165 _zoom_box.pack_start (zoom_focus_selector, false, false);
3168 /* Track zoom buttons */
3169 _track_box.set_spacing (2);
3170 _track_box.set_border_width (2);
3172 visible_tracks_selector.set_name ("zoom button");
3173 if (Profile->get_mixbus()) {
3174 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3176 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3179 tav_expand_button.set_name ("zoom button");
3180 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3181 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3182 tav_expand_button.set_related_action (act);
3184 tav_shrink_button.set_name ("zoom button");
3185 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3186 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3187 tav_shrink_button.set_related_action (act);
3189 if (ARDOUR::Profile->get_mixbus()) {
3190 _track_box.pack_start (visible_tracks_selector);
3191 } else if (ARDOUR::Profile->get_trx()) {
3192 _track_box.pack_start (tav_shrink_button);
3193 _track_box.pack_start (tav_expand_button);
3195 _track_box.pack_start (visible_tracks_selector);
3196 _track_box.pack_start (tav_shrink_button);
3197 _track_box.pack_start (tav_expand_button);
3200 snap_box.set_spacing (2);
3201 snap_box.set_border_width (2);
3203 grid_type_selector.set_name ("mouse mode button");
3205 snap_mode_button.set_name ("mouse mode button");
3207 edit_point_selector.set_name ("mouse mode button");
3209 snap_box.pack_start (snap_mode_button, false, false);
3210 snap_box.pack_start (grid_type_selector, false, false);
3214 HBox *nudge_box = manage (new HBox);
3215 nudge_box->set_spacing (2);
3216 nudge_box->set_border_width (2);
3218 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3219 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3221 nudge_box->pack_start (nudge_backward_button, false, false);
3222 nudge_box->pack_start (nudge_forward_button, false, false);
3223 nudge_box->pack_start (*nudge_clock, false, false);
3226 /* Pack everything in... */
3228 toolbar_hbox.set_spacing (2);
3229 toolbar_hbox.set_border_width (2);
3231 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3232 tool_shadow->set_size_request (4, -1);
3233 tool_shadow->show();
3235 ebox_hpacker.pack_start (*tool_shadow, false, false);
3236 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3238 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3239 spacer->set_name("EditorWindow");
3240 spacer->set_size_request(-1,4);
3243 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3244 ebox_vpacker.pack_start(*spacer, false, false);
3245 ebox_vpacker.show();
3247 toolbar_hbox.pack_start (*mode_box, false, false);
3249 if (!ARDOUR::Profile->get_trx()) {
3251 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3253 toolbar_hbox.pack_start (snap_box, false, false);
3255 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3257 toolbar_hbox.pack_start (*nudge_box, false, false);
3259 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3261 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3263 toolbar_hbox.pack_end (_track_box, false, false);
3267 toolbar_hbox.show_all ();
3271 Editor::build_edit_point_menu ()
3273 using namespace Menu_Helpers;
3275 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3276 if(!Profile->get_mixbus())
3277 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3278 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3280 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3284 Editor::build_edit_mode_menu ()
3286 using namespace Menu_Helpers;
3288 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3289 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3290 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3291 /* Note: Splice was removed */
3293 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3297 Editor::build_grid_type_menu ()
3299 using namespace Menu_Helpers;
3301 /* main grid: bars, quarter-notes, etc */
3302 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3303 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3304 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3305 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3306 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3307 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3308 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3309 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3312 grid_type_selector.AddMenuElem(SeparatorElem());
3313 Gtk::Menu *_triplet_menu = manage (new Menu);
3314 MenuList& triplet_items (_triplet_menu->items());
3316 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3317 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3318 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3319 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3321 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3323 /* quintuplet grid */
3324 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3325 MenuList& quintuplet_items (_quintuplet_menu->items());
3327 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3328 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3329 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3331 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3333 /* septuplet grid */
3334 Gtk::Menu *_septuplet_menu = manage (new Menu);
3335 MenuList& septuplet_items (_septuplet_menu->items());
3337 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3338 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3339 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3341 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3343 grid_type_selector.AddMenuElem(SeparatorElem());
3344 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3345 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3346 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3350 Editor::setup_tooltips ()
3352 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3353 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3354 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3355 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3356 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3357 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3358 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3359 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3360 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3361 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3362 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3363 set_tooltip (zoom_in_button, _("Zoom In"));
3364 set_tooltip (zoom_out_button, _("Zoom Out"));
3365 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3366 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3367 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3368 set_tooltip (tav_expand_button, _("Expand Tracks"));
3369 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3370 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3371 set_tooltip (grid_type_selector, _("Grid Mode"));
3372 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3373 set_tooltip (edit_point_selector, _("Edit Point"));
3374 set_tooltip (edit_mode_selector, _("Edit Mode"));
3375 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3379 Editor::convert_drop_to_paths (
3380 vector<string>& paths,
3381 const RefPtr<Gdk::DragContext>& /*context*/,
3384 const SelectionData& data,
3388 if (_session == 0) {
3392 vector<string> uris = data.get_uris();
3396 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3397 are actually URI lists. So do it by hand.
3400 if (data.get_target() != "text/plain") {
3404 /* Parse the "uri-list" format that Nautilus provides,
3405 where each pathname is delimited by \r\n.
3407 THERE MAY BE NO NULL TERMINATING CHAR!!!
3410 string txt = data.get_text();
3414 p = (char *) malloc (txt.length() + 1);
3415 txt.copy (p, txt.length(), 0);
3416 p[txt.length()] = '\0';
3422 while (g_ascii_isspace (*p))
3426 while (*q && (*q != '\n') && (*q != '\r')) {
3433 while (q > p && g_ascii_isspace (*q))
3438 uris.push_back (string (p, q - p + 1));
3442 p = strchr (p, '\n');
3454 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3455 if ((*i).substr (0,7) == "file://") {
3456 paths.push_back (Glib::filename_from_uri (*i));
3464 Editor::new_tempo_section ()
3469 Editor::map_transport_state ()
3471 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3473 if (_session && _session->transport_stopped()) {
3474 have_pending_keyboard_selection = false;
3477 update_loop_range_view ();
3481 Editor::transport_looped ()
3483 /* reset Playhead position interpolation.
3484 * see Editor::super_rapid_screen_update
3486 _last_update_time = 0;
3492 Editor::begin_selection_op_history ()
3494 selection_op_cmd_depth = 0;
3495 selection_op_history_it = 0;
3497 while(!selection_op_history.empty()) {
3498 delete selection_op_history.front();
3499 selection_op_history.pop_front();
3502 selection_undo_action->set_sensitive (false);
3503 selection_redo_action->set_sensitive (false);
3504 selection_op_history.push_front (&_selection_memento->get_state ());
3508 Editor::begin_reversible_selection_op (string name)
3511 //cerr << name << endl;
3512 /* begin/commit pairs can be nested */
3513 selection_op_cmd_depth++;
3518 Editor::commit_reversible_selection_op ()
3521 if (selection_op_cmd_depth == 1) {
3523 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3524 /* The user has undone some selection ops and then made a new one,
3525 * making anything earlier in the list invalid.
3528 list<XMLNode *>::iterator it = selection_op_history.begin();
3529 list<XMLNode *>::iterator e_it = it;
3530 advance (e_it, selection_op_history_it);
3532 for (; it != e_it; ++it) {
3535 selection_op_history.erase (selection_op_history.begin(), e_it);
3538 selection_op_history.push_front (&_selection_memento->get_state ());
3539 selection_op_history_it = 0;
3541 selection_undo_action->set_sensitive (true);
3542 selection_redo_action->set_sensitive (false);
3545 if (selection_op_cmd_depth > 0) {
3546 selection_op_cmd_depth--;
3552 Editor::undo_selection_op ()
3555 selection_op_history_it++;
3557 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3558 if (n == selection_op_history_it) {
3559 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3560 selection_redo_action->set_sensitive (true);
3564 /* is there an earlier entry? */
3565 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3566 selection_undo_action->set_sensitive (false);
3572 Editor::redo_selection_op ()
3575 if (selection_op_history_it > 0) {
3576 selection_op_history_it--;
3579 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3580 if (n == selection_op_history_it) {
3581 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3582 selection_undo_action->set_sensitive (true);
3587 if (selection_op_history_it == 0) {
3588 selection_redo_action->set_sensitive (false);
3594 Editor::begin_reversible_command (string name)
3597 before.push_back (&_selection_memento->get_state ());
3598 _session->begin_reversible_command (name);
3603 Editor::begin_reversible_command (GQuark q)
3606 before.push_back (&_selection_memento->get_state ());
3607 _session->begin_reversible_command (q);
3612 Editor::abort_reversible_command ()
3615 while(!before.empty()) {
3616 delete before.front();
3619 _session->abort_reversible_command ();
3624 Editor::commit_reversible_command ()
3627 if (before.size() == 1) {
3628 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3629 redo_action->set_sensitive(false);
3630 undo_action->set_sensitive(true);
3631 begin_selection_op_history ();
3634 if (before.empty()) {
3635 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3640 _session->commit_reversible_command ();
3645 Editor::history_changed ()
3649 if (undo_action && _session) {
3650 if (_session->undo_depth() == 0) {
3651 label = S_("Command|Undo");
3653 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3655 undo_action->property_label() = label;
3658 if (redo_action && _session) {
3659 if (_session->redo_depth() == 0) {
3661 redo_action->set_sensitive (false);
3663 label = string_compose(_("Redo (%1)"), _session->next_redo());
3664 redo_action->set_sensitive (true);
3666 redo_action->property_label() = label;
3671 Editor::duplicate_range (bool with_dialog)
3675 RegionSelection rs = get_regions_from_selection_and_entered ();
3677 if (selection->time.length() == 0 && rs.empty()) {
3683 ArdourDialog win (_("Duplicate"));
3684 Label label (_("Number of duplications:"));
3685 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3686 SpinButton spinner (adjustment, 0.0, 1);
3689 win.get_vbox()->set_spacing (12);
3690 win.get_vbox()->pack_start (hbox);
3691 hbox.set_border_width (6);
3692 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3694 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3695 place, visually. so do this by hand.
3698 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3699 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3700 spinner.grab_focus();
3706 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3707 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3708 win.set_default_response (RESPONSE_ACCEPT);
3710 spinner.grab_focus ();
3712 switch (win.run ()) {
3713 case RESPONSE_ACCEPT:
3719 times = adjustment.get_value();
3722 if ((current_mouse_mode() == MouseRange)) {
3723 if (selection->time.length()) {
3724 duplicate_selection (times);
3726 } else if (get_smart_mode()) {
3727 if (selection->time.length()) {
3728 duplicate_selection (times);
3730 duplicate_some_regions (rs, times);
3732 duplicate_some_regions (rs, times);
3737 Editor::set_edit_mode (EditMode m)
3739 Config->set_edit_mode (m);
3743 Editor::cycle_edit_mode ()
3745 switch (Config->get_edit_mode()) {
3747 Config->set_edit_mode (Ripple);
3751 Config->set_edit_mode (Lock);
3754 Config->set_edit_mode (Slide);
3760 Editor::edit_mode_selection_done (EditMode m)
3762 Config->set_edit_mode (m);
3766 Editor::grid_type_selection_done (GridType gridtype)
3768 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3770 ract->set_active ();
3775 Editor::snap_mode_selection_done (SnapMode mode)
3777 RefPtr<RadioAction> ract = snap_mode_action (mode);
3780 ract->set_active (true);
3785 Editor::cycle_edit_point (bool with_marker)
3787 if(Profile->get_mixbus())
3788 with_marker = false;
3790 switch (_edit_point) {
3792 set_edit_point_preference (EditAtPlayhead);
3794 case EditAtPlayhead:
3796 set_edit_point_preference (EditAtSelectedMarker);
3798 set_edit_point_preference (EditAtMouse);
3801 case EditAtSelectedMarker:
3802 set_edit_point_preference (EditAtMouse);
3808 Editor::edit_point_selection_done (EditPoint ep)
3810 set_edit_point_preference (ep);
3814 Editor::build_zoom_focus_menu ()
3816 using namespace Menu_Helpers;
3818 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3819 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3820 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3821 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3822 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3823 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3825 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3829 Editor::zoom_focus_selection_done (ZoomFocus f)
3831 RefPtr<RadioAction> ract = zoom_focus_action (f);
3833 ract->set_active ();
3838 Editor::build_track_count_menu ()
3840 using namespace Menu_Helpers;
3842 if (!Profile->get_mixbus()) {
3843 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3844 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3845 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3846 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3847 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3848 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3849 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3850 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3851 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3852 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3853 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3854 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3855 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3857 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3858 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3859 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3860 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3861 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3862 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3863 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3864 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3865 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3866 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3868 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3869 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3870 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3871 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3872 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3873 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3874 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3875 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3876 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3877 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3878 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3879 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3884 Editor::set_zoom_preset (int64_t ms)
3887 temporal_zoom_session();
3891 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3892 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3896 Editor::set_visible_track_count (int32_t n)
3898 _visible_track_count = n;
3900 /* if the canvas hasn't really been allocated any size yet, just
3901 record the desired number of visible tracks and return. when canvas
3902 allocation happens, we will get called again and then we can do the
3906 if (_visible_canvas_height <= 1) {
3912 DisplaySuspender ds;
3914 if (_visible_track_count > 0) {
3915 h = trackviews_height() / _visible_track_count;
3916 std::ostringstream s;
3917 s << _visible_track_count;
3919 } else if (_visible_track_count == 0) {
3921 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3922 if ((*i)->marked_for_display()) {
3924 TimeAxisView::Children cl ((*i)->get_child_list ());
3925 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3926 if ((*j)->marked_for_display()) {
3933 visible_tracks_selector.set_text (X_("*"));
3936 h = trackviews_height() / n;
3939 /* negative value means that the visible track count has
3940 been overridden by explicit track height changes.
3942 visible_tracks_selector.set_text (X_("*"));
3946 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3947 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3950 if (str != visible_tracks_selector.get_text()) {
3951 visible_tracks_selector.set_text (str);
3956 Editor::override_visible_track_count ()
3958 _visible_track_count = -1;
3959 visible_tracks_selector.set_text (_("*"));
3963 Editor::edit_controls_button_release (GdkEventButton* ev)
3965 if (Keyboard::is_context_menu_event (ev)) {
3966 ARDOUR_UI::instance()->add_route ();
3967 } else if (ev->button == 1) {
3968 selection->clear_tracks ();
3975 Editor::mouse_select_button_release (GdkEventButton* ev)
3977 /* this handles just right-clicks */
3979 if (ev->button != 3) {
3987 Editor::set_zoom_focus (ZoomFocus f)
3989 string str = zoom_focus_strings[(int)f];
3991 if (str != zoom_focus_selector.get_text()) {
3992 zoom_focus_selector.set_text (str);
3995 if (zoom_focus != f) {
4002 Editor::cycle_zoom_focus ()
4004 switch (zoom_focus) {
4006 set_zoom_focus (ZoomFocusRight);
4008 case ZoomFocusRight:
4009 set_zoom_focus (ZoomFocusCenter);
4011 case ZoomFocusCenter:
4012 set_zoom_focus (ZoomFocusPlayhead);
4014 case ZoomFocusPlayhead:
4015 set_zoom_focus (ZoomFocusMouse);
4017 case ZoomFocusMouse:
4018 set_zoom_focus (ZoomFocusEdit);
4021 set_zoom_focus (ZoomFocusLeft);
4027 Editor::update_grid ()
4029 if (grid_musical()) {
4030 std::vector<TempoMap::BBTPoint> grid;
4031 if (bbt_ruler_scale != bbt_show_many) {
4032 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
4034 maybe_draw_grid_lines ();
4035 } else if (grid_nonmusical()) {
4036 maybe_draw_grid_lines ();
4043 Editor::toggle_follow_playhead ()
4045 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
4046 set_follow_playhead (tact->get_active());
4049 /** @param yn true to follow playhead, otherwise false.
4050 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4053 Editor::set_follow_playhead (bool yn, bool catch_up)
4055 if (_follow_playhead != yn) {
4056 if ((_follow_playhead = yn) == true && catch_up) {
4058 reset_x_origin_to_follow_playhead ();
4065 Editor::toggle_stationary_playhead ()
4067 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
4068 set_stationary_playhead (tact->get_active());
4072 Editor::set_stationary_playhead (bool yn)
4074 if (_stationary_playhead != yn) {
4075 if ((_stationary_playhead = yn) == true) {
4076 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
4077 // update_current_screen ();
4084 Editor::playlist_selector () const
4086 return *_playlist_selector;
4090 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4092 if (paste_count == 0) {
4093 /* don't bother calculating an offset that will be zero anyway */
4097 /* calculate basic unsnapped multi-paste offset */
4098 samplecnt_t offset = paste_count * duration;
4100 /* snap offset so pos + offset is aligned to the grid */
4101 MusicSample offset_pos (pos + offset, 0);
4102 snap_to(offset_pos, RoundUpMaybe);
4103 offset = offset_pos.sample - pos;
4109 Editor::get_grid_beat_divisions(samplepos_t position)
4111 switch (_grid_type) {
4112 case GridTypeBeatDiv32: return 32;
4113 case GridTypeBeatDiv28: return 28;
4114 case GridTypeBeatDiv24: return 24;
4115 case GridTypeBeatDiv20: return 20;
4116 case GridTypeBeatDiv16: return 16;
4117 case GridTypeBeatDiv14: return 14;
4118 case GridTypeBeatDiv12: return 12;
4119 case GridTypeBeatDiv10: return 10;
4120 case GridTypeBeatDiv8: return 8;
4121 case GridTypeBeatDiv7: return 7;
4122 case GridTypeBeatDiv6: return 6;
4123 case GridTypeBeatDiv5: return 5;
4124 case GridTypeBeatDiv4: return 4;
4125 case GridTypeBeatDiv3: return 3;
4126 case GridTypeBeatDiv2: return 2;
4127 case GridTypeBeat: return 1;
4128 case GridTypeBar: return 1;
4130 case GridTypeNone: return 0;
4131 case GridTypeTimecode: return 0;
4132 case GridTypeMinSec: return 0;
4133 case GridTypeCDFrame: return 0;
4139 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4140 if the grid is non-musical, returns 0.
4141 if the grid is snapped to bars, returns -1.
4142 @param event_state the current keyboard modifier mask.
4145 Editor::get_grid_music_divisions (uint32_t event_state)
4147 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4151 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4155 switch (_grid_type) {
4156 case GridTypeBeatDiv32: return 32;
4157 case GridTypeBeatDiv28: return 28;
4158 case GridTypeBeatDiv24: return 24;
4159 case GridTypeBeatDiv20: return 20;
4160 case GridTypeBeatDiv16: return 16;
4161 case GridTypeBeatDiv14: return 14;
4162 case GridTypeBeatDiv12: return 12;
4163 case GridTypeBeatDiv10: return 10;
4164 case GridTypeBeatDiv8: return 8;
4165 case GridTypeBeatDiv7: return 7;
4166 case GridTypeBeatDiv6: return 6;
4167 case GridTypeBeatDiv5: return 5;
4168 case GridTypeBeatDiv4: return 4;
4169 case GridTypeBeatDiv3: return 3;
4170 case GridTypeBeatDiv2: return 2;
4171 case GridTypeBeat: return 1;
4172 case GridTypeBar : return -1;
4174 case GridTypeNone: return 0;
4175 case GridTypeTimecode: return 0;
4176 case GridTypeMinSec: return 0;
4177 case GridTypeCDFrame: return 0;
4183 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4187 const unsigned divisions = get_grid_beat_divisions(position);
4189 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4192 switch (_grid_type) {
4194 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4197 const Meter& m = _session->tempo_map().meter_at_sample (position);
4198 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4206 return Temporal::Beats();
4210 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4214 ret = nudge_clock->current_duration (pos);
4215 next = ret + 1; /* XXXX fix me */
4221 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4223 ArdourDialog dialog (_("Playlist Deletion"));
4224 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4225 "If it is kept, its audio files will not be cleaned.\n"
4226 "If it is deleted, audio files used by it alone will be cleaned."),
4229 dialog.set_position (WIN_POS_CENTER);
4230 dialog.get_vbox()->pack_start (label);
4234 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4235 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4236 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4237 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4238 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4240 /* by default gtk uses the left most button */
4241 keep->grab_focus ();
4243 switch (dialog.run ()) {
4245 /* keep this and all remaining ones */
4250 /* delete this and all others */
4254 case RESPONSE_ACCEPT:
4255 /* delete the playlist */
4259 case RESPONSE_REJECT:
4260 /* keep the playlist */
4272 Editor::audio_region_selection_covers (samplepos_t where)
4274 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4275 if ((*a)->region()->covers (where)) {
4284 Editor::prepare_for_cleanup ()
4286 cut_buffer->clear_regions ();
4287 cut_buffer->clear_playlists ();
4289 selection->clear_regions ();
4290 selection->clear_playlists ();
4292 _regions->suspend_redisplay ();
4296 Editor::finish_cleanup ()
4298 _regions->resume_redisplay ();
4302 Editor::transport_loop_location()
4305 return _session->locations()->auto_loop_location();
4312 Editor::transport_punch_location()
4315 return _session->locations()->auto_punch_location();
4322 Editor::control_layout_scroll (GdkEventScroll* ev)
4324 /* Just forward to the normal canvas scroll method. The coordinate
4325 systems are different but since the canvas is always larger than the
4326 track headers, and aligned with the trackview area, this will work.
4328 In the not too distant future this layout is going away anyway and
4329 headers will be on the canvas.
4331 return canvas_scroll_event (ev, false);
4335 Editor::session_state_saved (string)
4338 _snapshots->redisplay ();
4342 Editor::maximise_editing_space ()
4348 Gtk::Window* toplevel = current_toplevel();
4351 toplevel->fullscreen ();
4357 Editor::restore_editing_space ()
4363 Gtk::Window* toplevel = current_toplevel();
4366 toplevel->unfullscreen();
4372 * Make new playlists for a given track and also any others that belong
4373 * to the same active route group with the `select' property.
4378 Editor::new_playlists (TimeAxisView* v)
4380 begin_reversible_command (_("new playlists"));
4381 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4382 _session->playlists()->get (playlists);
4383 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4384 commit_reversible_command ();
4388 * Use a copy of the current playlist for a given track and also any others that belong
4389 * to the same active route group with the `select' property.
4394 Editor::copy_playlists (TimeAxisView* v)
4396 begin_reversible_command (_("copy playlists"));
4397 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4398 _session->playlists()->get (playlists);
4399 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4400 commit_reversible_command ();
4403 /** Clear the current playlist for a given track and also any others that belong
4404 * to the same active route group with the `select' property.
4409 Editor::clear_playlists (TimeAxisView* v)
4411 begin_reversible_command (_("clear playlists"));
4412 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4413 _session->playlists()->get (playlists);
4414 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4415 commit_reversible_command ();
4419 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4421 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4425 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4427 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4431 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4433 atv.clear_playlist ();
4437 Editor::get_y_origin () const
4439 return vertical_adjustment.get_value ();
4442 /** Queue up a change to the viewport x origin.
4443 * @param sample New x origin.
4446 Editor::reset_x_origin (samplepos_t sample)
4448 pending_visual_change.add (VisualChange::TimeOrigin);
4449 pending_visual_change.time_origin = sample;
4450 ensure_visual_change_idle_handler ();
4454 Editor::reset_y_origin (double y)
4456 pending_visual_change.add (VisualChange::YOrigin);
4457 pending_visual_change.y_origin = y;
4458 ensure_visual_change_idle_handler ();
4462 Editor::reset_zoom (samplecnt_t spp)
4464 if (spp == samples_per_pixel) {
4468 pending_visual_change.add (VisualChange::ZoomLevel);
4469 pending_visual_change.samples_per_pixel = spp;
4470 ensure_visual_change_idle_handler ();
4474 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4476 reset_x_origin (sample);
4479 if (!no_save_visual) {
4480 undo_visual_stack.push_back (current_visual_state(false));
4484 Editor::VisualState::VisualState (bool with_tracks)
4485 : gui_state (with_tracks ? new GUIObjectState : 0)
4489 Editor::VisualState::~VisualState ()
4494 Editor::VisualState*
4495 Editor::current_visual_state (bool with_tracks)
4497 VisualState* vs = new VisualState (with_tracks);
4498 vs->y_position = vertical_adjustment.get_value();
4499 vs->samples_per_pixel = samples_per_pixel;
4500 vs->_leftmost_sample = _leftmost_sample;
4501 vs->zoom_focus = zoom_focus;
4504 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4511 Editor::undo_visual_state ()
4513 if (undo_visual_stack.empty()) {
4517 VisualState* vs = undo_visual_stack.back();
4518 undo_visual_stack.pop_back();
4521 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4524 use_visual_state (*vs);
4529 Editor::redo_visual_state ()
4531 if (redo_visual_stack.empty()) {
4535 VisualState* vs = redo_visual_stack.back();
4536 redo_visual_stack.pop_back();
4538 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4539 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4542 use_visual_state (*vs);
4547 Editor::swap_visual_state ()
4549 if (undo_visual_stack.empty()) {
4550 redo_visual_state ();
4552 undo_visual_state ();
4557 Editor::use_visual_state (VisualState& vs)
4559 PBD::Unwinder<bool> nsv (no_save_visual, true);
4560 DisplaySuspender ds;
4562 vertical_adjustment.set_value (vs.y_position);
4564 set_zoom_focus (vs.zoom_focus);
4565 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4568 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4570 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4571 (*i)->clear_property_cache();
4572 (*i)->reset_visual_state ();
4576 _routes->update_visibility ();
4579 /** This is the core function that controls the zoom level of the canvas. It is called
4580 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4581 * @param spp new number of samples per pixel
4584 Editor::set_samples_per_pixel (samplecnt_t spp)
4590 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4591 const samplecnt_t lots_of_pixels = 4000;
4593 /* if the zoom level is greater than what you'd get trying to display 3
4594 * days of audio on a really big screen, then it's too big.
4597 if (spp * lots_of_pixels > three_days) {
4601 samples_per_pixel = spp;
4605 Editor::on_samples_per_pixel_changed ()
4607 bool const showing_time_selection = selection->time.length() > 0;
4609 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4610 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4611 (*i)->reshow_selection (selection->time);
4615 ZoomChanged (); /* EMIT_SIGNAL */
4617 ArdourCanvas::GtkCanvasViewport* c;
4619 c = get_track_canvas();
4621 c->canvas()->zoomed ();
4624 if (playhead_cursor) {
4625 playhead_cursor->set_position (playhead_cursor->current_sample ());
4628 refresh_location_display();
4629 _summary->set_overlays_dirty ();
4631 update_marker_labels ();
4637 Editor::playhead_cursor_sample () const
4639 return playhead_cursor->current_sample();
4643 Editor::queue_visual_videotimeline_update ()
4645 pending_visual_change.add (VisualChange::VideoTimeline);
4646 ensure_visual_change_idle_handler ();
4650 Editor::ensure_visual_change_idle_handler ()
4652 if (pending_visual_change.idle_handler_id < 0) {
4653 /* see comment in add_to_idle_resize above. */
4654 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4655 pending_visual_change.being_handled = false;
4660 Editor::_idle_visual_changer (void* arg)
4662 return static_cast<Editor*>(arg)->idle_visual_changer ();
4666 Editor::pre_render ()
4668 visual_change_queued = false;
4670 if (pending_visual_change.pending != 0) {
4671 ensure_visual_change_idle_handler();
4676 Editor::idle_visual_changer ()
4678 pending_visual_change.idle_handler_id = -1;
4680 if (pending_visual_change.pending == 0) {
4684 /* set_horizontal_position() below (and maybe other calls) call
4685 gtk_main_iteration(), so it's possible that a signal will be handled
4686 half-way through this method. If this signal wants an
4687 idle_visual_changer we must schedule another one after this one, so
4688 mark the idle_handler_id as -1 here to allow that. Also make a note
4689 that we are doing the visual change, so that changes in response to
4690 super-rapid-screen-update can be dropped if we are still processing
4694 if (visual_change_queued) {
4698 pending_visual_change.being_handled = true;
4700 VisualChange vc = pending_visual_change;
4702 pending_visual_change.pending = (VisualChange::Type) 0;
4704 visual_changer (vc);
4706 pending_visual_change.being_handled = false;
4708 visual_change_queued = true;
4710 return 0; /* this is always a one-shot call */
4714 Editor::visual_changer (const VisualChange& vc)
4717 * Changed first so the correct horizontal canvas position is calculated in
4718 * Editor::set_horizontal_position
4720 if (vc.pending & VisualChange::ZoomLevel) {
4721 set_samples_per_pixel (vc.samples_per_pixel);
4724 if (vc.pending & VisualChange::TimeOrigin) {
4725 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4726 set_horizontal_position (new_time_origin);
4729 if (vc.pending & VisualChange::YOrigin) {
4730 vertical_adjustment.set_value (vc.y_origin);
4734 * Now the canvas is in the final state before render the canvas items that
4735 * support the Item::prepare_for_render interface can calculate the correct
4736 * item to visible canvas intersection.
4738 if (vc.pending & VisualChange::ZoomLevel) {
4739 on_samples_per_pixel_changed ();
4741 compute_fixed_ruler_scale ();
4743 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4744 update_tempo_based_rulers ();
4747 if (!(vc.pending & VisualChange::ZoomLevel)) {
4748 /* If the canvas is not being zoomed then the canvas items will not change
4749 * and cause Item::prepare_for_render to be called so do it here manually.
4750 * Not ideal, but I can't think of a better solution atm.
4752 _track_canvas->prepare_for_render();
4755 /* If we are only scrolling vertically there is no need to update these */
4756 if (vc.pending != VisualChange::YOrigin) {
4757 update_fixed_rulers ();
4758 redisplay_grid (true);
4760 /* video frames & position need to be updated for zoom, horiz-scroll
4761 * and (explicitly) VisualChange::VideoTimeline.
4763 update_video_timeline();
4766 _summary->set_overlays_dirty ();
4769 struct EditorOrderTimeAxisSorter {
4770 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4771 return a->order () < b->order ();
4776 Editor::sort_track_selection (TrackViewList& sel)
4778 EditorOrderTimeAxisSorter cmp;
4783 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4786 samplepos_t where = 0;
4787 EditPoint ep = _edit_point;
4789 if (Profile->get_mixbus()) {
4790 if (ep == EditAtSelectedMarker) {
4791 ep = EditAtPlayhead;
4795 if (from_outside_canvas && (ep == EditAtMouse)) {
4796 ep = EditAtPlayhead;
4797 } else if (from_context_menu && (ep == EditAtMouse)) {
4798 return canvas_event_sample (&context_click_event, 0, 0);
4801 if (entered_marker) {
4802 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4803 return entered_marker->position();
4806 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4807 ep = EditAtSelectedMarker;
4810 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4811 ep = EditAtPlayhead;
4814 MusicSample snap_mf (0, 0);
4817 case EditAtPlayhead:
4818 if (_dragging_playhead) {
4819 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4820 where = playhead_cursor->current_sample();
4822 where = _session->audible_sample();
4824 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4827 case EditAtSelectedMarker:
4828 if (!selection->markers.empty()) {
4830 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4833 where = loc->start();
4837 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4845 if (!mouse_sample (where, ignored)) {
4846 /* XXX not right but what can we do ? */
4849 snap_mf.sample = where;
4851 where = snap_mf.sample;
4852 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4860 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4862 if (!_session) return;
4864 begin_reversible_command (cmd);
4868 if ((tll = transport_loop_location()) == 0) {
4869 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4870 XMLNode &before = _session->locations()->get_state();
4871 _session->locations()->add (loc, true);
4872 _session->set_auto_loop_location (loc);
4873 XMLNode &after = _session->locations()->get_state();
4874 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4876 XMLNode &before = tll->get_state();
4877 tll->set_hidden (false, this);
4878 tll->set (start, end);
4879 XMLNode &after = tll->get_state();
4880 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4883 commit_reversible_command ();
4887 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4889 if (!_session) return;
4891 begin_reversible_command (cmd);
4895 if ((tpl = transport_punch_location()) == 0) {
4896 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4897 XMLNode &before = _session->locations()->get_state();
4898 _session->locations()->add (loc, true);
4899 _session->set_auto_punch_location (loc);
4900 XMLNode &after = _session->locations()->get_state();
4901 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4903 XMLNode &before = tpl->get_state();
4904 tpl->set_hidden (false, this);
4905 tpl->set (start, end);
4906 XMLNode &after = tpl->get_state();
4907 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4910 commit_reversible_command ();
4913 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4914 * @param rs List to which found regions are added.
4915 * @param where Time to look at.
4916 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4919 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4921 const TrackViewList* tracks;
4924 tracks = &track_views;
4929 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4931 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4934 boost::shared_ptr<Track> tr;
4935 boost::shared_ptr<Playlist> pl;
4937 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4939 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4941 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4942 RegionView* rv = rtv->view()->find_view (*i);
4953 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4955 const TrackViewList* tracks;
4958 tracks = &track_views;
4963 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4964 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4966 boost::shared_ptr<Track> tr;
4967 boost::shared_ptr<Playlist> pl;
4969 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4971 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4973 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4975 RegionView* rv = rtv->view()->find_view (*i);
4986 /** Get regions using the following method:
4988 * Make a region list using:
4989 * (a) any selected regions
4990 * (b) the intersection of any selected tracks and the edit point(*)
4991 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4993 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4995 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4999 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
5001 RegionSelection regions;
5003 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5004 regions.add (entered_regionview);
5006 regions = selection->regions;
5009 if (regions.empty()) {
5010 TrackViewList tracks = selection->tracks;
5012 if (!tracks.empty()) {
5013 /* no region selected or entered, but some selected tracks:
5014 * act on all regions on the selected tracks at the edit point
5016 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
5017 get_regions_at(regions, where, tracks);
5024 /** Get regions using the following method:
5026 * Make a region list using:
5027 * (a) any selected regions
5028 * (b) the intersection of any selected tracks and the edit point(*)
5029 * (c) if neither exists, then whatever region is under the mouse
5031 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5033 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5036 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
5038 RegionSelection regions;
5040 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5041 regions.add (entered_regionview);
5043 regions = selection->regions;
5046 if (regions.empty()) {
5047 TrackViewList tracks = selection->tracks;
5049 if (!tracks.empty()) {
5050 /* no region selected or entered, but some selected tracks:
5051 * act on all regions on the selected tracks at the edit point
5053 get_regions_at(regions, pos, tracks);
5060 /** Start with regions that are selected, or the entered regionview if none are selected.
5061 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5062 * of the regions that we started with.
5066 Editor::get_regions_from_selection_and_entered () const
5068 RegionSelection regions = selection->regions;
5070 if (regions.empty() && entered_regionview) {
5071 regions.add (entered_regionview);
5078 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5080 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5081 RouteTimeAxisView* rtav;
5083 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5084 boost::shared_ptr<Playlist> pl;
5085 std::vector<boost::shared_ptr<Region> > results;
5086 boost::shared_ptr<Track> tr;
5088 if ((tr = rtav->track()) == 0) {
5093 if ((pl = (tr->playlist())) != 0) {
5094 boost::shared_ptr<Region> r = pl->region_by_id (id);
5096 RegionView* rv = rtav->view()->find_view (r);
5098 regions.push_back (rv);
5107 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5110 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5111 MidiTimeAxisView* mtav;
5113 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5115 mtav->get_per_region_note_selection (selection);
5122 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5124 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5126 RouteTimeAxisView* tatv;
5128 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5130 boost::shared_ptr<Playlist> pl;
5131 vector<boost::shared_ptr<Region> > results;
5133 boost::shared_ptr<Track> tr;
5135 if ((tr = tatv->track()) == 0) {
5140 if ((pl = (tr->playlist())) != 0) {
5141 if (src_comparison) {
5142 pl->get_source_equivalent_regions (region, results);
5144 pl->get_region_list_equivalent_regions (region, results);
5148 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5149 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5150 regions.push_back (marv);
5159 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5161 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5162 RouteTimeAxisView* tatv;
5163 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5164 if (!tatv->track()) {
5167 RegionView* marv = tatv->view()->find_view (region);
5177 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5179 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5180 RouteTimeAxisView* rtav;
5181 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5182 if (rtav->route() == route) {
5191 Editor::show_rhythm_ferret ()
5193 if (rhythm_ferret == 0) {
5194 rhythm_ferret = new RhythmFerret(*this);
5197 rhythm_ferret->set_session (_session);
5198 rhythm_ferret->show ();
5199 rhythm_ferret->present ();
5203 Editor::first_idle ()
5205 MessageDialog* dialog = 0;
5207 if (track_views.size() > 1) {
5208 Timers::TimerSuspender t;
5209 dialog = new MessageDialog (
5210 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5214 ARDOUR_UI::instance()->flush_pending (60);
5217 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5221 /* now that all regionviews should exist, setup region selection */
5225 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5226 /* this is cumulative: rs is NOT cleared each time */
5227 get_regionviews_by_id (*pr, rs);
5230 selection->set (rs);
5232 /* first idle adds route children (automation tracks), so we need to redisplay here */
5233 _routes->redisplay ();
5237 if (_session->undo_depth() == 0) {
5238 undo_action->set_sensitive(false);
5240 redo_action->set_sensitive(false);
5241 begin_selection_op_history ();
5247 Editor::_idle_resize (gpointer arg)
5249 return ((Editor*)arg)->idle_resize ();
5253 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5255 if (resize_idle_id < 0) {
5256 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5257 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5258 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5260 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5261 _pending_resize_amount = 0;
5264 /* make a note of the smallest resulting height, so that we can clamp the
5265 lower limit at TimeAxisView::hSmall */
5267 int32_t min_resulting = INT32_MAX;
5269 _pending_resize_amount += h;
5270 _pending_resize_view = view;
5272 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5274 if (selection->tracks.contains (_pending_resize_view)) {
5275 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5276 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5280 if (min_resulting < 0) {
5285 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5286 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5290 /** Handle pending resizing of tracks */
5292 Editor::idle_resize ()
5294 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5296 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5297 selection->tracks.contains (_pending_resize_view)) {
5299 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5300 if (*i != _pending_resize_view) {
5301 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5306 _pending_resize_amount = 0;
5307 _group_tabs->set_dirty ();
5308 resize_idle_id = -1;
5316 ENSURE_GUI_THREAD (*this, &Editor::located);
5319 playhead_cursor->set_position (_session->audible_sample ());
5320 if (_follow_playhead && !_pending_initial_locate) {
5321 reset_x_origin_to_follow_playhead ();
5325 _pending_locate_request = false;
5326 _pending_initial_locate = false;
5327 _last_update_time = 0;
5331 Editor::region_view_added (RegionView * rv)
5333 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5335 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5336 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5337 if (rv->region()->id () == (*rnote).first) {
5338 mrv->select_notes ((*rnote).second);
5339 selection->pending_midi_note_selection.erase(rnote);
5345 _summary->set_background_dirty ();
5347 mark_region_boundary_cache_dirty ();
5351 Editor::region_view_removed ()
5353 _summary->set_background_dirty ();
5355 mark_region_boundary_cache_dirty ();
5359 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5361 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5362 if ((*j)->stripable() == s) {
5371 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5373 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5374 if ((*j)->control() == c) {
5378 TimeAxisView::Children kids = (*j)->get_child_list ();
5380 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5381 if ((*k)->control() == c) {
5391 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5395 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5396 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5406 Editor::suspend_route_redisplay ()
5409 _routes->suspend_redisplay();
5414 Editor::resume_route_redisplay ()
5417 _routes->redisplay(); // queue redisplay
5418 _routes->resume_redisplay();
5423 Editor::add_vcas (VCAList& vlist)
5427 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5428 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5431 add_stripables (sl);
5435 Editor::add_routes (RouteList& rlist)
5439 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5443 add_stripables (sl);
5447 Editor::add_stripables (StripableList& sl)
5449 list<TimeAxisView*> new_views;
5450 boost::shared_ptr<VCA> v;
5451 boost::shared_ptr<Route> r;
5452 TrackViewList new_selection;
5453 bool from_scratch = (track_views.size() == 0);
5455 sl.sort (Stripable::Sorter());
5457 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5459 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5461 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5463 new_views.push_back (vtv);
5465 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5467 if (r->is_auditioner() || r->is_monitor()) {
5471 RouteTimeAxisView* rtv;
5472 DataType dt = r->input()->default_type();
5474 if (dt == ARDOUR::DataType::AUDIO) {
5475 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5477 } else if (dt == ARDOUR::DataType::MIDI) {
5478 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5481 throw unknown_type();
5484 new_views.push_back (rtv);
5485 track_views.push_back (rtv);
5486 new_selection.push_back (rtv);
5488 rtv->effective_gain_display ();
5490 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5491 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5495 if (new_views.size() > 0) {
5496 _routes->time_axis_views_added (new_views);
5497 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5500 /* note: !new_selection.empty() means that we got some routes rather
5504 if (!from_scratch && !new_selection.empty()) {
5505 selection->set (new_selection);
5506 begin_selection_op_history();
5509 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5510 show_editor_mixer (true);
5513 editor_list_button.set_sensitive (true);
5517 Editor::timeaxisview_deleted (TimeAxisView *tv)
5519 if (tv == entered_track) {
5523 if (_session && _session->deletion_in_progress()) {
5524 /* the situation is under control */
5528 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5530 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5532 _routes->route_removed (tv);
5534 TimeAxisView::Children c = tv->get_child_list ();
5535 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5536 if (entered_track == i->get()) {
5541 /* remove it from the list of track views */
5543 TrackViewList::iterator i;
5545 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5546 i = track_views.erase (i);
5549 /* update whatever the current mixer strip is displaying, if revelant */
5551 boost::shared_ptr<Route> route;
5554 route = rtav->route ();
5557 if (current_mixer_strip && current_mixer_strip->route() == route) {
5559 TimeAxisView* next_tv;
5561 if (track_views.empty()) {
5563 } else if (i == track_views.end()) {
5564 next_tv = track_views.front();
5569 // skip VCAs (cannot be selected, n/a in editor-mixer)
5570 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5571 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5572 next_tv = track_views.front();
5574 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5575 /* just in case: no master, only a VCA remains */
5581 set_selected_mixer_strip (*next_tv);
5583 /* make the editor mixer strip go away setting the
5584 * button to inactive (which also unticks the menu option)
5587 ActionManager::uncheck_toggleaction ("Editor/show-editor-mixer");
5593 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5599 DisplaySuspender ds;
5600 PresentationInfo::ChangeSuspender cs;
5602 if (apply_to_selection) {
5603 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5605 TrackSelection::iterator j = i;
5608 hide_track_in_display (*i, false);
5613 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5615 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5616 /* this will hide the mixer strip */
5617 set_selected_mixer_strip (*tv);
5620 _routes->hide_track_in_display (*tv);
5625 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5630 _routes->show_track_in_display (*tv);
5631 if (move_into_view) {
5632 ensure_time_axis_view_is_visible (*tv, false);
5637 Editor::sync_track_view_list_and_routes ()
5639 track_views = TrackViewList (_routes->views ());
5641 _summary->set_background_dirty();
5642 _group_tabs->set_dirty ();
5644 return false; // do not call again (until needed)
5648 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5650 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5655 /** Find a StripableTimeAxisView by the ID of its stripable */
5656 StripableTimeAxisView*
5657 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5659 StripableTimeAxisView* v;
5661 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5662 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5663 if(v->stripable()->id() == id) {
5673 Editor::fit_route_group (RouteGroup *g)
5675 TrackViewList ts = axis_views_from_routes (g->route_list ());
5680 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5682 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5685 _session->cancel_audition ();
5689 if (_session->is_auditioning()) {
5690 _session->cancel_audition ();
5691 if (r == last_audition_region) {
5696 _session->audition_region (r);
5697 last_audition_region = r;
5702 Editor::hide_a_region (boost::shared_ptr<Region> r)
5704 r->set_hidden (true);
5708 Editor::show_a_region (boost::shared_ptr<Region> r)
5710 r->set_hidden (false);
5714 Editor::audition_region_from_region_list ()
5716 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5720 Editor::hide_region_from_region_list ()
5722 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5726 Editor::show_region_in_region_list ()
5728 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5732 Editor::step_edit_status_change (bool yn)
5735 start_step_editing ();
5737 stop_step_editing ();
5742 Editor::start_step_editing ()
5744 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5748 Editor::stop_step_editing ()
5750 step_edit_connection.disconnect ();
5754 Editor::check_step_edit ()
5756 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5757 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5759 mtv->check_step_edit ();
5763 return true; // do it again, till we stop
5767 Editor::scroll_press (Direction dir)
5769 ++_scroll_callbacks;
5771 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5772 /* delay the first auto-repeat */
5778 scroll_backward (1);
5786 scroll_up_one_track ();
5790 scroll_down_one_track ();
5794 /* do hacky auto-repeat */
5795 if (!_scroll_connection.connected ()) {
5797 _scroll_connection = Glib::signal_timeout().connect (
5798 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5801 _scroll_callbacks = 0;
5808 Editor::scroll_release ()
5810 _scroll_connection.disconnect ();
5813 /** Queue a change for the Editor viewport x origin to follow the playhead */
5815 Editor::reset_x_origin_to_follow_playhead ()
5817 samplepos_t const sample = playhead_cursor->current_sample ();
5819 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5821 if (_session->transport_speed() < 0) {
5823 if (sample > (current_page_samples() / 2)) {
5824 center_screen (sample-(current_page_samples()/2));
5826 center_screen (current_page_samples()/2);
5833 if (sample < _leftmost_sample) {
5835 if (_session->transport_rolling()) {
5836 /* rolling; end up with the playhead at the right of the page */
5837 l = sample - current_page_samples ();
5839 /* not rolling: end up with the playhead 1/4 of the way along the page */
5840 l = sample - current_page_samples() / 4;
5844 if (_session->transport_rolling()) {
5845 /* rolling: end up with the playhead on the left of the page */
5848 /* not rolling: end up with the playhead 3/4 of the way along the page */
5849 l = sample - 3 * current_page_samples() / 4;
5857 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5863 Editor::super_rapid_screen_update ()
5865 if (!_session || !_session->engine().running()) {
5869 /* METERING / MIXER STRIPS */
5871 /* update track meters, if required */
5872 if (contents().is_mapped() && meters_running) {
5873 RouteTimeAxisView* rtv;
5874 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5875 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5876 rtv->fast_update ();
5881 /* and any current mixer strip */
5882 if (current_mixer_strip) {
5883 current_mixer_strip->fast_update ();
5886 bool latent_locate = false;
5887 samplepos_t sample = _session->audible_sample (&latent_locate);
5888 const int64_t now = g_get_monotonic_time ();
5891 if (_session->exporting ()) {
5892 /* freewheel/export may be faster or slower than transport_speed() / SR.
5893 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5895 _last_update_time = 0;
5898 if (!_session->transport_rolling () || _session->is_auditioning ()) {
5899 /* Do not interpolate the playhead position; just set it */
5900 _last_update_time = 0;
5903 if (_last_update_time > 0) {
5904 /* interpolate and smoothen playhead position */
5905 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5906 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5907 err = sample - guess;
5909 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5910 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5913 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5915 err, _err_screen_engine);
5920 _err_screen_engine = 0;
5923 if (err > 8192 || latent_locate) {
5924 // in case of x-runs or freewheeling
5925 _last_update_time = 0;
5926 sample = _session->audible_sample ();
5928 _last_update_time = now;
5931 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5933 MusicSample where (sample, 0);
5934 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5935 snapped_cursor->hide ();
5936 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5937 /* EditAtPlayhead does not snap */
5938 } else if (_edit_point == EditAtSelectedMarker) {
5939 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5940 * however, the current editing code -does- snap so I'll draw it that way for now.
5942 if (!selection->markers.empty()) {
5943 MusicSample ms (selection->markers.front()->position(), 0);
5944 snap_to (ms); // should use snap_to_with_modifier?
5945 snapped_cursor->set_position (ms.sample);
5946 snapped_cursor->show ();
5948 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5949 snapped_cursor->show ();
5950 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5951 snapped_cursor->hide ();
5954 /* There are a few reasons why we might not update the playhead / viewport stuff:
5956 * 1. we don't update things when there's a pending locate request, otherwise
5957 * when the editor requests a locate there is a chance that this method
5958 * will move the playhead before the locate request is processed, causing
5960 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5961 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5963 if (_pending_locate_request) {
5964 _last_update_time = 0;
5968 if (_dragging_playhead) {
5969 _last_update_time = 0;
5973 if (playhead_cursor->current_sample () == sample) {
5977 playhead_cursor->set_position (sample);
5979 if (_session->requested_return_sample() >= 0) {
5980 _last_update_time = 0;
5984 if (!_follow_playhead || pending_visual_change.being_handled) {
5985 /* We only do this if we aren't already
5986 * handling a visual change (ie if
5987 * pending_visual_change.being_handled is
5988 * false) so that these requests don't stack
5989 * up there are too many of them to handle in
5995 if (!_stationary_playhead) {
5996 reset_x_origin_to_follow_playhead ();
5998 samplepos_t const sample = playhead_cursor->current_sample ();
5999 double target = ((double)sample - (double)current_page_samples() / 2.0);
6000 if (target <= 0.0) {
6003 /* compare to EditorCursor::set_position() */
6004 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
6005 double const new_pos = sample_to_pixel_unrounded (target);
6006 if (rint (new_pos) != rint (old_pos)) {
6007 reset_x_origin (pixel_to_sample (new_pos));
6014 Editor::session_going_away ()
6016 _have_idled = false;
6018 _session_connections.drop_connections ();
6020 super_rapid_screen_update_connection.disconnect ();
6022 selection->clear ();
6023 cut_buffer->clear ();
6025 clicked_regionview = 0;
6026 clicked_axisview = 0;
6027 clicked_routeview = 0;
6028 entered_regionview = 0;
6030 _last_update_time = 0;
6033 playhead_cursor->hide ();
6035 /* rip everything out of the list displays */
6039 _route_groups->clear ();
6041 /* do this first so that deleting a track doesn't reset cms to null
6042 and thus cause a leak.
6045 if (current_mixer_strip) {
6046 if (current_mixer_strip->get_parent() != 0) {
6047 global_hpacker.remove (*current_mixer_strip);
6049 delete current_mixer_strip;
6050 current_mixer_strip = 0;
6053 /* delete all trackviews */
6055 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6058 track_views.clear ();
6060 nudge_clock->set_session (0);
6062 editor_list_button.set_active(false);
6063 editor_list_button.set_sensitive(false);
6065 /* clear tempo/meter rulers */
6066 remove_metric_marks ();
6067 clear_marker_display ();
6073 stop_step_editing ();
6077 /* get rid of any existing editor mixer strip */
6079 WindowTitle title(Glib::get_application_name());
6080 title += _("Editor");
6082 own_window()->set_title (title.get_string());
6085 SessionHandlePtr::session_going_away ();
6089 Editor::trigger_script (int i)
6091 LuaInstance::instance()-> call_action (i);
6095 Editor::show_editor_list (bool yn)
6098 _editor_list_vbox.show ();
6100 _editor_list_vbox.hide ();
6105 Editor::change_region_layering_order (bool from_context_menu)
6107 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6109 if (!clicked_routeview) {
6110 if (layering_order_editor) {
6111 layering_order_editor->hide ();
6116 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6122 boost::shared_ptr<Playlist> pl = track->playlist();
6128 if (layering_order_editor == 0) {
6129 layering_order_editor = new RegionLayeringOrderEditor (*this);
6132 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6133 layering_order_editor->maybe_present ();
6137 Editor::update_region_layering_order_editor ()
6139 if (layering_order_editor && layering_order_editor->is_visible ()) {
6140 change_region_layering_order (true);
6145 Editor::setup_fade_images ()
6147 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6148 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6149 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6150 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6151 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6153 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6154 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6155 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6156 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6157 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6161 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6163 Editor::action_menu_item (std::string const & name)
6165 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6168 return *manage (a->create_menu_item ());
6172 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6174 EventBox* b = manage (new EventBox);
6175 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6176 Label* l = manage (new Label (name));
6180 _the_notebook.append_page (widget, *b);
6184 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6186 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6187 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6190 if (ev->type == GDK_2BUTTON_PRESS) {
6192 /* double-click on a notebook tab shrinks or expands the notebook */
6194 if (_notebook_shrunk) {
6195 if (pre_notebook_shrink_pane_width) {
6196 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6198 _notebook_shrunk = false;
6200 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6202 /* this expands the LHS of the edit pane to cover the notebook
6203 PAGE but leaves the tabs visible.
6205 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6206 _notebook_shrunk = true;
6214 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6216 using namespace Menu_Helpers;
6218 MenuList& items = _control_point_context_menu.items ();
6221 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6222 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6223 if (!can_remove_control_point (item)) {
6224 items.back().set_sensitive (false);
6227 _control_point_context_menu.popup (event->button.button, event->button.time);
6231 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6233 using namespace Menu_Helpers;
6235 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6240 /* We need to get the selection here and pass it to the operations, since
6241 popping up the menu will cause a region leave event which clears
6242 entered_regionview. */
6244 MidiRegionView& mrv = note->region_view();
6245 const RegionSelection rs = get_regions_from_selection_and_entered ();
6246 const uint32_t sel_size = mrv.selection_size ();
6248 MenuList& items = _note_context_menu.items();
6252 items.push_back(MenuElem(_("Delete"),
6253 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6256 items.push_back(MenuElem(_("Edit..."),
6257 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6258 if (sel_size != 1) {
6259 items.back().set_sensitive (false);
6262 items.push_back(MenuElem(_("Transpose..."),
6263 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6266 items.push_back(MenuElem(_("Legatize"),
6267 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6269 items.back().set_sensitive (false);
6272 items.push_back(MenuElem(_("Quantize..."),
6273 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6275 items.push_back(MenuElem(_("Remove Overlap"),
6276 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6278 items.back().set_sensitive (false);
6281 items.push_back(MenuElem(_("Transform..."),
6282 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6284 _note_context_menu.popup (event->button.button, event->button.time);
6288 Editor::zoom_vertical_modifier_released()
6290 _stepping_axis_view = 0;
6294 Editor::ui_parameter_changed (string parameter)
6296 if (parameter == "icon-set") {
6297 while (!_cursor_stack.empty()) {
6298 _cursor_stack.pop_back();
6300 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6301 _cursor_stack.push_back(_cursors->grabber);
6302 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6303 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6305 } else if (parameter == "draggable-playhead") {
6306 if (_verbose_cursor) {
6307 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6309 } else if (parameter == "use-note-bars-for-velocity") {
6310 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6311 _track_canvas->request_redraw (_track_canvas->visible_area());
6312 } else if (parameter == "use-note-color-for-velocity") {
6313 /* handled individually by each MidiRegionView */
6318 Editor::use_own_window (bool and_fill_it)
6320 bool new_window = !own_window();
6322 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6324 if (win && new_window) {
6325 win->set_name ("EditorWindow");
6327 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6329 // win->signal_realize().connect (*this, &Editor::on_realize);
6330 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6331 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6332 win->set_data ("ardour-bindings", bindings);
6337 DisplaySuspender ds;
6338 contents().show_all ();
6340 /* XXX: this is a bit unfortunate; it would probably
6341 be nicer if we could just call show () above rather
6342 than needing the show_all ()
6345 /* re-hide stuff if necessary */
6346 editor_list_button_toggled ();
6347 parameter_changed ("show-summary");
6348 parameter_changed ("show-group-tabs");
6349 parameter_changed ("show-zoom-tools");
6351 /* now reset all audio_time_axis heights, because widgets might need
6357 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6358 tv = (static_cast<TimeAxisView*>(*i));
6359 tv->reset_height ();
6362 if (current_mixer_strip) {
6363 current_mixer_strip->hide_things ();
6364 current_mixer_strip->parameter_changed ("mixer-element-visibility");