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_sources.h"
113 #include "editor_summary.h"
114 #include "enums_convert.h"
115 #include "export_report.h"
116 #include "global_port_matrix.h"
117 #include "gui_object.h"
118 #include "gui_thread.h"
119 #include "keyboard.h"
120 #include "luainstance.h"
122 #include "midi_region_view.h"
123 #include "midi_time_axis.h"
124 #include "mixer_strip.h"
125 #include "mixer_ui.h"
126 #include "mouse_cursors.h"
127 #include "note_base.h"
128 #include "playlist_selector.h"
129 #include "public_editor.h"
130 #include "quantize_dialog.h"
131 #include "region_layering_order_editor.h"
132 #include "rgb_macros.h"
133 #include "rhythm_ferret.h"
134 #include "route_sorter.h"
135 #include "selection.h"
136 #include "simple_progress_dialog.h"
138 #include "grid_lines.h"
139 #include "time_axis_view.h"
140 #include "time_info_box.h"
142 #include "ui_config.h"
144 #include "vca_time_axis.h"
145 #include "verbose_cursor.h"
147 #include "pbd/i18n.h"
150 using namespace ARDOUR;
151 using namespace ArdourWidgets;
152 using namespace ARDOUR_UI_UTILS;
155 using namespace Glib;
156 using namespace Gtkmm2ext;
157 using namespace Editing;
159 using PBD::internationalize;
161 using Gtkmm2ext::Keyboard;
163 double Editor::timebar_height = 15.0;
165 static const gchar *_grid_type_strings[] = {
174 N_("1/3 (8th triplet)"), // or "1/12" ?
175 N_("1/6 (16th triplet)"),
176 N_("1/12 (32nd triplet)"),
177 N_("1/24 (64th triplet)"),
178 N_("1/5 (8th quintuplet)"),
179 N_("1/10 (16th quintuplet)"),
180 N_("1/20 (32nd quintuplet)"),
181 N_("1/7 (8th septuplet)"),
182 N_("1/14 (16th septuplet)"),
183 N_("1/28 (32nd septuplet)"),
190 static const gchar *_edit_point_strings[] = {
197 static const gchar *_edit_mode_strings[] = {
205 static const gchar *_zoom_focus_strings[] = {
215 #ifdef USE_RUBBERBAND
216 static const gchar *_rb_opt_strings[] = {
219 N_("Balanced multitimbral mixture"),
220 N_("Unpitched percussion with stable notes"),
221 N_("Crisp monophonic instrumental"),
222 N_("Unpitched solo percussion"),
223 N_("Resample without preserving pitch"),
228 /* Robin says: this should be odd to accomodate cairo drawing offset (width/2 rounds up to pixel boundary) */
230 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
232 #define COMBO_TRIANGLE_WIDTH 11 // as-measured for win/linux.
236 : PublicEditor (global_hpacker)
237 , editor_mixer_strip_width (Wide)
238 , constructed (false)
239 , _playlist_selector (0)
241 , no_save_visual (false)
242 , _leftmost_sample (0)
243 , samples_per_pixel (2048)
244 , zoom_focus (ZoomFocusPlayhead)
245 , mouse_mode (MouseObject)
246 , pre_internal_grid_type (GridTypeBeat)
247 , pre_internal_snap_mode (SnapOff)
248 , internal_grid_type (GridTypeBeat)
249 , internal_snap_mode (SnapOff)
250 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
251 , _notebook_shrunk (false)
252 , location_marker_color (0)
253 , location_range_color (0)
254 , location_loop_color (0)
255 , location_punch_color (0)
256 , location_cd_marker_color (0)
258 , _show_marker_lines (false)
259 , clicked_axisview (0)
260 , clicked_routeview (0)
261 , clicked_regionview (0)
262 , clicked_selection (0)
263 , clicked_control_point (0)
264 , button_release_can_deselect (true)
265 , _mouse_changed_selection (false)
266 , _popup_region_menu_item (0)
268 , _track_canvas_viewport (0)
269 , within_track_canvas (false)
270 , _verbose_cursor (0)
274 , range_marker_group (0)
275 , transport_marker_group (0)
276 , cd_marker_group (0)
277 , _time_markers_group (0)
278 , hv_scroll_group (0)
280 , cursor_scroll_group (0)
281 , no_scroll_group (0)
282 , _trackview_group (0)
283 , _drag_motion_group (0)
284 , _canvas_drop_zone (0)
285 , no_ruler_shown_update (false)
286 , ruler_grabbed_widget (0)
288 , minsec_mark_interval (0)
289 , minsec_mark_modulo (0)
291 , timecode_ruler_scale (timecode_show_many_hours)
292 , timecode_mark_modulo (0)
293 , timecode_nmarks (0)
294 , _samples_ruler_interval (0)
295 , bbt_ruler_scale (bbt_show_many)
298 , bbt_bar_helper_on (0)
299 , bbt_accent_modulo (0)
304 , visible_timebars (0)
305 , editor_ruler_menu (0)
309 , range_marker_bar (0)
310 , transport_marker_bar (0)
312 , minsec_label (_("Mins:Secs"))
313 , bbt_label (_("Bars:Beats"))
314 , timecode_label (_("Timecode"))
315 , samples_label (_("Samples"))
316 , tempo_label (_("Tempo"))
317 , meter_label (_("Meter"))
318 , mark_label (_("Location Markers"))
319 , range_mark_label (_("Range Markers"))
320 , transport_mark_label (_("Loop/Punch Ranges"))
321 , cd_mark_label (_("CD Markers"))
322 , videotl_label (_("Video Timeline"))
325 , playhead_cursor (0)
326 , _region_boundary_cache_dirty (true)
327 , edit_packer (4, 4, true)
328 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
329 , horizontal_adjustment (0.0, 0.0, 1e16)
330 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
331 , controls_layout (unused_adjustment, vertical_adjustment)
332 , _scroll_callbacks (0)
333 , _visible_canvas_width (0)
334 , _visible_canvas_height (0)
335 , _full_canvas_height (0)
336 , edit_controls_left_menu (0)
337 , edit_controls_right_menu (0)
338 , visual_change_queued(false)
339 , _last_update_time (0)
340 , _err_screen_engine (0)
341 , cut_buffer_start (0)
342 , cut_buffer_length (0)
343 , button_bindings (0)
344 , last_paste_pos (-1)
347 , current_interthread_info (0)
348 , analysis_window (0)
349 , select_new_marker (false)
351 , scrubbing_direction (0)
352 , scrub_reversals (0)
353 , scrub_reverse_distance (0)
354 , have_pending_keyboard_selection (false)
355 , pending_keyboard_selection_start (0)
356 , _grid_type (GridTypeBeat)
357 , _snap_mode (SnapOff)
358 , ignore_gui_changes (false)
359 , _drags (new DragManager (this))
361 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
362 , _dragging_playhead (false)
363 , _dragging_edit_point (false)
364 , _follow_playhead (true)
365 , _stationary_playhead (false)
368 , global_rect_group (0)
369 , time_line_group (0)
370 , tempo_marker_menu (0)
371 , meter_marker_menu (0)
373 , range_marker_menu (0)
374 , new_transport_marker_menu (0)
375 , marker_menu_item (0)
376 , bbt_beat_subdivision (4)
377 , _visible_track_count (-1)
378 , toolbar_selection_clock_table (2,3)
379 , automation_mode_button (_("mode"))
380 , selection (new Selection (this, true))
381 , cut_buffer (new Selection (this, false))
382 , _selection_memento (new SelectionMemento())
383 , _all_region_actions_sensitized (false)
384 , _ignore_region_action (false)
385 , _last_region_menu_was_main (false)
386 , _track_selection_change_without_scroll (false)
387 , _editor_track_selection_change_without_scroll (false)
388 , cd_marker_bar_drag_rect (0)
389 , range_bar_drag_rect (0)
390 , transport_bar_drag_rect (0)
391 , transport_bar_range_rect (0)
392 , transport_bar_preroll_rect (0)
393 , transport_bar_postroll_rect (0)
394 , transport_loop_range_rect (0)
395 , transport_punch_range_rect (0)
396 , transport_punchin_line (0)
397 , transport_punchout_line (0)
398 , transport_preroll_rect (0)
399 , transport_postroll_rect (0)
401 , rubberband_rect (0)
407 , autoscroll_horizontal_allowed (false)
408 , autoscroll_vertical_allowed (false)
410 , autoscroll_widget (0)
411 , show_gain_after_trim (false)
412 , selection_op_cmd_depth (0)
413 , selection_op_history_it (0)
414 , no_save_instant (false)
416 , current_mixer_strip (0)
417 , show_editor_mixer_when_tracks_arrive (false)
418 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
419 , current_stepping_trackview (0)
420 , last_track_height_step_timestamp (0)
422 , entered_regionview (0)
423 , clear_entered_track (false)
424 , _edit_point (EditAtMouse)
425 , meters_running (false)
427 , _have_idled (false)
428 , resize_idle_id (-1)
429 , _pending_resize_amount (0)
430 , _pending_resize_view (0)
431 , _pending_locate_request (false)
432 , _pending_initial_locate (false)
436 , layering_order_editor (0)
437 , _last_cut_copy_source_track (0)
438 , _region_selection_change_updates_region_list (true)
440 , _following_mixer_selection (false)
441 , _control_point_toggled_on_press (false)
442 , _stepping_axis_view (0)
443 , quantize_dialog (0)
444 , _main_menu_disabler (0)
446 /* we are a singleton */
448 PublicEditor::_instance = this;
452 last_event_time.tv_sec = 0;
453 last_event_time.tv_usec = 0;
455 selection_op_history.clear();
458 grid_type_strings = I18N (_grid_type_strings);
459 zoom_focus_strings = I18N (_zoom_focus_strings);
460 edit_mode_strings = I18N (_edit_mode_strings);
461 edit_point_strings = I18N (_edit_point_strings);
462 #ifdef USE_RUBBERBAND
463 rb_opt_strings = I18N (_rb_opt_strings);
467 build_edit_mode_menu();
468 build_zoom_focus_menu();
469 build_track_count_menu();
470 build_grid_type_menu();
471 build_edit_point_menu();
473 location_marker_color = UIConfiguration::instance().color ("location marker");
474 location_range_color = UIConfiguration::instance().color ("location range");
475 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
476 location_loop_color = UIConfiguration::instance().color ("location loop");
477 location_punch_color = UIConfiguration::instance().color ("location punch");
479 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
481 TimeAxisView::setup_sizes ();
482 ArdourMarker::setup_sizes (timebar_height);
483 TempoCurve::setup_sizes (timebar_height);
485 bbt_label.set_name ("EditorRulerLabel");
486 bbt_label.set_size_request (-1, (int)timebar_height);
487 bbt_label.set_alignment (1.0, 0.5);
488 bbt_label.set_padding (5,0);
490 bbt_label.set_no_show_all();
491 minsec_label.set_name ("EditorRulerLabel");
492 minsec_label.set_size_request (-1, (int)timebar_height);
493 minsec_label.set_alignment (1.0, 0.5);
494 minsec_label.set_padding (5,0);
495 minsec_label.hide ();
496 minsec_label.set_no_show_all();
497 timecode_label.set_name ("EditorRulerLabel");
498 timecode_label.set_size_request (-1, (int)timebar_height);
499 timecode_label.set_alignment (1.0, 0.5);
500 timecode_label.set_padding (5,0);
501 timecode_label.hide ();
502 timecode_label.set_no_show_all();
503 samples_label.set_name ("EditorRulerLabel");
504 samples_label.set_size_request (-1, (int)timebar_height);
505 samples_label.set_alignment (1.0, 0.5);
506 samples_label.set_padding (5,0);
507 samples_label.hide ();
508 samples_label.set_no_show_all();
510 tempo_label.set_name ("EditorRulerLabel");
511 tempo_label.set_size_request (-1, (int)timebar_height);
512 tempo_label.set_alignment (1.0, 0.5);
513 tempo_label.set_padding (5,0);
515 tempo_label.set_no_show_all();
517 meter_label.set_name ("EditorRulerLabel");
518 meter_label.set_size_request (-1, (int)timebar_height);
519 meter_label.set_alignment (1.0, 0.5);
520 meter_label.set_padding (5,0);
522 meter_label.set_no_show_all();
524 if (Profile->get_trx()) {
525 mark_label.set_text (_("Markers"));
527 mark_label.set_name ("EditorRulerLabel");
528 mark_label.set_size_request (-1, (int)timebar_height);
529 mark_label.set_alignment (1.0, 0.5);
530 mark_label.set_padding (5,0);
532 mark_label.set_no_show_all();
534 cd_mark_label.set_name ("EditorRulerLabel");
535 cd_mark_label.set_size_request (-1, (int)timebar_height);
536 cd_mark_label.set_alignment (1.0, 0.5);
537 cd_mark_label.set_padding (5,0);
538 cd_mark_label.hide();
539 cd_mark_label.set_no_show_all();
541 videotl_bar_height = 4;
542 videotl_label.set_name ("EditorRulerLabel");
543 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
544 videotl_label.set_alignment (1.0, 0.5);
545 videotl_label.set_padding (5,0);
546 videotl_label.hide();
547 videotl_label.set_no_show_all();
549 range_mark_label.set_name ("EditorRulerLabel");
550 range_mark_label.set_size_request (-1, (int)timebar_height);
551 range_mark_label.set_alignment (1.0, 0.5);
552 range_mark_label.set_padding (5,0);
553 range_mark_label.hide();
554 range_mark_label.set_no_show_all();
556 transport_mark_label.set_name ("EditorRulerLabel");
557 transport_mark_label.set_size_request (-1, (int)timebar_height);
558 transport_mark_label.set_alignment (1.0, 0.5);
559 transport_mark_label.set_padding (5,0);
560 transport_mark_label.hide();
561 transport_mark_label.set_no_show_all();
563 initialize_canvas ();
565 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
567 _summary = new EditorSummary (this);
569 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
570 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
572 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
574 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
575 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
577 edit_controls_vbox.set_spacing (0);
578 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
579 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
581 HBox* h = manage (new HBox);
582 _group_tabs = new EditorGroupTabs (this);
583 if (!ARDOUR::Profile->get_trx()) {
584 h->pack_start (*_group_tabs, PACK_SHRINK);
586 h->pack_start (edit_controls_vbox);
587 controls_layout.add (*h);
589 controls_layout.set_name ("EditControlsBase");
590 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
591 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
592 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
594 _cursors = new MouseCursors;
595 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
596 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
598 /* Push default cursor to ever-present bottom of cursor stack. */
599 push_canvas_cursor(_cursors->grabber);
601 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
603 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
604 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
605 pad_line_1->set_outline_color (0xFF0000FF);
611 edit_packer.set_col_spacings (0);
612 edit_packer.set_row_spacings (0);
613 edit_packer.set_homogeneous (false);
614 edit_packer.set_border_width (0);
615 edit_packer.set_name ("EditorWindow");
617 time_bars_event_box.add (time_bars_vbox);
618 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
619 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
621 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
622 axis_view_shadow->set_size_request (4, -1);
623 axis_view_shadow->set_name("EditorWindow");
624 axis_view_shadow->show();
626 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
628 /* labels for the time bars */
629 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
631 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
633 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
635 bottom_hbox.set_border_width (2);
636 bottom_hbox.set_spacing (3);
638 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
640 _route_groups = new EditorRouteGroups (this);
641 _routes = new EditorRoutes (this);
642 _regions = new EditorRegions (this);
643 _sources = new EditorSources (this);
644 _snapshots = new EditorSnapshots (this);
645 _locations = new EditorLocations (this);
646 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
648 /* these are static location signals */
650 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
651 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
654 add_notebook_page (_("Sources"), _sources->widget ());
655 add_notebook_page (_("Regions"), _regions->widget ());
656 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
657 add_notebook_page (_("Snapshots"), _snapshots->widget ());
658 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
659 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
661 _the_notebook.set_show_tabs (true);
662 _the_notebook.set_scrollable (true);
663 _the_notebook.popup_disable ();
664 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
665 _the_notebook.show_all ();
667 _notebook_shrunk = false;
670 /* Pick up some settings we need to cache, early */
672 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
675 settings->get_property ("notebook-shrunk", _notebook_shrunk);
678 editor_summary_pane.set_check_divider_position (true);
679 editor_summary_pane.add (edit_packer);
681 Button* summary_arrow_left = manage (new Button);
682 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
683 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
684 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
686 Button* summary_arrow_right = manage (new Button);
687 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
688 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
689 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 VBox* summary_arrows_left = manage (new VBox);
692 summary_arrows_left->pack_start (*summary_arrow_left);
694 VBox* summary_arrows_right = manage (new VBox);
695 summary_arrows_right->pack_start (*summary_arrow_right);
697 Frame* summary_frame = manage (new Frame);
698 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
700 summary_frame->add (*_summary);
701 summary_frame->show ();
703 _summary_hbox.pack_start (*summary_arrows_left, false, false);
704 _summary_hbox.pack_start (*summary_frame, true, true);
705 _summary_hbox.pack_start (*summary_arrows_right, false, false);
707 if (!ARDOUR::Profile->get_trx()) {
708 editor_summary_pane.add (_summary_hbox);
711 edit_pane.set_check_divider_position (true);
712 edit_pane.add (editor_summary_pane);
713 if (!ARDOUR::Profile->get_trx()) {
714 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
715 _editor_list_vbox.pack_start (_the_notebook);
716 edit_pane.add (_editor_list_vbox);
717 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
720 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
721 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
724 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
725 /* initial allocation is 90% to canvas, 10% to notebook */
728 edit_pane.set_divider (0, fract);
730 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
731 /* initial allocation is 90% to canvas, 10% to summary */
734 editor_summary_pane.set_divider (0, fract);
736 global_vpacker.set_spacing (0);
737 global_vpacker.set_border_width (0);
739 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
741 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
742 ebox->set_name("EditorWindow");
743 ebox->add (ebox_hpacker);
745 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
746 epane_box->set_name("EditorWindow");
747 epane_box->add (edit_pane);
749 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
750 epane_box2->set_name("EditorWindow");
751 epane_box2->add (global_vpacker);
753 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
754 toolbar_shadow->set_size_request (-1, 4);
755 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
756 toolbar_shadow->set_name("EditorWindow");
757 toolbar_shadow->show();
759 global_vpacker.pack_start (*toolbar_shadow, false, false);
760 global_vpacker.pack_start (*ebox, false, false);
761 global_vpacker.pack_start (*epane_box, true, true);
762 global_hpacker.pack_start (*epane_box2, true, true);
764 /* need to show the "contents" widget so that notebook will show if tab is switched to
767 global_hpacker.show ();
771 /* register actions now so that set_state() can find them and set toggles/checks etc */
778 _playlist_selector = new PlaylistSelector();
779 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
781 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
785 nudge_forward_button.set_name ("nudge button");
786 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
788 nudge_backward_button.set_name ("nudge button");
789 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
791 fade_context_menu.set_name ("ArdourContextMenu");
793 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
795 /* allow external control surfaces/protocols to do various things */
797 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
798 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
799 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
800 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
801 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
802 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
803 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
804 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
805 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
806 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
807 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
808 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
809 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
810 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
812 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
813 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
814 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
815 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
816 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
818 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
822 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
824 /* problematic: has to return a value and thus cannot be x-thread */
826 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
828 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
829 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
831 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
833 _ignore_region_action = false;
834 _last_region_menu_was_main = false;
836 _show_marker_lines = false;
838 /* Button bindings */
840 button_bindings = new Bindings ("editor-mouse");
842 XMLNode* node = button_settings();
844 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
845 button_bindings->load_operation (**i);
851 /* grab current parameter state */
852 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
853 UIConfiguration::instance().map_parameters (pc);
855 setup_fade_images ();
857 set_grid_to (GridTypeNone);
862 delete tempo_marker_menu;
863 delete meter_marker_menu;
865 delete range_marker_menu;
866 delete new_transport_marker_menu;
867 delete editor_ruler_menu;
868 delete _popup_region_menu_item;
870 delete button_bindings;
872 delete _route_groups;
873 delete _track_canvas_viewport;
876 delete _verbose_cursor;
877 delete quantize_dialog;
883 delete _playlist_selector;
884 delete _time_info_box;
889 LuaInstance::destroy_instance ();
891 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
894 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
897 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
903 Editor::button_settings () const
905 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
906 XMLNode* node = find_named_node (*settings, X_("Buttons"));
909 node = new XMLNode (X_("Buttons"));
916 Editor::get_smart_mode () const
918 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
922 Editor::catch_vanishing_regionview (RegionView *rv)
924 /* note: the selection will take care of the vanishing
925 audioregionview by itself.
928 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
932 if (clicked_regionview == rv) {
933 clicked_regionview = 0;
936 if (entered_regionview == rv) {
937 set_entered_regionview (0);
940 if (!_all_region_actions_sensitized) {
941 sensitize_all_region_actions (true);
946 Editor::set_entered_regionview (RegionView* rv)
948 if (rv == entered_regionview) {
952 if (entered_regionview) {
953 entered_regionview->exited ();
956 entered_regionview = rv;
958 if (entered_regionview != 0) {
959 entered_regionview->entered ();
962 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
963 /* This RegionView entry might have changed what region actions
964 are allowed, so sensitize them all in case a key is pressed.
966 sensitize_all_region_actions (true);
971 Editor::set_entered_track (TimeAxisView* tav)
974 entered_track->exited ();
980 entered_track->entered ();
985 Editor::instant_save ()
987 if (!constructed || !_session || no_save_instant) {
991 _session->add_instant_xml(get_state());
995 Editor::control_vertical_zoom_in_all ()
997 tav_zoom_smooth (false, true);
1001 Editor::control_vertical_zoom_out_all ()
1003 tav_zoom_smooth (true, true);
1007 Editor::control_vertical_zoom_in_selected ()
1009 tav_zoom_smooth (false, false);
1013 Editor::control_vertical_zoom_out_selected ()
1015 tav_zoom_smooth (true, false);
1019 Editor::control_view (uint32_t view)
1021 goto_visual_state (view);
1025 Editor::control_unselect ()
1027 selection->clear_tracks ();
1031 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1033 TimeAxisView* tav = time_axis_view_from_stripable (s);
1037 case Selection::Add:
1038 selection->add (tav);
1040 case Selection::Toggle:
1041 selection->toggle (tav);
1043 case Selection::Extend:
1045 case Selection::Set:
1046 selection->set (tav);
1050 selection->clear_tracks ();
1055 Editor::control_step_tracks_up ()
1057 scroll_tracks_up_line ();
1061 Editor::control_step_tracks_down ()
1063 scroll_tracks_down_line ();
1067 Editor::control_scroll (float fraction)
1069 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1075 double step = fraction * current_page_samples();
1078 _control_scroll_target is an optional<T>
1080 it acts like a pointer to an samplepos_t, with
1081 a operator conversion to boolean to check
1082 that it has a value could possibly use
1083 playhead_cursor->current_sample to store the
1084 value and a boolean in the class to know
1085 when it's out of date
1088 if (!_control_scroll_target) {
1089 _control_scroll_target = _session->transport_sample();
1090 _dragging_playhead = true;
1093 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1094 *_control_scroll_target = 0;
1095 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1096 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1098 *_control_scroll_target += (samplepos_t) trunc (step);
1101 /* move visuals, we'll catch up with it later */
1103 playhead_cursor->set_position (*_control_scroll_target);
1104 UpdateAllTransportClocks (*_control_scroll_target);
1106 if (*_control_scroll_target > (current_page_samples() / 2)) {
1107 /* try to center PH in window */
1108 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1114 Now we do a timeout to actually bring the session to the right place
1115 according to the playhead. This is to avoid reading disk buffers on every
1116 call to control_scroll, which is driven by ScrollTimeline and therefore
1117 probably by a control surface wheel which can generate lots of events.
1119 /* cancel the existing timeout */
1121 control_scroll_connection.disconnect ();
1123 /* add the next timeout */
1125 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1129 Editor::deferred_control_scroll (samplepos_t /*target*/)
1131 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1132 /* reset for next stream */
1133 _control_scroll_target = boost::none;
1134 _dragging_playhead = false;
1139 Editor::access_action (const std::string& action_group, const std::string& action_item)
1145 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1149 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
1153 } catch ( ActionManager::MissingActionException const& e) {
1154 cerr << "MissingActionException:" << e.what () << endl;
1159 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1161 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1165 Editor::on_realize ()
1169 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1170 start_lock_event_timing ();
1175 Editor::start_lock_event_timing ()
1177 /* check if we should lock the GUI every 30 seconds */
1179 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1183 Editor::generic_event_handler (GdkEvent* ev)
1186 case GDK_BUTTON_PRESS:
1187 case GDK_BUTTON_RELEASE:
1188 case GDK_MOTION_NOTIFY:
1190 case GDK_KEY_RELEASE:
1191 if (contents().is_mapped()) {
1192 gettimeofday (&last_event_time, 0);
1196 case GDK_LEAVE_NOTIFY:
1197 switch (ev->crossing.detail) {
1198 case GDK_NOTIFY_UNKNOWN:
1199 case GDK_NOTIFY_INFERIOR:
1200 case GDK_NOTIFY_ANCESTOR:
1202 case GDK_NOTIFY_VIRTUAL:
1203 case GDK_NOTIFY_NONLINEAR:
1204 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1205 /* leaving window, so reset focus, thus ending any and
1206 all text entry operations.
1208 ARDOUR_UI::instance()->reset_focus (&contents());
1221 Editor::lock_timeout_callback ()
1223 struct timeval now, delta;
1225 gettimeofday (&now, 0);
1227 timersub (&now, &last_event_time, &delta);
1229 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1231 /* don't call again. Returning false will effectively
1232 disconnect us from the timer callback.
1234 unlock() will call start_lock_event_timing() to get things
1244 Editor::map_position_change (samplepos_t sample)
1246 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1248 if (_session == 0) {
1252 if (_follow_playhead) {
1253 center_screen (sample);
1256 playhead_cursor->set_position (sample);
1260 Editor::center_screen (samplepos_t sample)
1262 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1264 /* if we're off the page, then scroll.
1267 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1268 center_screen_internal (sample, page);
1273 Editor::center_screen_internal (samplepos_t sample, float page)
1277 if (sample > page) {
1278 sample -= (samplepos_t) page;
1283 reset_x_origin (sample);
1288 Editor::update_title ()
1290 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1292 if (!own_window()) {
1297 bool dirty = _session->dirty();
1299 string session_name;
1301 if (_session->snap_name() != _session->name()) {
1302 session_name = _session->snap_name();
1304 session_name = _session->name();
1308 session_name = "*" + session_name;
1311 WindowTitle title(session_name);
1312 title += S_("Window|Editor");
1313 title += Glib::get_application_name();
1314 own_window()->set_title (title.get_string());
1316 /* ::session_going_away() will have taken care of it */
1321 Editor::set_session (Session *t)
1323 SessionHandlePtr::set_session (t);
1329 /* initialize _leftmost_sample to the extents of the session
1330 * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
1331 * before the visible state has been loaded from instant.xml */
1332 _leftmost_sample = session_gui_extents().first;
1334 _playlist_selector->set_session (_session);
1335 nudge_clock->set_session (_session);
1336 _summary->set_session (_session);
1337 _group_tabs->set_session (_session);
1338 _route_groups->set_session (_session);
1339 _regions->set_session (_session);
1340 _sources->set_session (_session);
1341 _snapshots->set_session (_session);
1342 _routes->set_session (_session);
1343 _locations->set_session (_session);
1344 _time_info_box->set_session (_session);
1346 if (rhythm_ferret) {
1347 rhythm_ferret->set_session (_session);
1350 if (analysis_window) {
1351 analysis_window->set_session (_session);
1355 sfbrowser->set_session (_session);
1358 compute_fixed_ruler_scale ();
1360 /* Make sure we have auto loop and auto punch ranges */
1362 Location* loc = _session->locations()->auto_loop_location();
1364 loc->set_name (_("Loop"));
1367 loc = _session->locations()->auto_punch_location();
1370 loc->set_name (_("Punch"));
1373 refresh_location_display ();
1375 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1376 * the selected Marker; this needs the LocationMarker list to be available.
1378 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1379 set_state (*node, Stateful::loading_state_version);
1381 /* catch up on selection state, etc. */
1384 sc.add (Properties::selected);
1385 presentation_info_changed (sc);
1387 /* catch up with the playhead */
1389 _session->request_locate (playhead_cursor->current_sample ());
1390 _pending_initial_locate = true;
1394 /* These signals can all be emitted by a non-GUI thread. Therefore the
1395 handlers for them must not attempt to directly interact with the GUI,
1396 but use PBD::Signal<T>::connect() which accepts an event loop
1397 ("context") where the handler will be asked to run.
1400 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1401 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1402 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1403 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1404 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1405 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1406 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1407 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1408 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1409 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1410 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1411 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1412 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1413 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1414 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1415 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1417 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1418 playhead_cursor->show ();
1420 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1421 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1422 snapped_cursor->show ();
1424 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1425 Config->map_parameters (pc);
1426 _session->config.map_parameters (pc);
1428 restore_ruler_visibility ();
1429 //tempo_map_changed (PropertyChange (0));
1430 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1432 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1433 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1436 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1437 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1440 /* register for undo history */
1441 _session->register_with_memento_command_factory(id(), this);
1442 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1444 LuaInstance::instance()->set_session(_session);
1446 start_updating_meters ();
1450 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1452 using namespace Menu_Helpers;
1454 void (Editor::*emf)(FadeShape);
1455 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1458 images = &_xfade_in_images;
1459 emf = &Editor::set_fade_in_shape;
1461 images = &_xfade_out_images;
1462 emf = &Editor::set_fade_out_shape;
1467 _("Linear (for highly correlated material)"),
1468 *(*images)[FadeLinear],
1469 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 _("Constant power"),
1478 *(*images)[FadeConstantPower],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *(*images)[FadeSymmetric],
1488 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *(*images)[FadeSlow],
1498 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1501 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1506 *(*images)[FadeFast],
1507 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1510 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 /** Pop up a context menu for when the user clicks on a start crossfade */
1515 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1517 using namespace Menu_Helpers;
1518 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1523 MenuList& items (xfade_in_context_menu.items());
1526 if (arv->audio_region()->fade_in_active()) {
1527 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1529 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1532 items.push_back (SeparatorElem());
1533 fill_xfade_menu (items, true);
1535 xfade_in_context_menu.popup (button, time);
1538 /** Pop up a context menu for when the user clicks on an end crossfade */
1540 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1542 using namespace Menu_Helpers;
1543 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1548 MenuList& items (xfade_out_context_menu.items());
1551 if (arv->audio_region()->fade_out_active()) {
1552 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1554 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1557 items.push_back (SeparatorElem());
1558 fill_xfade_menu (items, false);
1560 xfade_out_context_menu.popup (button, time);
1564 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1566 using namespace Menu_Helpers;
1567 Menu* (Editor::*build_menu_function)();
1570 switch (item_type) {
1572 case RegionViewName:
1573 case RegionViewNameHighlight:
1574 case LeftFrameHandle:
1575 case RightFrameHandle:
1576 if (with_selection) {
1577 build_menu_function = &Editor::build_track_selection_context_menu;
1579 build_menu_function = &Editor::build_track_region_context_menu;
1584 if (with_selection) {
1585 build_menu_function = &Editor::build_track_selection_context_menu;
1587 build_menu_function = &Editor::build_track_context_menu;
1592 if (clicked_routeview->track()) {
1593 build_menu_function = &Editor::build_track_context_menu;
1595 build_menu_function = &Editor::build_track_bus_context_menu;
1600 /* probably shouldn't happen but if it does, we don't care */
1604 menu = (this->*build_menu_function)();
1605 menu->set_name ("ArdourContextMenu");
1607 /* now handle specific situations */
1609 switch (item_type) {
1611 case RegionViewName:
1612 case RegionViewNameHighlight:
1613 case LeftFrameHandle:
1614 case RightFrameHandle:
1624 /* probably shouldn't happen but if it does, we don't care */
1628 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1630 /* Bounce to disk */
1632 using namespace Menu_Helpers;
1633 MenuList& edit_items = menu->items();
1635 edit_items.push_back (SeparatorElem());
1637 switch (clicked_routeview->audio_track()->freeze_state()) {
1638 case AudioTrack::NoFreeze:
1639 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1642 case AudioTrack::Frozen:
1643 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1646 case AudioTrack::UnFrozen:
1647 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1653 if (item_type == StreamItem && clicked_routeview) {
1654 clicked_routeview->build_underlay_menu(menu);
1657 /* When the region menu is opened, we setup the actions so that they look right
1660 sensitize_the_right_region_actions (false);
1661 _last_region_menu_was_main = false;
1663 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1664 menu->popup (button, time);
1668 Editor::build_track_context_menu ()
1670 using namespace Menu_Helpers;
1672 MenuList& edit_items = track_context_menu.items();
1675 add_dstream_context_items (edit_items);
1676 return &track_context_menu;
1680 Editor::build_track_bus_context_menu ()
1682 using namespace Menu_Helpers;
1684 MenuList& edit_items = track_context_menu.items();
1687 add_bus_context_items (edit_items);
1688 return &track_context_menu;
1692 Editor::build_track_region_context_menu ()
1694 using namespace Menu_Helpers;
1695 MenuList& edit_items = track_region_context_menu.items();
1698 /* we've just cleared the track region context menu, so the menu that these
1699 two items were on will have disappeared; stop them dangling.
1701 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1704 boost::shared_ptr<Track> tr;
1705 boost::shared_ptr<Playlist> pl;
1707 if ((tr = rtv->track())) {
1708 add_region_context_items (edit_items, tr);
1712 add_dstream_context_items (edit_items);
1714 return &track_region_context_menu;
1718 Editor::loudness_analyze_region_selection ()
1723 Selection& s (PublicEditor::instance ().get_selection ());
1724 RegionSelection ars = s.regions;
1725 ARDOUR::AnalysisGraph ag (_session);
1726 samplecnt_t total_work = 0;
1728 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1729 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1733 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1736 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1737 total_work += arv->region ()->length ();
1740 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1742 ag.set_total_samples (total_work);
1743 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1746 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1747 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1751 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1755 ag.analyze_region (ar);
1758 if (!ag.canceled ()) {
1759 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1765 Editor::loudness_analyze_range_selection ()
1770 Selection& s (PublicEditor::instance ().get_selection ());
1771 TimeSelection ts = s.time;
1772 ARDOUR::AnalysisGraph ag (_session);
1773 samplecnt_t total_work = 0;
1775 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1776 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1780 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1784 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1785 total_work += j->length ();
1789 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1791 ag.set_total_samples (total_work);
1792 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1795 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1796 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1800 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1804 ag.analyze_range (rui->route (), pl, ts);
1807 if (!ag.canceled ()) {
1808 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1814 Editor::spectral_analyze_region_selection ()
1816 if (analysis_window == 0) {
1817 analysis_window = new AnalysisWindow();
1820 analysis_window->set_session(_session);
1822 analysis_window->show_all();
1825 analysis_window->set_regionmode();
1826 analysis_window->analyze();
1828 analysis_window->present();
1832 Editor::spectral_analyze_range_selection()
1834 if (analysis_window == 0) {
1835 analysis_window = new AnalysisWindow();
1838 analysis_window->set_session(_session);
1840 analysis_window->show_all();
1843 analysis_window->set_rangemode();
1844 analysis_window->analyze();
1846 analysis_window->present();
1850 Editor::build_track_selection_context_menu ()
1852 using namespace Menu_Helpers;
1853 MenuList& edit_items = track_selection_context_menu.items();
1854 edit_items.clear ();
1856 add_selection_context_items (edit_items);
1857 // edit_items.push_back (SeparatorElem());
1858 // add_dstream_context_items (edit_items);
1860 return &track_selection_context_menu;
1864 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1866 using namespace Menu_Helpers;
1868 /* OK, stick the region submenu at the top of the list, and then add
1872 RegionSelection rs = get_regions_from_selection_and_entered ();
1874 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1876 if (_popup_region_menu_item == 0) {
1877 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1878 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1879 _popup_region_menu_item->show ();
1881 _popup_region_menu_item->set_label (menu_item_name);
1884 /* No layering allowed in later is higher layering model */
1885 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1886 if (act && Config->get_layer_model() == LaterHigher) {
1887 act->set_sensitive (false);
1889 act->set_sensitive (true);
1892 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1894 edit_items.push_back (*_popup_region_menu_item);
1895 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1896 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1898 edit_items.push_back (SeparatorElem());
1901 /** Add context menu items relevant to selection ranges.
1902 * @param edit_items List to add the items to.
1905 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1907 using namespace Menu_Helpers;
1909 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1910 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1912 edit_items.push_back (SeparatorElem());
1913 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1915 edit_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1917 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1919 edit_items.push_back (SeparatorElem());
1921 edit_items.push_back (
1923 _("Move Range Start to Previous Region Boundary"),
1924 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1928 edit_items.push_back (
1930 _("Move Range Start to Next Region Boundary"),
1931 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1935 edit_items.push_back (
1937 _("Move Range End to Previous Region Boundary"),
1938 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1942 edit_items.push_back (
1944 _("Move Range End to Next Region Boundary"),
1945 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1949 edit_items.push_back (SeparatorElem());
1950 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1951 // edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1953 edit_items.push_back (SeparatorElem());
1954 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1956 edit_items.push_back (SeparatorElem());
1957 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1958 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1959 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1961 edit_items.push_back (SeparatorElem());
1962 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1964 edit_items.push_back (SeparatorElem());
1965 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1966 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1970 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1971 edit_items.push_back (MenuElem (_("Bounce Range to Source List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1972 edit_items.push_back (MenuElem (_("Bounce Range to Source List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1973 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1974 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1975 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1981 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1983 using namespace Menu_Helpers;
1987 Menu *play_menu = manage (new Menu);
1988 MenuList& play_items = play_menu->items();
1989 play_menu->set_name ("ArdourContextMenu");
1991 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1992 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1993 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1994 play_items.push_back (SeparatorElem());
1995 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1997 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2001 Menu *select_menu = manage (new Menu);
2002 MenuList& select_items = select_menu->items();
2003 select_menu->set_name ("ArdourContextMenu");
2005 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2006 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2007 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2008 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2009 select_items.push_back (SeparatorElem());
2010 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2011 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2012 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2013 select_items.push_back (SeparatorElem());
2014 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2015 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2016 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2017 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2018 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2019 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2020 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2022 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2026 Menu *cutnpaste_menu = manage (new Menu);
2027 MenuList& cutnpaste_items = cutnpaste_menu->items();
2028 cutnpaste_menu->set_name ("ArdourContextMenu");
2030 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2031 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2032 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2034 cutnpaste_items.push_back (SeparatorElem());
2036 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2037 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2039 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2041 /* Adding new material */
2043 edit_items.push_back (SeparatorElem());
2044 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2045 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2049 Menu *nudge_menu = manage (new Menu());
2050 MenuList& nudge_items = nudge_menu->items();
2051 nudge_menu->set_name ("ArdourContextMenu");
2053 edit_items.push_back (SeparatorElem());
2054 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2055 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2056 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2057 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2059 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2063 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2065 using namespace Menu_Helpers;
2069 Menu *play_menu = manage (new Menu);
2070 MenuList& play_items = play_menu->items();
2071 play_menu->set_name ("ArdourContextMenu");
2073 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2074 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2075 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2079 Menu *select_menu = manage (new Menu);
2080 MenuList& select_items = select_menu->items();
2081 select_menu->set_name ("ArdourContextMenu");
2083 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2084 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2085 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2086 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2087 select_items.push_back (SeparatorElem());
2088 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2089 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2090 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2091 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2093 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2096 #if 0 // unused, why?
2097 Menu *cutnpaste_menu = manage (new Menu);
2098 MenuList& cutnpaste_items = cutnpaste_menu->items();
2099 cutnpaste_menu->set_name ("ArdourContextMenu");
2101 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2102 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2103 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2106 Menu *nudge_menu = manage (new Menu());
2107 MenuList& nudge_items = nudge_menu->items();
2108 nudge_menu->set_name ("ArdourContextMenu");
2110 edit_items.push_back (SeparatorElem());
2111 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2112 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2113 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2114 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2116 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2120 Editor::grid_type() const
2126 Editor::grid_musical() const
2128 switch (_grid_type) {
2129 case GridTypeBeatDiv32:
2130 case GridTypeBeatDiv28:
2131 case GridTypeBeatDiv24:
2132 case GridTypeBeatDiv20:
2133 case GridTypeBeatDiv16:
2134 case GridTypeBeatDiv14:
2135 case GridTypeBeatDiv12:
2136 case GridTypeBeatDiv10:
2137 case GridTypeBeatDiv8:
2138 case GridTypeBeatDiv7:
2139 case GridTypeBeatDiv6:
2140 case GridTypeBeatDiv5:
2141 case GridTypeBeatDiv4:
2142 case GridTypeBeatDiv3:
2143 case GridTypeBeatDiv2:
2148 case GridTypeTimecode:
2149 case GridTypeMinSec:
2150 case GridTypeCDFrame:
2157 Editor::grid_nonmusical() const
2159 switch (_grid_type) {
2160 case GridTypeTimecode:
2161 case GridTypeMinSec:
2162 case GridTypeCDFrame:
2164 case GridTypeBeatDiv32:
2165 case GridTypeBeatDiv28:
2166 case GridTypeBeatDiv24:
2167 case GridTypeBeatDiv20:
2168 case GridTypeBeatDiv16:
2169 case GridTypeBeatDiv14:
2170 case GridTypeBeatDiv12:
2171 case GridTypeBeatDiv10:
2172 case GridTypeBeatDiv8:
2173 case GridTypeBeatDiv7:
2174 case GridTypeBeatDiv6:
2175 case GridTypeBeatDiv5:
2176 case GridTypeBeatDiv4:
2177 case GridTypeBeatDiv3:
2178 case GridTypeBeatDiv2:
2187 Editor::snap_mode() const
2193 Editor::show_rulers_for_grid ()
2195 /* show appropriate rulers for this grid setting. */
2196 if (grid_musical()) {
2197 ruler_tempo_action->set_active(true);
2198 ruler_meter_action->set_active(true);
2199 ruler_bbt_action->set_active(true);
2201 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2202 ruler_timecode_action->set_active(false);
2203 ruler_minsec_action->set_active(false);
2204 ruler_samples_action->set_active(false);
2206 } else if (_grid_type == GridTypeTimecode) {
2207 ruler_timecode_action->set_active(true);
2209 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2210 ruler_tempo_action->set_active(false);
2211 ruler_meter_action->set_active(false);
2212 ruler_bbt_action->set_active(false);
2213 ruler_minsec_action->set_active(false);
2214 ruler_samples_action->set_active(false);
2216 } else if (_grid_type == GridTypeMinSec) {
2217 ruler_minsec_action->set_active(true);
2219 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2220 ruler_tempo_action->set_active(false);
2221 ruler_meter_action->set_active(false);
2222 ruler_bbt_action->set_active(false);
2223 ruler_timecode_action->set_active(false);
2224 ruler_samples_action->set_active(false);
2226 } else if (_grid_type == GridTypeCDFrame) {
2227 ruler_cd_marker_action->set_active(true);
2228 ruler_minsec_action->set_active(true);
2230 if (UIConfiguration::instance().get_rulers_follow_grid()) {
2231 ruler_tempo_action->set_active(false);
2232 ruler_meter_action->set_active(false);
2233 ruler_bbt_action->set_active(false);
2234 ruler_timecode_action->set_active(false);
2235 ruler_samples_action->set_active(false);
2241 Editor::set_grid_to (GridType gt)
2243 if (_grid_type == gt) { // already set
2247 unsigned int grid_ind = (unsigned int)gt;
2249 if (internal_editing() && UIConfiguration::instance().get_grid_follows_internal()) {
2250 internal_grid_type = gt;
2252 pre_internal_grid_type = gt;
2257 if (grid_ind > grid_type_strings.size() - 1) {
2259 _grid_type = (GridType)grid_ind;
2262 string str = grid_type_strings[grid_ind];
2264 if (str != grid_type_selector.get_text()) {
2265 grid_type_selector.set_text (str);
2268 if (UIConfiguration::instance().get_show_grids_ruler()) {
2269 show_rulers_for_grid ();
2274 if (grid_musical()) {
2275 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2276 update_tempo_based_rulers ();
2279 mark_region_boundary_cache_dirty ();
2281 redisplay_grid (false);
2283 SnapChanged (); /* EMIT SIGNAL */
2287 Editor::set_snap_mode (SnapMode mode)
2289 if (internal_editing()) {
2290 internal_snap_mode = mode;
2292 pre_internal_snap_mode = mode;
2297 if (_snap_mode == SnapOff) {
2298 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2300 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2307 Editor::set_edit_point_preference (EditPoint ep, bool force)
2309 if (Profile->get_mixbus()) {
2310 if (ep == EditAtSelectedMarker) {
2311 ep = EditAtPlayhead;
2315 bool changed = (_edit_point != ep);
2319 string str = edit_point_strings[(int)ep];
2320 if (str != edit_point_selector.get_text ()) {
2321 edit_point_selector.set_text (str);
2324 update_all_enter_cursors();
2326 if (!force && !changed) {
2330 const char* action=NULL;
2332 switch (_edit_point) {
2333 case EditAtPlayhead:
2334 action = "edit-at-playhead";
2336 case EditAtSelectedMarker:
2337 action = "edit-at-selected-marker";
2340 action = "edit-at-mouse";
2344 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action ("Editor", action);
2345 tact->set_active (true);
2348 bool in_track_canvas;
2350 if (!mouse_sample (foo, in_track_canvas)) {
2351 in_track_canvas = false;
2354 reset_canvas_action_sensitivity (in_track_canvas);
2355 sensitize_the_right_region_actions (false);
2361 Editor::set_state (const XMLNode& node, int version)
2364 PBD::Unwinder<bool> nsi (no_save_instant, true);
2367 Tabbable::set_state (node, version);
2370 if (_session && node.get_property ("playhead", ph_pos)) {
2372 playhead_cursor->set_position (ph_pos);
2374 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2375 playhead_cursor->set_position (0);
2378 playhead_cursor->set_position (0);
2381 node.get_property ("mixer-width", editor_mixer_strip_width);
2383 node.get_property ("zoom-focus", zoom_focus);
2384 zoom_focus_selection_done (zoom_focus);
2387 if (node.get_property ("zoom", z)) {
2388 /* older versions of ardour used floating point samples_per_pixel */
2389 reset_zoom (llrintf (z));
2391 reset_zoom (samples_per_pixel);
2395 if (node.get_property ("visible-track-count", cnt)) {
2396 set_visible_track_count (cnt);
2400 if (!node.get_property ("grid-type", grid_type)) {
2401 grid_type = _grid_type;
2403 set_grid_to (grid_type);
2406 if (node.get_property ("snap-mode", sm)) {
2407 snap_mode_selection_done(sm);
2408 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2409 * snap_mode_selection_done() will only mark an already active item as active
2410 * which does not trigger set_text().
2414 set_snap_mode (_snap_mode);
2417 node.get_property ("internal-grid-type", internal_grid_type);
2418 node.get_property ("internal-snap-mode", internal_snap_mode);
2419 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2420 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2423 if (node.get_property ("mouse-mode", mm_str)) {
2424 MouseMode m = str2mousemode(mm_str);
2425 set_mouse_mode (m, true);
2427 set_mouse_mode (MouseObject, true);
2431 if (node.get_property ("left-frame", lf_pos)) {
2435 reset_x_origin (lf_pos);
2439 if (node.get_property ("y-origin", y_origin)) {
2440 reset_y_origin (y_origin);
2444 node.get_property ("join-object-range", yn);
2446 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2447 /* do it twice to force the change */
2448 tact->set_active (!yn);
2449 tact->set_active (yn);
2450 set_mouse_mode(mouse_mode, true);
2454 if (node.get_property ("edit-point", ep)) {
2455 set_edit_point_preference (ep, true);
2457 set_edit_point_preference (_edit_point);
2460 if (node.get_property ("follow-playhead", yn)) {
2461 set_follow_playhead (yn);
2464 if (node.get_property ("stationary-playhead", yn)) {
2465 set_stationary_playhead (yn);
2468 if (node.get_property ("show-editor-mixer", yn)) {
2470 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2471 /* do it twice to force the change */
2472 tact->set_active (!yn);
2473 tact->set_active (yn);
2477 node.get_property ("show-editor-list", yn);
2479 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2480 /* do it twice to force the change */
2481 tact->set_active (!yn);
2482 tact->set_active (yn);
2486 if (node.get_property (X_("editor-list-page"), el_page)) {
2487 _the_notebook.set_current_page (el_page);
2491 node.get_property (X_("show-marker-lines"), yn);
2493 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-marker-lines"));
2494 /* do it twice to force the change */
2495 tact->set_active (!yn);
2496 tact->set_active (yn);
2499 XMLNodeList children = node.children ();
2500 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2501 selection->set_state (**i, Stateful::current_state_version);
2502 _regions->set_state (**i);
2503 _locations->set_state (**i);
2506 if (node.get_property ("maximised", yn)) {
2507 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Common"), X_("ToggleMaximalEditor"));
2508 bool fs = tact->get_active();
2510 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2514 samplepos_t nudge_clock_value;
2515 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2516 nudge_clock->set (nudge_clock_value);
2518 nudge_clock->set_mode (AudioClock::Timecode);
2519 nudge_clock->set (_session->sample_rate() * 5, true);
2524 * Not all properties may have been in XML, but
2525 * those that are linked to a private variable may need changing
2527 RefPtr<ToggleAction> tact;
2529 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
2530 yn = _follow_playhead;
2531 if (tact->get_active() != yn) {
2532 tact->set_active (yn);
2535 tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
2536 yn = _stationary_playhead;
2537 if (tact->get_active() != yn) {
2538 tact->set_active (yn);
2546 Editor::get_state ()
2548 XMLNode* node = new XMLNode (X_("Editor"));
2550 node->set_property ("id", id().to_s ());
2552 node->add_child_nocopy (Tabbable::get_state());
2554 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2555 node->set_property("notebook-shrunk", _notebook_shrunk);
2556 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2558 maybe_add_mixer_strip_width (*node);
2560 node->set_property ("zoom-focus", zoom_focus);
2562 node->set_property ("zoom", samples_per_pixel);
2563 node->set_property ("grid-type", _grid_type);
2564 node->set_property ("snap-mode", _snap_mode);
2565 node->set_property ("internal-grid-type", internal_grid_type);
2566 node->set_property ("internal-snap-mode", internal_snap_mode);
2567 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2568 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2569 node->set_property ("edit-point", _edit_point);
2570 node->set_property ("visible-track-count", _visible_track_count);
2572 node->set_property ("playhead", playhead_cursor->current_sample ());
2573 node->set_property ("left-frame", _leftmost_sample);
2574 node->set_property ("y-origin", vertical_adjustment.get_value ());
2576 node->set_property ("maximised", _maximised);
2577 node->set_property ("follow-playhead", _follow_playhead);
2578 node->set_property ("stationary-playhead", _stationary_playhead);
2579 node->set_property ("mouse-mode", mouse_mode);
2580 node->set_property ("join-object-range", smart_mode_action->get_active ());
2582 Glib::RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-mixer"));
2583 node->set_property (X_("show-editor-mixer"), tact->get_active());
2585 tact = ActionManager::get_toggle_action (X_("Editor"), X_("show-editor-list"));
2586 node->set_property (X_("show-editor-list"), tact->get_active());
2588 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2590 if (button_bindings) {
2591 XMLNode* bb = new XMLNode (X_("Buttons"));
2592 button_bindings->save (*bb);
2593 node->add_child_nocopy (*bb);
2596 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2598 node->add_child_nocopy (selection->get_state ());
2599 node->add_child_nocopy (_regions->get_state ());
2601 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2603 node->add_child_nocopy (_locations->get_state ());
2608 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2609 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2611 * @return pair: TimeAxisView that y is over, layer index.
2613 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2614 * in stacked or expanded region display mode, otherwise 0.
2616 std::pair<TimeAxisView *, double>
2617 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2619 if (!trackview_relative_offset) {
2620 y -= _trackview_group->canvas_origin().y;
2624 return std::make_pair ((TimeAxisView *) 0, 0);
2627 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2629 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2636 return std::make_pair ((TimeAxisView *) 0, 0);
2640 Editor::set_snapped_cursor_position (samplepos_t pos)
2642 if (_edit_point == EditAtMouse) {
2643 snapped_cursor->set_position(pos);
2648 /** Snap a position to the grid, if appropriate, taking into account current
2649 * grid settings and also the state of any snap modifier keys that may be pressed.
2650 * @param start Position to snap.
2651 * @param event Event to get current key modifier information from, or 0.
2654 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref)
2656 if (!_session || !event) {
2660 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2661 if (_snap_mode == SnapOff) {
2662 snap_to_internal (start, direction, pref);
2664 start.set (start.sample, 0);
2667 if (_snap_mode != SnapOff) {
2668 snap_to_internal (start, direction, pref);
2669 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2670 /* SnapOff, but we pressed the snap_delta modifier */
2671 snap_to_internal (start, direction, pref);
2673 start.set (start.sample, 0);
2679 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2681 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2682 start.set (start.sample, 0);
2686 snap_to_internal (start, direction, pref, ensure_snap);
2690 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2692 samplepos_t diff = abs (test - presnap);
2698 test = max_samplepos; // reset this so it doesn't get accidentally reused
2702 Editor::snap_to_timecode (MusicSample presnap, RoundMode direction, SnapPref gpref)
2704 samplepos_t start = presnap.sample;
2705 const samplepos_t one_timecode_second = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame());
2706 samplepos_t one_timecode_minute = (samplepos_t)(rint(_session->timecode_frames_per_second()) * _session->samples_per_timecode_frame() * 60);
2708 TimecodeRulerScale scale = (gpref != SnapToGrid_Unscaled) ? timecode_ruler_scale : timecode_show_samples;
2711 case timecode_show_bits:
2712 case timecode_show_samples:
2713 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2714 fmod((double)start, (double)_session->samples_per_timecode_frame()) == 0) {
2715 /* start is already on a whole timecode frame, do nothing */
2716 } else if (((direction == 0) && (fmod((double)start, (double)_session->samples_per_timecode_frame()) > (_session->samples_per_timecode_frame() / 2))) || (direction > 0)) {
2717 start = (samplepos_t) (ceil ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2719 start = (samplepos_t) (floor ((double) start / _session->samples_per_timecode_frame()) * _session->samples_per_timecode_frame());
2723 case timecode_show_seconds:
2724 if (_session->config.get_timecode_offset_negative()) {
2725 start += _session->config.get_timecode_offset ();
2727 start -= _session->config.get_timecode_offset ();
2729 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2730 (start % one_timecode_second == 0)) {
2731 /* start is already on a whole second, do nothing */
2732 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2733 start = (samplepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2735 start = (samplepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2738 if (_session->config.get_timecode_offset_negative()) {
2739 start -= _session->config.get_timecode_offset ();
2741 start += _session->config.get_timecode_offset ();
2745 case timecode_show_minutes:
2746 case timecode_show_hours:
2747 case timecode_show_many_hours:
2748 if (_session->config.get_timecode_offset_negative()) {
2749 start += _session->config.get_timecode_offset ();
2751 start -= _session->config.get_timecode_offset ();
2753 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2754 (start % one_timecode_minute == 0)) {
2755 /* start is already on a whole minute, do nothing */
2756 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2757 start = (samplepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2759 start = (samplepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2761 if (_session->config.get_timecode_offset_negative()) {
2762 start -= _session->config.get_timecode_offset ();
2764 start += _session->config.get_timecode_offset ();
2768 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2771 MusicSample ret(start,0);
2776 Editor::snap_to_minsec (MusicSample presnap, RoundMode direction, SnapPref gpref)
2778 MusicSample ret(presnap);
2780 const samplepos_t one_second = _session->sample_rate();
2781 const samplepos_t one_minute = one_second * 60;
2782 const samplepos_t one_hour = one_minute * 60;
2784 MinsecRulerScale scale = (gpref != SnapToGrid_Unscaled) ? minsec_ruler_scale : minsec_show_seconds;
2787 case minsec_show_msecs:
2788 case minsec_show_seconds: {
2789 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2790 presnap.sample % one_second == 0) {
2791 /* start is already on a whole second, do nothing */
2792 } else if (((direction == 0) && (presnap.sample % one_second > one_second / 2)) || (direction > 0)) {
2793 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_second) * one_second;
2795 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_second) * one_second;
2799 case minsec_show_minutes: {
2800 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2801 presnap.sample % one_minute == 0) {
2802 /* start is already on a whole minute, do nothing */
2803 } else if (((direction == 0) && (presnap.sample % one_minute > one_minute / 2)) || (direction > 0)) {
2804 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_minute) * one_minute;
2806 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_minute) * one_minute;
2811 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2812 presnap.sample % one_hour == 0) {
2813 /* start is already on a whole hour, do nothing */
2814 } else if (((direction == 0) && (presnap.sample % one_hour > one_hour / 2)) || (direction > 0)) {
2815 ret.sample = (samplepos_t) ceil ((double) presnap.sample / one_hour) * one_hour;
2817 ret.sample = (samplepos_t) floor ((double) presnap.sample / one_hour) * one_hour;
2826 Editor::snap_to_cd_frames (MusicSample presnap, RoundMode direction, SnapPref gpref)
2828 if ((gpref != SnapToGrid_Unscaled) && (minsec_ruler_scale != minsec_show_msecs)) {
2829 return snap_to_minsec (presnap, direction, gpref);
2832 const samplepos_t one_second = _session->sample_rate();
2834 MusicSample ret(presnap);
2836 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2837 presnap.sample % (one_second/75) == 0) {
2838 /* start is already on a whole CD sample, do nothing */
2839 } else if (((direction == 0) && (presnap.sample % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2840 ret.sample = (samplepos_t) ceil ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2842 ret.sample = (samplepos_t) floor ((double) presnap.sample / (one_second / 75)) * (one_second / 75);
2849 Editor::snap_to_bbt (MusicSample presnap, RoundMode direction, SnapPref gpref)
2851 MusicSample ret(presnap);
2853 if (gpref != SnapToGrid_Unscaled) { // use the visual grid lines which are limited by the zoom scale that the user selected
2856 switch (_grid_type) {
2857 case GridTypeBeatDiv3:
2858 case GridTypeBeatDiv6:
2859 case GridTypeBeatDiv12:
2860 case GridTypeBeatDiv24:
2863 case GridTypeBeatDiv5:
2864 case GridTypeBeatDiv10:
2865 case GridTypeBeatDiv20:
2868 case GridTypeBeatDiv7:
2869 case GridTypeBeatDiv14:
2870 case GridTypeBeatDiv28:
2877 BBTRulerScale scale = bbt_ruler_scale;
2884 ret = _session->tempo_map().round_to_bar (presnap.sample, direction);
2886 case bbt_show_quarters:
2887 ret = _session->tempo_map().round_to_beat (presnap.sample, direction);
2889 case bbt_show_eighths:
2890 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 1 * divisor, direction);
2892 case bbt_show_sixteenths:
2893 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 2 * divisor, direction);
2895 case bbt_show_thirtyseconds:
2896 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, 4 * divisor, direction);
2900 ret = _session->tempo_map().round_to_quarter_note_subdivision (presnap.sample, get_grid_beat_divisions(_grid_type), direction);
2907 Editor::snap_to_grid (MusicSample presnap, RoundMode direction, SnapPref gpref)
2909 MusicSample ret(presnap);
2911 if (grid_musical()) {
2912 ret = snap_to_bbt (presnap, direction, gpref);
2915 switch (_grid_type) {
2916 case GridTypeTimecode:
2917 ret = snap_to_timecode(presnap, direction, gpref);
2919 case GridTypeMinSec:
2920 ret = snap_to_minsec(presnap, direction, gpref);
2922 case GridTypeCDFrame:
2923 ret = snap_to_cd_frames(presnap, direction, gpref);
2933 Editor::snap_to_marker (samplepos_t presnap, RoundMode direction)
2939 _session->locations()->marks_either_side (presnap, before, after);
2941 if (before == max_samplepos && after == max_samplepos) {
2942 /* No marks to snap to, so just don't snap */
2944 } else if (before == max_samplepos) {
2946 } else if (after == max_samplepos) {
2949 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2951 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2953 } else if (direction == 0) {
2954 if ((presnap - before) < (after - presnap)) {
2966 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool ensure_snap)
2968 const samplepos_t presnap = start.sample;
2970 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2971 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2972 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2974 /* check snap-to-marker */
2975 if ((pref == SnapToAny_Visual) && UIConfiguration::instance().get_snap_to_marks()) {
2976 test = snap_to_marker (presnap, direction);
2977 check_best_snap(presnap, test, dist, best);
2980 /* check snap-to-region-{start/end/sync} */
2982 (pref == SnapToAny_Visual) &&
2983 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
2985 if (!region_boundary_cache.empty()) {
2987 vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
2988 vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2989 if (next != region_boundary_cache.begin ()) {
2994 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2996 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2998 else if (direction == 0) {
2999 if ((presnap - *prev) < (*next - presnap)) {
3008 check_best_snap(presnap, test, dist, best);
3012 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
3013 MusicSample pre(presnap, 0);
3014 MusicSample post = snap_to_grid (pre, direction, pref);
3015 check_best_snap(presnap, post.sample, dist, best);
3018 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
3019 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
3020 * ToDo: Perhaps this should only occur if EditPointMouse?
3022 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
3024 start.set (best, 0);
3026 } else if (presnap > best) {
3027 if (presnap > (best+ snap_threshold_s)) {
3030 } else if (presnap < best) {
3031 if (presnap < (best - snap_threshold_s)) {
3036 start.set (best, 0);
3041 Editor::setup_toolbar ()
3043 HBox* mode_box = manage(new HBox);
3044 mode_box->set_border_width (2);
3045 mode_box->set_spacing(2);
3047 HBox* mouse_mode_box = manage (new HBox);
3048 HBox* mouse_mode_hbox = manage (new HBox);
3049 VBox* mouse_mode_vbox = manage (new VBox);
3050 Alignment* mouse_mode_align = manage (new Alignment);
3052 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
3053 mouse_mode_size_group->add_widget (smart_mode_button);
3054 mouse_mode_size_group->add_widget (mouse_move_button);
3055 if (!Profile->get_mixbus()) {
3056 mouse_mode_size_group->add_widget (mouse_cut_button);
3058 mouse_mode_size_group->add_widget (mouse_select_button);
3059 mouse_mode_size_group->add_widget (mouse_timefx_button);
3060 if (!Profile->get_mixbus()) {
3061 mouse_mode_size_group->add_widget (mouse_audition_button);
3063 mouse_mode_size_group->add_widget (mouse_draw_button);
3064 mouse_mode_size_group->add_widget (mouse_content_button);
3066 if (!Profile->get_mixbus()) {
3067 mouse_mode_size_group->add_widget (zoom_in_button);
3068 mouse_mode_size_group->add_widget (zoom_out_button);
3069 mouse_mode_size_group->add_widget (zoom_out_full_button);
3070 mouse_mode_size_group->add_widget (zoom_focus_selector);
3071 mouse_mode_size_group->add_widget (tav_shrink_button);
3072 mouse_mode_size_group->add_widget (tav_expand_button);
3074 mouse_mode_size_group->add_widget (zoom_preset_selector);
3075 mouse_mode_size_group->add_widget (visible_tracks_selector);
3078 mouse_mode_size_group->add_widget (grid_type_selector);
3079 mouse_mode_size_group->add_widget (snap_mode_button);
3081 mouse_mode_size_group->add_widget (edit_point_selector);
3082 mouse_mode_size_group->add_widget (edit_mode_selector);
3084 mouse_mode_size_group->add_widget (*nudge_clock);
3085 mouse_mode_size_group->add_widget (nudge_forward_button);
3086 mouse_mode_size_group->add_widget (nudge_backward_button);
3088 mouse_mode_hbox->set_spacing (2);
3090 if (!ARDOUR::Profile->get_trx()) {
3091 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
3094 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
3095 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
3097 if (!ARDOUR::Profile->get_mixbus()) {
3098 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
3099 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
3102 if (!ARDOUR::Profile->get_trx()) {
3103 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
3104 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
3105 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
3108 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
3110 mouse_mode_align->add (*mouse_mode_vbox);
3111 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
3113 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
3115 edit_mode_selector.set_name ("mouse mode button");
3117 if (!ARDOUR::Profile->get_trx()) {
3118 mode_box->pack_start (edit_mode_selector, false, false);
3119 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3120 mode_box->pack_start (edit_point_selector, false, false);
3121 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3124 mode_box->pack_start (*mouse_mode_box, false, false);
3128 _zoom_box.set_spacing (2);
3129 _zoom_box.set_border_width (2);
3133 zoom_preset_selector.set_name ("zoom button");
3134 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
3136 zoom_in_button.set_name ("zoom button");
3137 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3138 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3139 zoom_in_button.set_related_action (act);
3141 zoom_out_button.set_name ("zoom button");
3142 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3143 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3144 zoom_out_button.set_related_action (act);
3146 zoom_out_full_button.set_name ("zoom button");
3147 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3148 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3149 zoom_out_full_button.set_related_action (act);
3151 zoom_focus_selector.set_name ("zoom button");
3153 if (ARDOUR::Profile->get_mixbus()) {
3154 _zoom_box.pack_start (zoom_preset_selector, false, false);
3155 } else if (ARDOUR::Profile->get_trx()) {
3156 mode_box->pack_start (zoom_out_button, false, false);
3157 mode_box->pack_start (zoom_in_button, false, false);
3159 _zoom_box.pack_start (zoom_out_button, false, false);
3160 _zoom_box.pack_start (zoom_in_button, false, false);
3161 _zoom_box.pack_start (zoom_out_full_button, false, false);
3162 _zoom_box.pack_start (zoom_focus_selector, false, false);
3165 /* Track zoom buttons */
3166 _track_box.set_spacing (2);
3167 _track_box.set_border_width (2);
3169 visible_tracks_selector.set_name ("zoom button");
3170 if (Profile->get_mixbus()) {
3171 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3173 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3176 tav_expand_button.set_name ("zoom button");
3177 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3178 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3179 tav_expand_button.set_related_action (act);
3181 tav_shrink_button.set_name ("zoom button");
3182 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3183 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3184 tav_shrink_button.set_related_action (act);
3186 if (ARDOUR::Profile->get_mixbus()) {
3187 _track_box.pack_start (visible_tracks_selector);
3188 } else if (ARDOUR::Profile->get_trx()) {
3189 _track_box.pack_start (tav_shrink_button);
3190 _track_box.pack_start (tav_expand_button);
3192 _track_box.pack_start (visible_tracks_selector);
3193 _track_box.pack_start (tav_shrink_button);
3194 _track_box.pack_start (tav_expand_button);
3197 snap_box.set_spacing (2);
3198 snap_box.set_border_width (2);
3200 grid_type_selector.set_name ("mouse mode button");
3202 snap_mode_button.set_name ("mouse mode button");
3204 edit_point_selector.set_name ("mouse mode button");
3206 snap_box.pack_start (snap_mode_button, false, false);
3207 snap_box.pack_start (grid_type_selector, false, false);
3211 HBox *nudge_box = manage (new HBox);
3212 nudge_box->set_spacing (2);
3213 nudge_box->set_border_width (2);
3215 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3216 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3218 nudge_box->pack_start (nudge_backward_button, false, false);
3219 nudge_box->pack_start (nudge_forward_button, false, false);
3220 nudge_box->pack_start (*nudge_clock, false, false);
3223 /* Pack everything in... */
3225 toolbar_hbox.set_spacing (2);
3226 toolbar_hbox.set_border_width (2);
3228 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3229 tool_shadow->set_size_request (4, -1);
3230 tool_shadow->show();
3232 ebox_hpacker.pack_start (*tool_shadow, false, false);
3233 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3235 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3236 spacer->set_name("EditorWindow");
3237 spacer->set_size_request(-1,4);
3240 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3241 ebox_vpacker.pack_start(*spacer, false, false);
3242 ebox_vpacker.show();
3244 toolbar_hbox.pack_start (*mode_box, false, false);
3246 if (!ARDOUR::Profile->get_trx()) {
3248 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3250 toolbar_hbox.pack_start (snap_box, false, false);
3252 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3254 toolbar_hbox.pack_start (*nudge_box, false, false);
3256 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3258 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3260 toolbar_hbox.pack_end (_track_box, false, false);
3264 toolbar_hbox.show_all ();
3268 Editor::build_edit_point_menu ()
3270 using namespace Menu_Helpers;
3272 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3273 if(!Profile->get_mixbus())
3274 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3275 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3277 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3281 Editor::build_edit_mode_menu ()
3283 using namespace Menu_Helpers;
3285 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3286 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3287 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3288 /* Note: Splice was removed */
3290 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3294 Editor::build_grid_type_menu ()
3296 using namespace Menu_Helpers;
3298 /* main grid: bars, quarter-notes, etc */
3299 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3300 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3301 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3302 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3303 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3304 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3305 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3306 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3309 grid_type_selector.AddMenuElem(SeparatorElem());
3310 Gtk::Menu *_triplet_menu = manage (new Menu);
3311 MenuList& triplet_items (_triplet_menu->items());
3313 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3314 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3315 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3316 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3318 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3320 /* quintuplet grid */
3321 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3322 MenuList& quintuplet_items (_quintuplet_menu->items());
3324 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3325 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3326 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3328 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3330 /* septuplet grid */
3331 Gtk::Menu *_septuplet_menu = manage (new Menu);
3332 MenuList& septuplet_items (_septuplet_menu->items());
3334 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3335 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3336 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3338 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3340 grid_type_selector.AddMenuElem(SeparatorElem());
3341 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3342 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3343 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3347 Editor::setup_tooltips ()
3349 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3350 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3351 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3352 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3353 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3354 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3355 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3356 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3357 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3358 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3359 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3360 set_tooltip (zoom_in_button, _("Zoom In"));
3361 set_tooltip (zoom_out_button, _("Zoom Out"));
3362 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3363 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3364 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3365 set_tooltip (tav_expand_button, _("Expand Tracks"));
3366 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3367 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3368 set_tooltip (grid_type_selector, _("Grid Mode"));
3369 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3370 set_tooltip (edit_point_selector, _("Edit Point"));
3371 set_tooltip (edit_mode_selector, _("Edit Mode"));
3372 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3376 Editor::convert_drop_to_paths (
3377 vector<string>& paths,
3378 const RefPtr<Gdk::DragContext>& /*context*/,
3381 const SelectionData& data,
3385 if (_session == 0) {
3389 vector<string> uris = data.get_uris();
3393 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3394 are actually URI lists. So do it by hand.
3397 if (data.get_target() != "text/plain") {
3401 /* Parse the "uri-list" format that Nautilus provides,
3402 where each pathname is delimited by \r\n.
3404 THERE MAY BE NO NULL TERMINATING CHAR!!!
3407 string txt = data.get_text();
3411 p = (char *) malloc (txt.length() + 1);
3412 txt.copy (p, txt.length(), 0);
3413 p[txt.length()] = '\0';
3419 while (g_ascii_isspace (*p))
3423 while (*q && (*q != '\n') && (*q != '\r')) {
3430 while (q > p && g_ascii_isspace (*q))
3435 uris.push_back (string (p, q - p + 1));
3439 p = strchr (p, '\n');
3451 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3452 if ((*i).substr (0,7) == "file://") {
3453 paths.push_back (Glib::filename_from_uri (*i));
3461 Editor::new_tempo_section ()
3466 Editor::map_transport_state ()
3468 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3470 if (_session && _session->transport_stopped()) {
3471 have_pending_keyboard_selection = false;
3474 update_loop_range_view ();
3478 Editor::transport_looped ()
3480 /* reset Playhead position interpolation.
3481 * see Editor::super_rapid_screen_update
3483 _last_update_time = 0;
3489 Editor::begin_selection_op_history ()
3491 selection_op_cmd_depth = 0;
3492 selection_op_history_it = 0;
3494 while(!selection_op_history.empty()) {
3495 delete selection_op_history.front();
3496 selection_op_history.pop_front();
3499 selection_undo_action->set_sensitive (false);
3500 selection_redo_action->set_sensitive (false);
3501 selection_op_history.push_front (&_selection_memento->get_state ());
3505 Editor::begin_reversible_selection_op (string name)
3508 //cerr << name << endl;
3509 /* begin/commit pairs can be nested */
3510 selection_op_cmd_depth++;
3515 Editor::commit_reversible_selection_op ()
3518 if (selection_op_cmd_depth == 1) {
3520 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3521 /* The user has undone some selection ops and then made a new one,
3522 * making anything earlier in the list invalid.
3525 list<XMLNode *>::iterator it = selection_op_history.begin();
3526 list<XMLNode *>::iterator e_it = it;
3527 advance (e_it, selection_op_history_it);
3529 for (; it != e_it; ++it) {
3532 selection_op_history.erase (selection_op_history.begin(), e_it);
3535 selection_op_history.push_front (&_selection_memento->get_state ());
3536 selection_op_history_it = 0;
3538 selection_undo_action->set_sensitive (true);
3539 selection_redo_action->set_sensitive (false);
3542 if (selection_op_cmd_depth > 0) {
3543 selection_op_cmd_depth--;
3549 Editor::undo_selection_op ()
3552 selection_op_history_it++;
3554 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3555 if (n == selection_op_history_it) {
3556 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3557 selection_redo_action->set_sensitive (true);
3561 /* is there an earlier entry? */
3562 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3563 selection_undo_action->set_sensitive (false);
3569 Editor::redo_selection_op ()
3572 if (selection_op_history_it > 0) {
3573 selection_op_history_it--;
3576 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3577 if (n == selection_op_history_it) {
3578 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3579 selection_undo_action->set_sensitive (true);
3584 if (selection_op_history_it == 0) {
3585 selection_redo_action->set_sensitive (false);
3591 Editor::begin_reversible_command (string name)
3594 before.push_back (&_selection_memento->get_state ());
3595 _session->begin_reversible_command (name);
3600 Editor::begin_reversible_command (GQuark q)
3603 before.push_back (&_selection_memento->get_state ());
3604 _session->begin_reversible_command (q);
3609 Editor::abort_reversible_command ()
3612 while(!before.empty()) {
3613 delete before.front();
3616 _session->abort_reversible_command ();
3621 Editor::commit_reversible_command ()
3624 if (before.size() == 1) {
3625 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3626 redo_action->set_sensitive(false);
3627 undo_action->set_sensitive(true);
3628 begin_selection_op_history ();
3631 if (before.empty()) {
3632 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3637 _session->commit_reversible_command ();
3642 Editor::history_changed ()
3646 if (undo_action && _session) {
3647 if (_session->undo_depth() == 0) {
3648 label = S_("Command|Undo");
3650 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3652 undo_action->property_label() = label;
3655 if (redo_action && _session) {
3656 if (_session->redo_depth() == 0) {
3658 redo_action->set_sensitive (false);
3660 label = string_compose(_("Redo (%1)"), _session->next_redo());
3661 redo_action->set_sensitive (true);
3663 redo_action->property_label() = label;
3668 Editor::duplicate_range (bool with_dialog)
3672 RegionSelection rs = get_regions_from_selection_and_entered ();
3674 if (selection->time.length() == 0 && rs.empty()) {
3680 ArdourDialog win (_("Duplicate"));
3681 Label label (_("Number of duplications:"));
3682 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3683 SpinButton spinner (adjustment, 0.0, 1);
3686 win.get_vbox()->set_spacing (12);
3687 win.get_vbox()->pack_start (hbox);
3688 hbox.set_border_width (6);
3689 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3691 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3692 place, visually. so do this by hand.
3695 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3696 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3697 spinner.grab_focus();
3703 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3704 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3705 win.set_default_response (RESPONSE_ACCEPT);
3707 spinner.grab_focus ();
3709 switch (win.run ()) {
3710 case RESPONSE_ACCEPT:
3716 times = adjustment.get_value();
3719 if ((current_mouse_mode() == MouseRange)) {
3720 if (selection->time.length()) {
3721 duplicate_selection (times);
3723 } else if (get_smart_mode()) {
3724 if (selection->time.length()) {
3725 duplicate_selection (times);
3727 duplicate_some_regions (rs, times);
3729 duplicate_some_regions (rs, times);
3734 Editor::set_edit_mode (EditMode m)
3736 Config->set_edit_mode (m);
3740 Editor::cycle_edit_mode ()
3742 switch (Config->get_edit_mode()) {
3744 Config->set_edit_mode (Ripple);
3748 Config->set_edit_mode (Lock);
3751 Config->set_edit_mode (Slide);
3757 Editor::edit_mode_selection_done (EditMode m)
3759 Config->set_edit_mode (m);
3763 Editor::grid_type_selection_done (GridType gridtype)
3765 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3767 ract->set_active ();
3772 Editor::snap_mode_selection_done (SnapMode mode)
3774 RefPtr<RadioAction> ract = snap_mode_action (mode);
3777 ract->set_active (true);
3782 Editor::cycle_edit_point (bool with_marker)
3784 if(Profile->get_mixbus())
3785 with_marker = false;
3787 switch (_edit_point) {
3789 set_edit_point_preference (EditAtPlayhead);
3791 case EditAtPlayhead:
3793 set_edit_point_preference (EditAtSelectedMarker);
3795 set_edit_point_preference (EditAtMouse);
3798 case EditAtSelectedMarker:
3799 set_edit_point_preference (EditAtMouse);
3805 Editor::edit_point_selection_done (EditPoint ep)
3807 set_edit_point_preference (ep);
3811 Editor::build_zoom_focus_menu ()
3813 using namespace Menu_Helpers;
3815 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3816 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3817 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3818 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3819 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3820 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3822 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3826 Editor::zoom_focus_selection_done (ZoomFocus f)
3828 RefPtr<RadioAction> ract = zoom_focus_action (f);
3830 ract->set_active ();
3835 Editor::build_track_count_menu ()
3837 using namespace Menu_Helpers;
3839 if (!Profile->get_mixbus()) {
3840 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3841 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3842 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3843 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3844 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3845 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3846 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3847 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3848 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3849 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3850 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3851 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3852 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3854 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3855 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3856 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3857 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3858 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3859 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3860 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3861 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3862 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3863 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3865 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3866 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3867 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3868 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3869 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3870 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3871 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3872 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3873 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3874 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3875 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3876 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3881 Editor::set_zoom_preset (int64_t ms)
3884 temporal_zoom_session();
3888 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3889 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3893 Editor::set_visible_track_count (int32_t n)
3895 _visible_track_count = n;
3897 /* if the canvas hasn't really been allocated any size yet, just
3898 record the desired number of visible tracks and return. when canvas
3899 allocation happens, we will get called again and then we can do the
3903 if (_visible_canvas_height <= 1) {
3909 DisplaySuspender ds;
3911 if (_visible_track_count > 0) {
3912 h = trackviews_height() / _visible_track_count;
3913 std::ostringstream s;
3914 s << _visible_track_count;
3916 } else if (_visible_track_count == 0) {
3918 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3919 if ((*i)->marked_for_display()) {
3921 TimeAxisView::Children cl ((*i)->get_child_list ());
3922 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3923 if ((*j)->marked_for_display()) {
3930 visible_tracks_selector.set_text (X_("*"));
3933 h = trackviews_height() / n;
3936 /* negative value means that the visible track count has
3937 been overridden by explicit track height changes.
3939 visible_tracks_selector.set_text (X_("*"));
3943 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3944 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3947 if (str != visible_tracks_selector.get_text()) {
3948 visible_tracks_selector.set_text (str);
3953 Editor::override_visible_track_count ()
3955 _visible_track_count = -1;
3956 visible_tracks_selector.set_text (_("*"));
3960 Editor::edit_controls_button_release (GdkEventButton* ev)
3962 if (Keyboard::is_context_menu_event (ev)) {
3963 ARDOUR_UI::instance()->add_route ();
3964 } else if (ev->button == 1) {
3965 selection->clear_tracks ();
3972 Editor::mouse_select_button_release (GdkEventButton* ev)
3974 /* this handles just right-clicks */
3976 if (ev->button != 3) {
3984 Editor::set_zoom_focus (ZoomFocus f)
3986 string str = zoom_focus_strings[(int)f];
3988 if (str != zoom_focus_selector.get_text()) {
3989 zoom_focus_selector.set_text (str);
3992 if (zoom_focus != f) {
3999 Editor::cycle_zoom_focus ()
4001 switch (zoom_focus) {
4003 set_zoom_focus (ZoomFocusRight);
4005 case ZoomFocusRight:
4006 set_zoom_focus (ZoomFocusCenter);
4008 case ZoomFocusCenter:
4009 set_zoom_focus (ZoomFocusPlayhead);
4011 case ZoomFocusPlayhead:
4012 set_zoom_focus (ZoomFocusMouse);
4014 case ZoomFocusMouse:
4015 set_zoom_focus (ZoomFocusEdit);
4018 set_zoom_focus (ZoomFocusLeft);
4024 Editor::update_grid ()
4026 if (grid_musical()) {
4027 std::vector<TempoMap::BBTPoint> grid;
4028 if (bbt_ruler_scale != bbt_show_many) {
4029 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
4031 maybe_draw_grid_lines ();
4032 } else if (grid_nonmusical()) {
4033 maybe_draw_grid_lines ();
4040 Editor::toggle_follow_playhead ()
4042 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-follow-playhead"));
4043 set_follow_playhead (tact->get_active());
4046 /** @param yn true to follow playhead, otherwise false.
4047 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
4050 Editor::set_follow_playhead (bool yn, bool catch_up)
4052 if (_follow_playhead != yn) {
4053 if ((_follow_playhead = yn) == true && catch_up) {
4055 reset_x_origin_to_follow_playhead ();
4062 Editor::toggle_stationary_playhead ()
4064 RefPtr<ToggleAction> tact = ActionManager::get_toggle_action (X_("Editor"), X_("toggle-stationary-playhead"));
4065 set_stationary_playhead (tact->get_active());
4069 Editor::set_stationary_playhead (bool yn)
4071 if (_stationary_playhead != yn) {
4072 if ((_stationary_playhead = yn) == true) {
4073 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
4074 // update_current_screen ();
4081 Editor::playlist_selector () const
4083 return *_playlist_selector;
4087 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
4089 if (paste_count == 0) {
4090 /* don't bother calculating an offset that will be zero anyway */
4094 /* calculate basic unsnapped multi-paste offset */
4095 samplecnt_t offset = paste_count * duration;
4097 /* snap offset so pos + offset is aligned to the grid */
4098 MusicSample offset_pos (pos + offset, 0);
4099 snap_to(offset_pos, RoundUpMaybe);
4100 offset = offset_pos.sample - pos;
4106 Editor::get_grid_beat_divisions(samplepos_t position)
4108 switch (_grid_type) {
4109 case GridTypeBeatDiv32: return 32;
4110 case GridTypeBeatDiv28: return 28;
4111 case GridTypeBeatDiv24: return 24;
4112 case GridTypeBeatDiv20: return 20;
4113 case GridTypeBeatDiv16: return 16;
4114 case GridTypeBeatDiv14: return 14;
4115 case GridTypeBeatDiv12: return 12;
4116 case GridTypeBeatDiv10: return 10;
4117 case GridTypeBeatDiv8: return 8;
4118 case GridTypeBeatDiv7: return 7;
4119 case GridTypeBeatDiv6: return 6;
4120 case GridTypeBeatDiv5: return 5;
4121 case GridTypeBeatDiv4: return 4;
4122 case GridTypeBeatDiv3: return 3;
4123 case GridTypeBeatDiv2: return 2;
4124 case GridTypeBeat: return 1;
4125 case GridTypeBar: return 1;
4127 case GridTypeNone: return 0;
4128 case GridTypeTimecode: return 0;
4129 case GridTypeMinSec: return 0;
4130 case GridTypeCDFrame: return 0;
4136 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4137 if the grid is non-musical, returns 0.
4138 if the grid is snapped to bars, returns -1.
4139 @param event_state the current keyboard modifier mask.
4142 Editor::get_grid_music_divisions (uint32_t event_state)
4144 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4148 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4152 switch (_grid_type) {
4153 case GridTypeBeatDiv32: return 32;
4154 case GridTypeBeatDiv28: return 28;
4155 case GridTypeBeatDiv24: return 24;
4156 case GridTypeBeatDiv20: return 20;
4157 case GridTypeBeatDiv16: return 16;
4158 case GridTypeBeatDiv14: return 14;
4159 case GridTypeBeatDiv12: return 12;
4160 case GridTypeBeatDiv10: return 10;
4161 case GridTypeBeatDiv8: return 8;
4162 case GridTypeBeatDiv7: return 7;
4163 case GridTypeBeatDiv6: return 6;
4164 case GridTypeBeatDiv5: return 5;
4165 case GridTypeBeatDiv4: return 4;
4166 case GridTypeBeatDiv3: return 3;
4167 case GridTypeBeatDiv2: return 2;
4168 case GridTypeBeat: return 1;
4169 case GridTypeBar : return -1;
4171 case GridTypeNone: return 0;
4172 case GridTypeTimecode: return 0;
4173 case GridTypeMinSec: return 0;
4174 case GridTypeCDFrame: return 0;
4180 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4184 const unsigned divisions = get_grid_beat_divisions(position);
4186 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4189 switch (_grid_type) {
4191 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4194 const Meter& m = _session->tempo_map().meter_at_sample (position);
4195 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4203 return Temporal::Beats();
4207 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4211 ret = nudge_clock->current_duration (pos);
4212 next = ret + 1; /* XXXX fix me */
4218 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4220 ArdourDialog dialog (_("Playlist Deletion"));
4221 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4222 "If it is kept, its audio files will not be cleaned.\n"
4223 "If it is deleted, audio files used by it alone will be cleaned."),
4226 dialog.set_position (WIN_POS_CENTER);
4227 dialog.get_vbox()->pack_start (label);
4231 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4232 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4233 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4234 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4235 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4237 /* by default gtk uses the left most button */
4238 keep->grab_focus ();
4240 switch (dialog.run ()) {
4242 /* keep this and all remaining ones */
4247 /* delete this and all others */
4251 case RESPONSE_ACCEPT:
4252 /* delete the playlist */
4256 case RESPONSE_REJECT:
4257 /* keep the playlist */
4269 Editor::audio_region_selection_covers (samplepos_t where)
4271 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4272 if ((*a)->region()->covers (where)) {
4281 Editor::cleanup_regions ()
4283 _regions->remove_unused_regions();
4288 Editor::prepare_for_cleanup ()
4290 cut_buffer->clear_regions ();
4291 cut_buffer->clear_playlists ();
4293 selection->clear_regions ();
4294 selection->clear_playlists ();
4296 _regions->suspend_redisplay ();
4300 Editor::finish_cleanup ()
4302 _regions->resume_redisplay ();
4306 Editor::transport_loop_location()
4309 return _session->locations()->auto_loop_location();
4316 Editor::transport_punch_location()
4319 return _session->locations()->auto_punch_location();
4326 Editor::control_layout_scroll (GdkEventScroll* ev)
4328 /* Just forward to the normal canvas scroll method. The coordinate
4329 systems are different but since the canvas is always larger than the
4330 track headers, and aligned with the trackview area, this will work.
4332 In the not too distant future this layout is going away anyway and
4333 headers will be on the canvas.
4335 return canvas_scroll_event (ev, false);
4339 Editor::session_state_saved (string)
4342 _snapshots->redisplay ();
4346 Editor::maximise_editing_space ()
4352 Gtk::Window* toplevel = current_toplevel();
4355 toplevel->fullscreen ();
4361 Editor::restore_editing_space ()
4367 Gtk::Window* toplevel = current_toplevel();
4370 toplevel->unfullscreen();
4376 * Make new playlists for a given track and also any others that belong
4377 * to the same active route group with the `select' property.
4382 Editor::new_playlists (TimeAxisView* v)
4384 begin_reversible_command (_("new playlists"));
4385 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4386 _session->playlists()->get (playlists);
4387 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4388 commit_reversible_command ();
4392 * Use a copy of the current playlist for a given track and also any others that belong
4393 * to the same active route group with the `select' property.
4398 Editor::copy_playlists (TimeAxisView* v)
4400 begin_reversible_command (_("copy playlists"));
4401 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4402 _session->playlists()->get (playlists);
4403 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4404 commit_reversible_command ();
4407 /** Clear the current playlist for a given track and also any others that belong
4408 * to the same active route group with the `select' property.
4413 Editor::clear_playlists (TimeAxisView* v)
4415 begin_reversible_command (_("clear playlists"));
4416 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4417 _session->playlists()->get (playlists);
4418 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4419 commit_reversible_command ();
4423 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4425 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4429 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4431 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4435 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4437 atv.clear_playlist ();
4441 Editor::get_y_origin () const
4443 return vertical_adjustment.get_value ();
4446 /** Queue up a change to the viewport x origin.
4447 * @param sample New x origin.
4450 Editor::reset_x_origin (samplepos_t sample)
4452 pending_visual_change.add (VisualChange::TimeOrigin);
4453 pending_visual_change.time_origin = sample;
4454 ensure_visual_change_idle_handler ();
4458 Editor::reset_y_origin (double y)
4460 pending_visual_change.add (VisualChange::YOrigin);
4461 pending_visual_change.y_origin = y;
4462 ensure_visual_change_idle_handler ();
4466 Editor::reset_zoom (samplecnt_t spp)
4468 if (spp == samples_per_pixel) {
4472 pending_visual_change.add (VisualChange::ZoomLevel);
4473 pending_visual_change.samples_per_pixel = spp;
4474 ensure_visual_change_idle_handler ();
4478 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4480 reset_x_origin (sample);
4483 if (!no_save_visual) {
4484 undo_visual_stack.push_back (current_visual_state(false));
4488 Editor::VisualState::VisualState (bool with_tracks)
4489 : gui_state (with_tracks ? new GUIObjectState : 0)
4493 Editor::VisualState::~VisualState ()
4498 Editor::VisualState*
4499 Editor::current_visual_state (bool with_tracks)
4501 VisualState* vs = new VisualState (with_tracks);
4502 vs->y_position = vertical_adjustment.get_value();
4503 vs->samples_per_pixel = samples_per_pixel;
4504 vs->_leftmost_sample = _leftmost_sample;
4505 vs->zoom_focus = zoom_focus;
4508 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4515 Editor::undo_visual_state ()
4517 if (undo_visual_stack.empty()) {
4521 VisualState* vs = undo_visual_stack.back();
4522 undo_visual_stack.pop_back();
4525 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4528 use_visual_state (*vs);
4533 Editor::redo_visual_state ()
4535 if (redo_visual_stack.empty()) {
4539 VisualState* vs = redo_visual_stack.back();
4540 redo_visual_stack.pop_back();
4542 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4543 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4546 use_visual_state (*vs);
4551 Editor::swap_visual_state ()
4553 if (undo_visual_stack.empty()) {
4554 redo_visual_state ();
4556 undo_visual_state ();
4561 Editor::use_visual_state (VisualState& vs)
4563 PBD::Unwinder<bool> nsv (no_save_visual, true);
4564 DisplaySuspender ds;
4566 vertical_adjustment.set_value (vs.y_position);
4568 set_zoom_focus (vs.zoom_focus);
4569 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4572 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4574 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4575 (*i)->clear_property_cache();
4576 (*i)->reset_visual_state ();
4580 _routes->update_visibility ();
4583 /** This is the core function that controls the zoom level of the canvas. It is called
4584 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4585 * @param spp new number of samples per pixel
4588 Editor::set_samples_per_pixel (samplecnt_t spp)
4594 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4595 const samplecnt_t lots_of_pixels = 4000;
4597 /* if the zoom level is greater than what you'd get trying to display 3
4598 * days of audio on a really big screen, then it's too big.
4601 if (spp * lots_of_pixels > three_days) {
4605 samples_per_pixel = spp;
4609 Editor::on_samples_per_pixel_changed ()
4611 bool const showing_time_selection = selection->time.length() > 0;
4613 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4614 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4615 (*i)->reshow_selection (selection->time);
4619 ZoomChanged (); /* EMIT_SIGNAL */
4621 ArdourCanvas::GtkCanvasViewport* c;
4623 c = get_track_canvas();
4625 c->canvas()->zoomed ();
4628 if (playhead_cursor) {
4629 playhead_cursor->set_position (playhead_cursor->current_sample ());
4632 refresh_location_display();
4633 _summary->set_overlays_dirty ();
4635 update_marker_labels ();
4641 Editor::playhead_cursor_sample () const
4643 return playhead_cursor->current_sample();
4647 Editor::queue_visual_videotimeline_update ()
4649 pending_visual_change.add (VisualChange::VideoTimeline);
4650 ensure_visual_change_idle_handler ();
4654 Editor::ensure_visual_change_idle_handler ()
4656 if (pending_visual_change.idle_handler_id < 0) {
4657 /* see comment in add_to_idle_resize above. */
4658 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4659 pending_visual_change.being_handled = false;
4664 Editor::_idle_visual_changer (void* arg)
4666 return static_cast<Editor*>(arg)->idle_visual_changer ();
4670 Editor::pre_render ()
4672 visual_change_queued = false;
4674 if (pending_visual_change.pending != 0) {
4675 ensure_visual_change_idle_handler();
4680 Editor::idle_visual_changer ()
4682 pending_visual_change.idle_handler_id = -1;
4684 if (pending_visual_change.pending == 0) {
4688 /* set_horizontal_position() below (and maybe other calls) call
4689 gtk_main_iteration(), so it's possible that a signal will be handled
4690 half-way through this method. If this signal wants an
4691 idle_visual_changer we must schedule another one after this one, so
4692 mark the idle_handler_id as -1 here to allow that. Also make a note
4693 that we are doing the visual change, so that changes in response to
4694 super-rapid-screen-update can be dropped if we are still processing
4698 if (visual_change_queued) {
4702 pending_visual_change.being_handled = true;
4704 VisualChange vc = pending_visual_change;
4706 pending_visual_change.pending = (VisualChange::Type) 0;
4708 visual_changer (vc);
4710 pending_visual_change.being_handled = false;
4712 visual_change_queued = true;
4714 return 0; /* this is always a one-shot call */
4718 Editor::visual_changer (const VisualChange& vc)
4721 * Changed first so the correct horizontal canvas position is calculated in
4722 * Editor::set_horizontal_position
4724 if (vc.pending & VisualChange::ZoomLevel) {
4725 set_samples_per_pixel (vc.samples_per_pixel);
4728 if (vc.pending & VisualChange::TimeOrigin) {
4729 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4730 set_horizontal_position (new_time_origin);
4733 if (vc.pending & VisualChange::YOrigin) {
4734 vertical_adjustment.set_value (vc.y_origin);
4738 * Now the canvas is in the final state before render the canvas items that
4739 * support the Item::prepare_for_render interface can calculate the correct
4740 * item to visible canvas intersection.
4742 if (vc.pending & VisualChange::ZoomLevel) {
4743 on_samples_per_pixel_changed ();
4745 compute_fixed_ruler_scale ();
4747 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4748 update_tempo_based_rulers ();
4751 if (!(vc.pending & VisualChange::ZoomLevel)) {
4752 /* If the canvas is not being zoomed then the canvas items will not change
4753 * and cause Item::prepare_for_render to be called so do it here manually.
4754 * Not ideal, but I can't think of a better solution atm.
4756 _track_canvas->prepare_for_render();
4759 /* If we are only scrolling vertically there is no need to update these */
4760 if (vc.pending != VisualChange::YOrigin) {
4761 update_fixed_rulers ();
4762 redisplay_grid (true);
4764 /* video frames & position need to be updated for zoom, horiz-scroll
4765 * and (explicitly) VisualChange::VideoTimeline.
4767 update_video_timeline();
4770 _summary->set_overlays_dirty ();
4773 struct EditorOrderTimeAxisSorter {
4774 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4775 return a->order () < b->order ();
4780 Editor::sort_track_selection (TrackViewList& sel)
4782 EditorOrderTimeAxisSorter cmp;
4787 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4790 samplepos_t where = 0;
4791 EditPoint ep = _edit_point;
4793 if (Profile->get_mixbus()) {
4794 if (ep == EditAtSelectedMarker) {
4795 ep = EditAtPlayhead;
4799 if (from_outside_canvas && (ep == EditAtMouse)) {
4800 ep = EditAtPlayhead;
4801 } else if (from_context_menu && (ep == EditAtMouse)) {
4802 return canvas_event_sample (&context_click_event, 0, 0);
4805 if (entered_marker) {
4806 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4807 return entered_marker->position();
4810 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4811 ep = EditAtSelectedMarker;
4814 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4815 ep = EditAtPlayhead;
4818 MusicSample snap_mf (0, 0);
4821 case EditAtPlayhead:
4822 if (_dragging_playhead) {
4823 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4824 where = playhead_cursor->current_sample();
4826 where = _session->audible_sample();
4828 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4831 case EditAtSelectedMarker:
4832 if (!selection->markers.empty()) {
4834 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4837 where = loc->start();
4841 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4849 if (!mouse_sample (where, ignored)) {
4850 /* XXX not right but what can we do ? */
4853 snap_mf.sample = where;
4855 where = snap_mf.sample;
4856 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4864 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4866 if (!_session) return;
4868 begin_reversible_command (cmd);
4872 if ((tll = transport_loop_location()) == 0) {
4873 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4874 XMLNode &before = _session->locations()->get_state();
4875 _session->locations()->add (loc, true);
4876 _session->set_auto_loop_location (loc);
4877 XMLNode &after = _session->locations()->get_state();
4878 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4880 XMLNode &before = tll->get_state();
4881 tll->set_hidden (false, this);
4882 tll->set (start, end);
4883 XMLNode &after = tll->get_state();
4884 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4887 commit_reversible_command ();
4891 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4893 if (!_session) return;
4895 begin_reversible_command (cmd);
4899 if ((tpl = transport_punch_location()) == 0) {
4900 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4901 XMLNode &before = _session->locations()->get_state();
4902 _session->locations()->add (loc, true);
4903 _session->set_auto_punch_location (loc);
4904 XMLNode &after = _session->locations()->get_state();
4905 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4907 XMLNode &before = tpl->get_state();
4908 tpl->set_hidden (false, this);
4909 tpl->set (start, end);
4910 XMLNode &after = tpl->get_state();
4911 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4914 commit_reversible_command ();
4917 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4918 * @param rs List to which found regions are added.
4919 * @param where Time to look at.
4920 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4923 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4925 const TrackViewList* tracks;
4928 tracks = &track_views;
4933 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4935 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4938 boost::shared_ptr<Track> tr;
4939 boost::shared_ptr<Playlist> pl;
4941 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4943 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4945 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4946 RegionView* rv = rtv->view()->find_view (*i);
4957 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4959 const TrackViewList* tracks;
4962 tracks = &track_views;
4967 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4968 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4970 boost::shared_ptr<Track> tr;
4971 boost::shared_ptr<Playlist> pl;
4973 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4975 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4977 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4979 RegionView* rv = rtv->view()->find_view (*i);
4990 /** Get regions using the following method:
4992 * Make a region list using:
4993 * (a) any selected regions
4994 * (b) the intersection of any selected tracks and the edit point(*)
4995 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4997 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4999 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5003 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
5005 RegionSelection regions;
5007 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5008 regions.add (entered_regionview);
5010 regions = selection->regions;
5013 if (regions.empty()) {
5014 TrackViewList tracks = selection->tracks;
5016 if (!tracks.empty()) {
5017 /* no region selected or entered, but some selected tracks:
5018 * act on all regions on the selected tracks at the edit point
5020 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
5021 get_regions_at(regions, where, tracks);
5028 /** Get regions using the following method:
5030 * Make a region list using:
5031 * (a) any selected regions
5032 * (b) the intersection of any selected tracks and the edit point(*)
5033 * (c) if neither exists, then whatever region is under the mouse
5035 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
5037 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
5040 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
5042 RegionSelection regions;
5044 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
5045 regions.add (entered_regionview);
5047 regions = selection->regions;
5050 if (regions.empty()) {
5051 TrackViewList tracks = selection->tracks;
5053 if (!tracks.empty()) {
5054 /* no region selected or entered, but some selected tracks:
5055 * act on all regions on the selected tracks at the edit point
5057 get_regions_at(regions, pos, tracks);
5064 /** Start with regions that are selected, or the entered regionview if none are selected.
5065 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
5066 * of the regions that we started with.
5070 Editor::get_regions_from_selection_and_entered () const
5072 RegionSelection regions = selection->regions;
5074 if (regions.empty() && entered_regionview) {
5075 regions.add (entered_regionview);
5082 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
5084 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5085 RouteTimeAxisView* rtav;
5087 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5088 boost::shared_ptr<Playlist> pl;
5089 std::vector<boost::shared_ptr<Region> > results;
5090 boost::shared_ptr<Track> tr;
5092 if ((tr = rtav->track()) == 0) {
5097 if ((pl = (tr->playlist())) != 0) {
5098 boost::shared_ptr<Region> r = pl->region_by_id (id);
5100 RegionView* rv = rtav->view()->find_view (r);
5102 regions.push_back (rv);
5111 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
5114 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5115 MidiTimeAxisView* mtav;
5117 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
5119 mtav->get_per_region_note_selection (selection);
5126 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
5128 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5130 RouteTimeAxisView* tatv;
5132 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5134 boost::shared_ptr<Playlist> pl;
5135 vector<boost::shared_ptr<Region> > results;
5137 boost::shared_ptr<Track> tr;
5139 if ((tr = tatv->track()) == 0) {
5144 if ((pl = (tr->playlist())) != 0) {
5145 if (src_comparison) {
5146 pl->get_source_equivalent_regions (region, results);
5148 pl->get_region_list_equivalent_regions (region, results);
5152 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5153 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5154 regions.push_back (marv);
5163 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5165 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5166 RouteTimeAxisView* tatv;
5167 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5168 if (!tatv->track()) {
5171 RegionView* marv = tatv->view()->find_view (region);
5181 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5183 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5184 RouteTimeAxisView* rtav;
5185 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5186 if (rtav->route() == route) {
5195 Editor::show_rhythm_ferret ()
5197 if (rhythm_ferret == 0) {
5198 rhythm_ferret = new RhythmFerret(*this);
5201 rhythm_ferret->set_session (_session);
5202 rhythm_ferret->show ();
5203 rhythm_ferret->present ();
5207 Editor::first_idle ()
5209 MessageDialog* dialog = 0;
5211 if (track_views.size() > 1) {
5212 Timers::TimerSuspender t;
5213 dialog = new MessageDialog (
5214 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5218 ARDOUR_UI::instance()->flush_pending (60);
5221 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5225 /* now that all regionviews should exist, setup region selection */
5229 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5230 /* this is cumulative: rs is NOT cleared each time */
5231 get_regionviews_by_id (*pr, rs);
5234 selection->set (rs);
5236 /* first idle adds route children (automation tracks), so we need to redisplay here */
5237 _routes->redisplay ();
5241 if (_session->undo_depth() == 0) {
5242 undo_action->set_sensitive(false);
5244 redo_action->set_sensitive(false);
5245 begin_selection_op_history ();
5251 Editor::_idle_resize (gpointer arg)
5253 return ((Editor*)arg)->idle_resize ();
5257 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5259 if (resize_idle_id < 0) {
5260 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5261 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5262 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5264 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5265 _pending_resize_amount = 0;
5268 /* make a note of the smallest resulting height, so that we can clamp the
5269 lower limit at TimeAxisView::hSmall */
5271 int32_t min_resulting = INT32_MAX;
5273 _pending_resize_amount += h;
5274 _pending_resize_view = view;
5276 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5278 if (selection->tracks.contains (_pending_resize_view)) {
5279 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5280 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5284 if (min_resulting < 0) {
5289 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5290 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5294 /** Handle pending resizing of tracks */
5296 Editor::idle_resize ()
5298 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5300 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5301 selection->tracks.contains (_pending_resize_view)) {
5303 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5304 if (*i != _pending_resize_view) {
5305 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5310 _pending_resize_amount = 0;
5311 _group_tabs->set_dirty ();
5312 resize_idle_id = -1;
5320 ENSURE_GUI_THREAD (*this, &Editor::located);
5323 playhead_cursor->set_position (_session->audible_sample ());
5324 if (_follow_playhead && !_pending_initial_locate) {
5325 reset_x_origin_to_follow_playhead ();
5329 _pending_locate_request = false;
5330 _pending_initial_locate = false;
5331 _last_update_time = 0;
5335 Editor::region_view_added (RegionView * rv)
5337 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5339 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5340 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5341 if (rv->region()->id () == (*rnote).first) {
5342 mrv->select_notes ((*rnote).second);
5343 selection->pending_midi_note_selection.erase(rnote);
5349 _summary->set_background_dirty ();
5351 mark_region_boundary_cache_dirty ();
5355 Editor::region_view_removed ()
5357 _summary->set_background_dirty ();
5359 mark_region_boundary_cache_dirty ();
5363 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5365 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5366 if ((*j)->stripable() == s) {
5375 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5377 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5378 if ((*j)->control() == c) {
5382 TimeAxisView::Children kids = (*j)->get_child_list ();
5384 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5385 if ((*k)->control() == c) {
5395 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5399 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5400 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5410 Editor::suspend_route_redisplay ()
5413 _routes->suspend_redisplay();
5418 Editor::resume_route_redisplay ()
5421 _routes->redisplay(); // queue redisplay
5422 _routes->resume_redisplay();
5427 Editor::add_vcas (VCAList& vlist)
5431 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5432 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5435 add_stripables (sl);
5439 Editor::add_routes (RouteList& rlist)
5443 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5447 add_stripables (sl);
5451 Editor::add_stripables (StripableList& sl)
5453 list<TimeAxisView*> new_views;
5454 boost::shared_ptr<VCA> v;
5455 boost::shared_ptr<Route> r;
5456 TrackViewList new_selection;
5457 bool from_scratch = (track_views.size() == 0);
5459 sl.sort (Stripable::Sorter());
5461 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5463 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5465 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5467 new_views.push_back (vtv);
5469 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5471 if (r->is_auditioner() || r->is_monitor()) {
5475 RouteTimeAxisView* rtv;
5476 DataType dt = r->input()->default_type();
5478 if (dt == ARDOUR::DataType::AUDIO) {
5479 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5481 } else if (dt == ARDOUR::DataType::MIDI) {
5482 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5485 throw unknown_type();
5488 new_views.push_back (rtv);
5489 track_views.push_back (rtv);
5490 new_selection.push_back (rtv);
5492 rtv->effective_gain_display ();
5494 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5495 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5499 if (new_views.size() > 0) {
5500 _routes->time_axis_views_added (new_views);
5501 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5504 /* note: !new_selection.empty() means that we got some routes rather
5508 if (!from_scratch && !new_selection.empty()) {
5509 selection->set (new_selection);
5510 begin_selection_op_history();
5513 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5514 show_editor_mixer (true);
5517 editor_list_button.set_sensitive (true);
5521 Editor::timeaxisview_deleted (TimeAxisView *tv)
5523 if (tv == entered_track) {
5527 if (_session && _session->deletion_in_progress()) {
5528 /* the situation is under control */
5532 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5534 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5536 _routes->route_removed (tv);
5538 TimeAxisView::Children c = tv->get_child_list ();
5539 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5540 if (entered_track == i->get()) {
5545 /* remove it from the list of track views */
5547 TrackViewList::iterator i;
5549 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5550 i = track_views.erase (i);
5553 /* update whatever the current mixer strip is displaying, if revelant */
5555 boost::shared_ptr<Route> route;
5558 route = rtav->route ();
5561 if (current_mixer_strip && current_mixer_strip->route() == route) {
5563 TimeAxisView* next_tv;
5565 if (track_views.empty()) {
5567 } else if (i == track_views.end()) {
5568 next_tv = track_views.front();
5573 // skip VCAs (cannot be selected, n/a in editor-mixer)
5574 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5575 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5576 next_tv = track_views.front();
5578 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5579 /* just in case: no master, only a VCA remains */
5585 set_selected_mixer_strip (*next_tv);
5587 /* make the editor mixer strip go away setting the
5588 * button to inactive (which also unticks the menu option)
5591 ActionManager::uncheck_toggleaction ("Editor/show-editor-mixer");
5597 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5603 DisplaySuspender ds;
5604 PresentationInfo::ChangeSuspender cs;
5606 if (apply_to_selection) {
5607 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5609 TrackSelection::iterator j = i;
5612 hide_track_in_display (*i, false);
5617 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5619 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5620 /* this will hide the mixer strip */
5621 set_selected_mixer_strip (*tv);
5624 _routes->hide_track_in_display (*tv);
5629 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5634 _routes->show_track_in_display (*tv);
5635 if (move_into_view) {
5636 ensure_time_axis_view_is_visible (*tv, false);
5641 Editor::sync_track_view_list_and_routes ()
5643 track_views = TrackViewList (_routes->views ());
5645 _summary->set_background_dirty();
5646 _group_tabs->set_dirty ();
5648 return false; // do not call again (until needed)
5652 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5654 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5659 /** Find a StripableTimeAxisView by the ID of its stripable */
5660 StripableTimeAxisView*
5661 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5663 StripableTimeAxisView* v;
5665 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5666 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5667 if(v->stripable()->id() == id) {
5677 Editor::fit_route_group (RouteGroup *g)
5679 TrackViewList ts = axis_views_from_routes (g->route_list ());
5684 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5686 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5689 _session->cancel_audition ();
5693 if (_session->is_auditioning()) {
5694 _session->cancel_audition ();
5695 if (r == last_audition_region) {
5700 _session->audition_region (r);
5701 last_audition_region = r;
5706 Editor::hide_a_region (boost::shared_ptr<Region> r)
5708 r->set_hidden (true);
5712 Editor::show_a_region (boost::shared_ptr<Region> r)
5714 r->set_hidden (false);
5718 Editor::audition_region_from_region_list ()
5720 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5724 Editor::step_edit_status_change (bool yn)
5727 start_step_editing ();
5729 stop_step_editing ();
5734 Editor::start_step_editing ()
5736 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5740 Editor::stop_step_editing ()
5742 step_edit_connection.disconnect ();
5746 Editor::check_step_edit ()
5748 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5749 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5751 mtv->check_step_edit ();
5755 return true; // do it again, till we stop
5759 Editor::scroll_press (Direction dir)
5761 ++_scroll_callbacks;
5763 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5764 /* delay the first auto-repeat */
5770 scroll_backward (1);
5778 scroll_up_one_track ();
5782 scroll_down_one_track ();
5786 /* do hacky auto-repeat */
5787 if (!_scroll_connection.connected ()) {
5789 _scroll_connection = Glib::signal_timeout().connect (
5790 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5793 _scroll_callbacks = 0;
5800 Editor::scroll_release ()
5802 _scroll_connection.disconnect ();
5805 /** Queue a change for the Editor viewport x origin to follow the playhead */
5807 Editor::reset_x_origin_to_follow_playhead ()
5809 samplepos_t const sample = playhead_cursor->current_sample ();
5811 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5813 if (_session->transport_speed() < 0) {
5815 if (sample > (current_page_samples() / 2)) {
5816 center_screen (sample-(current_page_samples()/2));
5818 center_screen (current_page_samples()/2);
5825 if (sample < _leftmost_sample) {
5827 if (_session->transport_rolling()) {
5828 /* rolling; end up with the playhead at the right of the page */
5829 l = sample - current_page_samples ();
5831 /* not rolling: end up with the playhead 1/4 of the way along the page */
5832 l = sample - current_page_samples() / 4;
5836 if (_session->transport_rolling()) {
5837 /* rolling: end up with the playhead on the left of the page */
5840 /* not rolling: end up with the playhead 3/4 of the way along the page */
5841 l = sample - 3 * current_page_samples() / 4;
5849 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5855 Editor::super_rapid_screen_update ()
5857 if (!_session || !_session->engine().running()) {
5861 /* METERING / MIXER STRIPS */
5863 /* update track meters, if required */
5864 if (contents().is_mapped() && meters_running) {
5865 RouteTimeAxisView* rtv;
5866 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5867 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5868 rtv->fast_update ();
5873 /* and any current mixer strip */
5874 if (current_mixer_strip) {
5875 current_mixer_strip->fast_update ();
5878 bool latent_locate = false;
5879 samplepos_t sample = _session->audible_sample (&latent_locate);
5880 const int64_t now = g_get_monotonic_time ();
5883 if (_session->exporting ()) {
5884 /* freewheel/export may be faster or slower than transport_speed() / SR.
5885 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5887 _last_update_time = 0;
5890 if (!_session->transport_rolling () || _session->is_auditioning ()) {
5891 /* Do not interpolate the playhead position; just set it */
5892 _last_update_time = 0;
5895 if (_last_update_time > 0) {
5896 /* interpolate and smoothen playhead position */
5897 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5898 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5899 err = sample - guess;
5901 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5902 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5905 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5907 err, _err_screen_engine);
5912 _err_screen_engine = 0;
5915 if (err > 8192 || latent_locate) {
5916 // in case of x-runs or freewheeling
5917 _last_update_time = 0;
5918 sample = _session->audible_sample ();
5920 _last_update_time = now;
5923 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5925 MusicSample where (sample, 0);
5926 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5927 snapped_cursor->hide ();
5928 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5929 /* EditAtPlayhead does not snap */
5930 } else if (_edit_point == EditAtSelectedMarker) {
5931 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5932 * however, the current editing code -does- snap so I'll draw it that way for now.
5934 if (!selection->markers.empty()) {
5935 MusicSample ms (selection->markers.front()->position(), 0);
5936 snap_to (ms); // should use snap_to_with_modifier?
5937 snapped_cursor->set_position (ms.sample);
5938 snapped_cursor->show ();
5940 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5941 snapped_cursor->show ();
5942 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5943 snapped_cursor->hide ();
5946 /* There are a few reasons why we might not update the playhead / viewport stuff:
5948 * 1. we don't update things when there's a pending locate request, otherwise
5949 * when the editor requests a locate there is a chance that this method
5950 * will move the playhead before the locate request is processed, causing
5952 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5953 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5955 if (_pending_locate_request) {
5956 _last_update_time = 0;
5960 if (_dragging_playhead) {
5961 _last_update_time = 0;
5965 if (playhead_cursor->current_sample () == sample) {
5969 playhead_cursor->set_position (sample);
5971 if (_session->requested_return_sample() >= 0) {
5972 _last_update_time = 0;
5976 if (!_follow_playhead || pending_visual_change.being_handled) {
5977 /* We only do this if we aren't already
5978 * handling a visual change (ie if
5979 * pending_visual_change.being_handled is
5980 * false) so that these requests don't stack
5981 * up there are too many of them to handle in
5987 if (!_stationary_playhead) {
5988 reset_x_origin_to_follow_playhead ();
5990 samplepos_t const sample = playhead_cursor->current_sample ();
5991 double target = ((double)sample - (double)current_page_samples() / 2.0);
5992 if (target <= 0.0) {
5995 /* compare to EditorCursor::set_position() */
5996 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5997 double const new_pos = sample_to_pixel_unrounded (target);
5998 if (rint (new_pos) != rint (old_pos)) {
5999 reset_x_origin (pixel_to_sample (new_pos));
6006 Editor::session_going_away ()
6008 _have_idled = false;
6010 _session_connections.drop_connections ();
6012 super_rapid_screen_update_connection.disconnect ();
6014 selection->clear ();
6015 cut_buffer->clear ();
6017 clicked_regionview = 0;
6018 clicked_axisview = 0;
6019 clicked_routeview = 0;
6020 entered_regionview = 0;
6022 _last_update_time = 0;
6025 playhead_cursor->hide ();
6027 /* rip everything out of the list displays */
6032 _route_groups->clear ();
6034 /* do this first so that deleting a track doesn't reset cms to null
6035 and thus cause a leak.
6038 if (current_mixer_strip) {
6039 if (current_mixer_strip->get_parent() != 0) {
6040 global_hpacker.remove (*current_mixer_strip);
6042 delete current_mixer_strip;
6043 current_mixer_strip = 0;
6046 /* delete all trackviews */
6048 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6051 track_views.clear ();
6053 nudge_clock->set_session (0);
6055 editor_list_button.set_active(false);
6056 editor_list_button.set_sensitive(false);
6058 /* clear tempo/meter rulers */
6059 remove_metric_marks ();
6060 clear_marker_display ();
6066 stop_step_editing ();
6070 /* get rid of any existing editor mixer strip */
6072 WindowTitle title(Glib::get_application_name());
6073 title += _("Editor");
6075 own_window()->set_title (title.get_string());
6078 SessionHandlePtr::session_going_away ();
6082 Editor::trigger_script (int i)
6084 LuaInstance::instance()-> call_action (i);
6088 Editor::show_editor_list (bool yn)
6091 _editor_list_vbox.show ();
6093 _editor_list_vbox.hide ();
6098 Editor::change_region_layering_order (bool from_context_menu)
6100 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
6102 if (!clicked_routeview) {
6103 if (layering_order_editor) {
6104 layering_order_editor->hide ();
6109 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
6115 boost::shared_ptr<Playlist> pl = track->playlist();
6121 if (layering_order_editor == 0) {
6122 layering_order_editor = new RegionLayeringOrderEditor (*this);
6125 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
6126 layering_order_editor->maybe_present ();
6130 Editor::update_region_layering_order_editor ()
6132 if (layering_order_editor && layering_order_editor->is_visible ()) {
6133 change_region_layering_order (true);
6138 Editor::setup_fade_images ()
6140 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6141 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6142 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6143 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6144 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6146 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6147 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6148 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6149 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6150 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6154 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6156 Editor::action_menu_item (std::string const & name)
6158 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6161 return *manage (a->create_menu_item ());
6165 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6167 EventBox* b = manage (new EventBox);
6168 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6169 Label* l = manage (new Label (name));
6173 _the_notebook.append_page (widget, *b);
6177 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6179 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6180 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6183 if (ev->type == GDK_2BUTTON_PRESS) {
6185 /* double-click on a notebook tab shrinks or expands the notebook */
6187 if (_notebook_shrunk) {
6188 if (pre_notebook_shrink_pane_width) {
6189 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6191 _notebook_shrunk = false;
6193 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6195 /* this expands the LHS of the edit pane to cover the notebook
6196 PAGE but leaves the tabs visible.
6198 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6199 _notebook_shrunk = true;
6207 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6209 using namespace Menu_Helpers;
6211 MenuList& items = _control_point_context_menu.items ();
6214 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6215 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6216 if (!can_remove_control_point (item)) {
6217 items.back().set_sensitive (false);
6220 _control_point_context_menu.popup (event->button.button, event->button.time);
6224 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6226 using namespace Menu_Helpers;
6228 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6233 /* We need to get the selection here and pass it to the operations, since
6234 popping up the menu will cause a region leave event which clears
6235 entered_regionview. */
6237 MidiRegionView& mrv = note->region_view();
6238 const RegionSelection rs = get_regions_from_selection_and_entered ();
6239 const uint32_t sel_size = mrv.selection_size ();
6241 MenuList& items = _note_context_menu.items();
6245 items.push_back(MenuElem(_("Delete"),
6246 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6249 items.push_back(MenuElem(_("Edit..."),
6250 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6251 if (sel_size != 1) {
6252 items.back().set_sensitive (false);
6255 items.push_back(MenuElem(_("Transpose..."),
6256 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6259 items.push_back(MenuElem(_("Legatize"),
6260 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6262 items.back().set_sensitive (false);
6265 items.push_back(MenuElem(_("Quantize..."),
6266 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6268 items.push_back(MenuElem(_("Remove Overlap"),
6269 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6271 items.back().set_sensitive (false);
6274 items.push_back(MenuElem(_("Transform..."),
6275 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6277 _note_context_menu.popup (event->button.button, event->button.time);
6281 Editor::zoom_vertical_modifier_released()
6283 _stepping_axis_view = 0;
6287 Editor::ui_parameter_changed (string parameter)
6289 if (parameter == "icon-set") {
6290 while (!_cursor_stack.empty()) {
6291 _cursor_stack.pop_back();
6293 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6294 _cursor_stack.push_back(_cursors->grabber);
6295 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6296 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6298 } else if (parameter == "draggable-playhead") {
6299 if (_verbose_cursor) {
6300 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6302 } else if (parameter == "use-note-bars-for-velocity") {
6303 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6304 _track_canvas->request_redraw (_track_canvas->visible_area());
6305 } else if (parameter == "use-note-color-for-velocity") {
6306 /* handled individually by each MidiRegionView */
6311 Editor::use_own_window (bool and_fill_it)
6313 bool new_window = !own_window();
6315 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6317 if (win && new_window) {
6318 win->set_name ("EditorWindow");
6320 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6322 // win->signal_realize().connect (*this, &Editor::on_realize);
6323 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6324 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6325 win->set_data ("ardour-bindings", bindings);
6330 DisplaySuspender ds;
6331 contents().show_all ();
6333 /* XXX: this is a bit unfortunate; it would probably
6334 be nicer if we could just call show () above rather
6335 than needing the show_all ()
6338 /* re-hide stuff if necessary */
6339 editor_list_button_toggled ();
6340 parameter_changed ("show-summary");
6341 parameter_changed ("show-group-tabs");
6342 parameter_changed ("show-zoom-tools");
6344 /* now reset all audio_time_axis heights, because widgets might need
6350 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6351 tv = (static_cast<TimeAxisView*>(*i));
6352 tv->reset_height ();
6355 if (current_mixer_strip) {
6356 current_mixer_strip->hide_things ();
6357 current_mixer_strip->parameter_changed ("mixer-element-visibility");