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/text.h"
84 #include "widgets/ardour_spacer.h"
85 #include "widgets/eventboxext.h"
86 #include "widgets/tooltips.h"
88 #include "control_protocol/control_protocol.h"
91 #include "analysis_window.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
101 #include "editing_convert.h"
103 #include "editor_cursors.h"
104 #include "editor_drag.h"
105 #include "editor_group_tabs.h"
106 #include "editor_locations.h"
107 #include "editor_regions.h"
108 #include "editor_route_groups.h"
109 #include "editor_routes.h"
110 #include "editor_snapshots.h"
111 #include "editor_summary.h"
112 #include "enums_convert.h"
113 #include "export_report.h"
114 #include "global_port_matrix.h"
115 #include "gui_object.h"
116 #include "gui_thread.h"
117 #include "keyboard.h"
118 #include "luainstance.h"
120 #include "midi_region_view.h"
121 #include "midi_time_axis.h"
122 #include "mixer_strip.h"
123 #include "mixer_ui.h"
124 #include "mouse_cursors.h"
125 #include "note_base.h"
126 #include "playlist_selector.h"
127 #include "public_editor.h"
128 #include "quantize_dialog.h"
129 #include "region_layering_order_editor.h"
130 #include "rgb_macros.h"
131 #include "rhythm_ferret.h"
132 #include "route_sorter.h"
133 #include "selection.h"
134 #include "simple_progress_dialog.h"
136 #include "grid_lines.h"
137 #include "time_axis_view.h"
138 #include "time_info_box.h"
140 #include "ui_config.h"
142 #include "vca_time_axis.h"
143 #include "verbose_cursor.h"
145 #include "pbd/i18n.h"
148 using namespace ARDOUR;
149 using namespace ArdourWidgets;
150 using namespace ARDOUR_UI_UTILS;
153 using namespace Glib;
154 using namespace Gtkmm2ext;
155 using namespace Editing;
157 using PBD::internationalize;
159 using Gtkmm2ext::Keyboard;
161 double Editor::timebar_height = 15.0;
163 static const gchar *_grid_type_strings[] = {
172 N_("1/3 (8th triplet)"), // or "1/12" ?
173 N_("1/6 (16th triplet)"),
174 N_("1/12 (32nd triplet)"),
175 N_("1/24 (64th triplet)"),
176 N_("1/5 (8th quintuplet)"),
177 N_("1/10 (16th quintuplet)"),
178 N_("1/20 (32nd quintuplet)"),
179 N_("1/7 (8th septuplet)"),
180 N_("1/14 (16th septuplet)"),
181 N_("1/28 (32nd septuplet)"),
188 static const gchar *_edit_point_strings[] = {
195 static const gchar *_edit_mode_strings[] = {
203 static const gchar *_zoom_focus_strings[] = {
213 #ifdef USE_RUBBERBAND
214 static const gchar *_rb_opt_strings[] = {
217 N_("Balanced multitimbral mixture"),
218 N_("Unpitched percussion with stable notes"),
219 N_("Crisp monophonic instrumental"),
220 N_("Unpitched solo percussion"),
221 N_("Resample without preserving pitch"),
226 /* Robin says: this should be odd to accomodate cairo drawing offset (width/2 rounds up to pixel boundary) */
228 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
230 #define COMBO_TRIANGLE_WIDTH 11 // as-measured for win/linux.
234 : PublicEditor (global_hpacker)
235 , editor_mixer_strip_width (Wide)
236 , constructed (false)
237 , _playlist_selector (0)
239 , no_save_visual (false)
240 , _leftmost_sample (0)
241 , samples_per_pixel (2048)
242 , zoom_focus (ZoomFocusPlayhead)
243 , mouse_mode (MouseObject)
244 , pre_internal_grid_type (GridTypeBeat)
245 , pre_internal_snap_mode (SnapOff)
246 , internal_grid_type (GridTypeBeat)
247 , internal_snap_mode (SnapOff)
248 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
249 , _notebook_shrunk (false)
250 , location_marker_color (0)
251 , location_range_color (0)
252 , location_loop_color (0)
253 , location_punch_color (0)
254 , location_cd_marker_color (0)
256 , _show_marker_lines (false)
257 , clicked_axisview (0)
258 , clicked_routeview (0)
259 , clicked_regionview (0)
260 , clicked_selection (0)
261 , clicked_control_point (0)
262 , button_release_can_deselect (true)
263 , _mouse_changed_selection (false)
264 , region_edit_menu_split_item (0)
265 , region_edit_menu_split_multichannel_item (0)
266 , track_region_edit_playlist_menu (0)
267 , track_edit_playlist_submenu (0)
268 , track_selection_edit_playlist_submenu (0)
269 , _popup_region_menu_item (0)
271 , _track_canvas_viewport (0)
272 , within_track_canvas (false)
273 , _verbose_cursor (0)
277 , range_marker_group (0)
278 , transport_marker_group (0)
279 , cd_marker_group (0)
280 , _time_markers_group (0)
281 , hv_scroll_group (0)
283 , cursor_scroll_group (0)
284 , no_scroll_group (0)
285 , _trackview_group (0)
286 , _drag_motion_group (0)
287 , _canvas_drop_zone (0)
288 , no_ruler_shown_update (false)
289 , ruler_grabbed_widget (0)
291 , minsec_mark_interval (0)
292 , minsec_mark_modulo (0)
294 , timecode_ruler_scale (timecode_show_many_hours)
295 , timecode_mark_modulo (0)
296 , timecode_nmarks (0)
297 , _samples_ruler_interval (0)
298 , bbt_ruler_scale (bbt_show_many)
301 , bbt_bar_helper_on (0)
302 , bbt_accent_modulo (0)
307 , visible_timebars (0)
308 , editor_ruler_menu (0)
312 , range_marker_bar (0)
313 , transport_marker_bar (0)
315 , minsec_label (_("Mins:Secs"))
316 , bbt_label (_("Bars:Beats"))
317 , timecode_label (_("Timecode"))
318 , samples_label (_("Samples"))
319 , tempo_label (_("Tempo"))
320 , meter_label (_("Meter"))
321 , mark_label (_("Location Markers"))
322 , range_mark_label (_("Range Markers"))
323 , transport_mark_label (_("Loop/Punch Ranges"))
324 , cd_mark_label (_("CD Markers"))
325 , videotl_label (_("Video Timeline"))
328 , playhead_cursor (0)
329 , _region_boundary_cache_dirty (true)
330 , edit_packer (4, 4, true)
331 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
332 , horizontal_adjustment (0.0, 0.0, 1e16)
333 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
334 , controls_layout (unused_adjustment, vertical_adjustment)
335 , _scroll_callbacks (0)
336 , _visible_canvas_width (0)
337 , _visible_canvas_height (0)
338 , _full_canvas_height (0)
339 , edit_controls_left_menu (0)
340 , edit_controls_right_menu (0)
341 , visual_change_queued(false)
342 , _last_update_time (0)
343 , _err_screen_engine (0)
344 , cut_buffer_start (0)
345 , cut_buffer_length (0)
346 , button_bindings (0)
347 , last_paste_pos (-1)
350 , current_interthread_info (0)
351 , analysis_window (0)
352 , select_new_marker (false)
354 , scrubbing_direction (0)
355 , scrub_reversals (0)
356 , scrub_reverse_distance (0)
357 , have_pending_keyboard_selection (false)
358 , pending_keyboard_selection_start (0)
359 , _grid_type (GridTypeBeat)
360 , _snap_mode (SnapOff)
361 , ignore_gui_changes (false)
362 , _drags (new DragManager (this))
364 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
365 , _dragging_playhead (false)
366 , _dragging_edit_point (false)
367 , _follow_playhead (true)
368 , _stationary_playhead (false)
371 , global_rect_group (0)
372 , time_line_group (0)
373 , tempo_marker_menu (0)
374 , meter_marker_menu (0)
376 , range_marker_menu (0)
377 , transport_marker_menu (0)
378 , new_transport_marker_menu (0)
380 , marker_menu_item (0)
381 , bbt_beat_subdivision (4)
382 , _visible_track_count (-1)
383 , toolbar_selection_clock_table (2,3)
384 , automation_mode_button (_("mode"))
385 , selection (new Selection (this, true))
386 , cut_buffer (new Selection (this, false))
387 , _selection_memento (new SelectionMemento())
388 , _all_region_actions_sensitized (false)
389 , _ignore_region_action (false)
390 , _last_region_menu_was_main (false)
391 , _track_selection_change_without_scroll (false)
392 , _editor_track_selection_change_without_scroll (false)
393 , cd_marker_bar_drag_rect (0)
394 , range_bar_drag_rect (0)
395 , transport_bar_drag_rect (0)
396 , transport_bar_range_rect (0)
397 , transport_bar_preroll_rect (0)
398 , transport_bar_postroll_rect (0)
399 , transport_loop_range_rect (0)
400 , transport_punch_range_rect (0)
401 , transport_punchin_line (0)
402 , transport_punchout_line (0)
403 , transport_preroll_rect (0)
404 , transport_postroll_rect (0)
406 , rubberband_rect (0)
412 , autoscroll_horizontal_allowed (false)
413 , autoscroll_vertical_allowed (false)
415 , autoscroll_widget (0)
416 , show_gain_after_trim (false)
417 , selection_op_cmd_depth (0)
418 , selection_op_history_it (0)
419 , no_save_instant (false)
421 , current_mixer_strip (0)
422 , show_editor_mixer_when_tracks_arrive (false)
423 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
424 , current_stepping_trackview (0)
425 , last_track_height_step_timestamp (0)
427 , entered_regionview (0)
428 , clear_entered_track (false)
429 , _edit_point (EditAtMouse)
430 , meters_running (false)
432 , _have_idled (false)
433 , resize_idle_id (-1)
434 , _pending_resize_amount (0)
435 , _pending_resize_view (0)
436 , _pending_locate_request (false)
437 , _pending_initial_locate (false)
441 , layering_order_editor (0)
442 , _last_cut_copy_source_track (0)
443 , _region_selection_change_updates_region_list (true)
445 , _following_mixer_selection (false)
446 , _control_point_toggled_on_press (false)
447 , _stepping_axis_view (0)
448 , quantize_dialog (0)
449 , _main_menu_disabler (0)
450 , myactions (X_("editor"))
452 /* we are a singleton */
454 PublicEditor::_instance = this;
458 last_event_time.tv_sec = 0;
459 last_event_time.tv_usec = 0;
461 selection_op_history.clear();
464 grid_type_strings = I18N (_grid_type_strings);
465 zoom_focus_strings = I18N (_zoom_focus_strings);
466 edit_mode_strings = I18N (_edit_mode_strings);
467 edit_point_strings = I18N (_edit_point_strings);
468 #ifdef USE_RUBBERBAND
469 rb_opt_strings = I18N (_rb_opt_strings);
473 build_edit_mode_menu();
474 build_zoom_focus_menu();
475 build_track_count_menu();
476 build_grid_type_menu();
477 build_edit_point_menu();
479 location_marker_color = UIConfiguration::instance().color ("location marker");
480 location_range_color = UIConfiguration::instance().color ("location range");
481 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
482 location_loop_color = UIConfiguration::instance().color ("location loop");
483 location_punch_color = UIConfiguration::instance().color ("location punch");
485 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
487 TimeAxisView::setup_sizes ();
488 ArdourMarker::setup_sizes (timebar_height);
489 TempoCurve::setup_sizes (timebar_height);
491 bbt_label.set_name ("EditorRulerLabel");
492 bbt_label.set_size_request (-1, (int)timebar_height);
493 bbt_label.set_alignment (1.0, 0.5);
494 bbt_label.set_padding (5,0);
496 bbt_label.set_no_show_all();
497 minsec_label.set_name ("EditorRulerLabel");
498 minsec_label.set_size_request (-1, (int)timebar_height);
499 minsec_label.set_alignment (1.0, 0.5);
500 minsec_label.set_padding (5,0);
501 minsec_label.hide ();
502 minsec_label.set_no_show_all();
503 timecode_label.set_name ("EditorRulerLabel");
504 timecode_label.set_size_request (-1, (int)timebar_height);
505 timecode_label.set_alignment (1.0, 0.5);
506 timecode_label.set_padding (5,0);
507 timecode_label.hide ();
508 timecode_label.set_no_show_all();
509 samples_label.set_name ("EditorRulerLabel");
510 samples_label.set_size_request (-1, (int)timebar_height);
511 samples_label.set_alignment (1.0, 0.5);
512 samples_label.set_padding (5,0);
513 samples_label.hide ();
514 samples_label.set_no_show_all();
516 tempo_label.set_name ("EditorRulerLabel");
517 tempo_label.set_size_request (-1, (int)timebar_height);
518 tempo_label.set_alignment (1.0, 0.5);
519 tempo_label.set_padding (5,0);
521 tempo_label.set_no_show_all();
523 meter_label.set_name ("EditorRulerLabel");
524 meter_label.set_size_request (-1, (int)timebar_height);
525 meter_label.set_alignment (1.0, 0.5);
526 meter_label.set_padding (5,0);
528 meter_label.set_no_show_all();
530 if (Profile->get_trx()) {
531 mark_label.set_text (_("Markers"));
533 mark_label.set_name ("EditorRulerLabel");
534 mark_label.set_size_request (-1, (int)timebar_height);
535 mark_label.set_alignment (1.0, 0.5);
536 mark_label.set_padding (5,0);
538 mark_label.set_no_show_all();
540 cd_mark_label.set_name ("EditorRulerLabel");
541 cd_mark_label.set_size_request (-1, (int)timebar_height);
542 cd_mark_label.set_alignment (1.0, 0.5);
543 cd_mark_label.set_padding (5,0);
544 cd_mark_label.hide();
545 cd_mark_label.set_no_show_all();
547 videotl_bar_height = 4;
548 videotl_label.set_name ("EditorRulerLabel");
549 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
550 videotl_label.set_alignment (1.0, 0.5);
551 videotl_label.set_padding (5,0);
552 videotl_label.hide();
553 videotl_label.set_no_show_all();
555 range_mark_label.set_name ("EditorRulerLabel");
556 range_mark_label.set_size_request (-1, (int)timebar_height);
557 range_mark_label.set_alignment (1.0, 0.5);
558 range_mark_label.set_padding (5,0);
559 range_mark_label.hide();
560 range_mark_label.set_no_show_all();
562 transport_mark_label.set_name ("EditorRulerLabel");
563 transport_mark_label.set_size_request (-1, (int)timebar_height);
564 transport_mark_label.set_alignment (1.0, 0.5);
565 transport_mark_label.set_padding (5,0);
566 transport_mark_label.hide();
567 transport_mark_label.set_no_show_all();
569 initialize_canvas ();
571 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
573 _summary = new EditorSummary (this);
575 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
576 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
578 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
580 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
581 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
583 edit_controls_vbox.set_spacing (0);
584 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
585 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
587 HBox* h = manage (new HBox);
588 _group_tabs = new EditorGroupTabs (this);
589 if (!ARDOUR::Profile->get_trx()) {
590 h->pack_start (*_group_tabs, PACK_SHRINK);
592 h->pack_start (edit_controls_vbox);
593 controls_layout.add (*h);
595 controls_layout.set_name ("EditControlsBase");
596 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
597 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
598 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
600 _cursors = new MouseCursors;
601 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
602 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
604 /* Push default cursor to ever-present bottom of cursor stack. */
605 push_canvas_cursor(_cursors->grabber);
607 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
609 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
610 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
611 pad_line_1->set_outline_color (0xFF0000FF);
617 edit_packer.set_col_spacings (0);
618 edit_packer.set_row_spacings (0);
619 edit_packer.set_homogeneous (false);
620 edit_packer.set_border_width (0);
621 edit_packer.set_name ("EditorWindow");
623 time_bars_event_box.add (time_bars_vbox);
624 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
625 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
627 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
628 axis_view_shadow->set_size_request (4, -1);
629 axis_view_shadow->set_name("EditorWindow");
630 axis_view_shadow->show();
632 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
634 /* labels for the time bars */
635 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
637 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
639 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
641 bottom_hbox.set_border_width (2);
642 bottom_hbox.set_spacing (3);
644 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
646 _route_groups = new EditorRouteGroups (this);
647 _routes = new EditorRoutes (this);
648 _regions = new EditorRegions (this);
649 _snapshots = new EditorSnapshots (this);
650 _locations = new EditorLocations (this);
651 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
653 /* these are static location signals */
655 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
657 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
659 add_notebook_page (_("Regions"), _regions->widget ());
660 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
661 add_notebook_page (_("Snapshots"), _snapshots->widget ());
662 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
663 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
665 _the_notebook.set_show_tabs (true);
666 _the_notebook.set_scrollable (true);
667 _the_notebook.popup_disable ();
668 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
669 _the_notebook.show_all ();
671 _notebook_shrunk = false;
674 /* Pick up some settings we need to cache, early */
676 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
679 settings->get_property ("notebook-shrunk", _notebook_shrunk);
682 editor_summary_pane.set_check_divider_position (true);
683 editor_summary_pane.add (edit_packer);
685 Button* summary_arrow_left = manage (new Button);
686 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
687 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
688 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 Button* summary_arrow_right = manage (new Button);
691 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
692 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
693 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
695 VBox* summary_arrows_left = manage (new VBox);
696 summary_arrows_left->pack_start (*summary_arrow_left);
698 VBox* summary_arrows_right = manage (new VBox);
699 summary_arrows_right->pack_start (*summary_arrow_right);
701 Frame* summary_sample = manage (new Frame);
702 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
704 summary_sample->add (*_summary);
705 summary_sample->show ();
707 _summary_hbox.pack_start (*summary_arrows_left, false, false);
708 _summary_hbox.pack_start (*summary_sample, true, true);
709 _summary_hbox.pack_start (*summary_arrows_right, false, false);
711 if (!ARDOUR::Profile->get_trx()) {
712 editor_summary_pane.add (_summary_hbox);
715 edit_pane.set_check_divider_position (true);
716 edit_pane.add (editor_summary_pane);
717 if (!ARDOUR::Profile->get_trx()) {
718 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
719 _editor_list_vbox.pack_start (_the_notebook);
720 edit_pane.add (_editor_list_vbox);
721 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
724 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
725 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
728 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
729 /* initial allocation is 90% to canvas, 10% to notebook */
732 edit_pane.set_divider (0, fract);
734 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
735 /* initial allocation is 90% to canvas, 10% to summary */
738 editor_summary_pane.set_divider (0, fract);
740 global_vpacker.set_spacing (0);
741 global_vpacker.set_border_width (0);
743 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
745 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
746 ebox->set_name("EditorWindow");
747 ebox->add (ebox_hpacker);
749 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
750 epane_box->set_name("EditorWindow");
751 epane_box->add (edit_pane);
753 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
754 epane_box2->set_name("EditorWindow");
755 epane_box2->add (global_vpacker);
757 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
758 toolbar_shadow->set_size_request (-1, 4);
759 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
760 toolbar_shadow->set_name("EditorWindow");
761 toolbar_shadow->show();
763 global_vpacker.pack_start (*toolbar_shadow, false, false);
764 global_vpacker.pack_start (*ebox, false, false);
765 global_vpacker.pack_start (*epane_box, true, true);
766 global_hpacker.pack_start (*epane_box2, true, true);
768 /* need to show the "contents" widget so that notebook will show if tab is switched to
771 global_hpacker.show ();
775 /* register actions now so that set_state() can find them and set toggles/checks etc */
782 _playlist_selector = new PlaylistSelector();
783 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
785 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
789 nudge_forward_button.set_name ("nudge button");
790 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
792 nudge_backward_button.set_name ("nudge button");
793 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
795 fade_context_menu.set_name ("ArdourContextMenu");
797 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
799 /* allow external control surfaces/protocols to do various things */
801 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
802 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
803 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
804 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
805 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
806 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
807 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
808 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
809 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
810 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
811 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
812 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
813 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
814 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
816 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
817 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
818 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
819 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
820 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
822 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
826 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
828 /* problematic: has to return a value and thus cannot be x-thread */
830 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
832 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
833 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
835 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
837 _ignore_region_action = false;
838 _last_region_menu_was_main = false;
839 _popup_region_menu_item = 0;
841 _show_marker_lines = false;
843 /* Button bindings */
845 button_bindings = new Bindings ("editor-mouse");
847 XMLNode* node = button_settings();
849 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
850 button_bindings->load_operation (**i);
856 /* grab current parameter state */
857 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
858 UIConfiguration::instance().map_parameters (pc);
860 setup_fade_images ();
862 set_grid_to (GridTypeNone);
869 delete button_bindings;
871 delete _route_groups;
872 delete _track_canvas_viewport;
875 delete _verbose_cursor;
876 delete quantize_dialog;
882 delete _playlist_selector;
883 delete _time_info_box;
888 LuaInstance::destroy_instance ();
890 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
893 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
896 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
902 Editor::button_settings () const
904 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
905 XMLNode* node = find_named_node (*settings, X_("Buttons"));
908 node = new XMLNode (X_("Buttons"));
915 Editor::get_smart_mode () const
917 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
921 Editor::catch_vanishing_regionview (RegionView *rv)
923 /* note: the selection will take care of the vanishing
924 audioregionview by itself.
927 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
931 if (clicked_regionview == rv) {
932 clicked_regionview = 0;
935 if (entered_regionview == rv) {
936 set_entered_regionview (0);
939 if (!_all_region_actions_sensitized) {
940 sensitize_all_region_actions (true);
945 Editor::set_entered_regionview (RegionView* rv)
947 if (rv == entered_regionview) {
951 if (entered_regionview) {
952 entered_regionview->exited ();
955 entered_regionview = rv;
957 if (entered_regionview != 0) {
958 entered_regionview->entered ();
961 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
962 /* This RegionView entry might have changed what region actions
963 are allowed, so sensitize them all in case a key is pressed.
965 sensitize_all_region_actions (true);
970 Editor::set_entered_track (TimeAxisView* tav)
973 entered_track->exited ();
979 entered_track->entered ();
984 Editor::instant_save ()
986 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
991 _session->add_instant_xml(get_state());
993 Config->add_instant_xml(get_state());
998 Editor::control_vertical_zoom_in_all ()
1000 tav_zoom_smooth (false, true);
1004 Editor::control_vertical_zoom_out_all ()
1006 tav_zoom_smooth (true, true);
1010 Editor::control_vertical_zoom_in_selected ()
1012 tav_zoom_smooth (false, false);
1016 Editor::control_vertical_zoom_out_selected ()
1018 tav_zoom_smooth (true, false);
1022 Editor::control_view (uint32_t view)
1024 goto_visual_state (view);
1028 Editor::control_unselect ()
1030 selection->clear_tracks ();
1034 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1036 TimeAxisView* tav = time_axis_view_from_stripable (s);
1040 case Selection::Add:
1041 selection->add (tav);
1043 case Selection::Toggle:
1044 selection->toggle (tav);
1046 case Selection::Extend:
1048 case Selection::Set:
1049 selection->set (tav);
1053 selection->clear_tracks ();
1058 Editor::control_step_tracks_up ()
1060 scroll_tracks_up_line ();
1064 Editor::control_step_tracks_down ()
1066 scroll_tracks_down_line ();
1070 Editor::control_scroll (float fraction)
1072 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1078 double step = fraction * current_page_samples();
1081 _control_scroll_target is an optional<T>
1083 it acts like a pointer to an samplepos_t, with
1084 a operator conversion to boolean to check
1085 that it has a value could possibly use
1086 playhead_cursor->current_sample to store the
1087 value and a boolean in the class to know
1088 when it's out of date
1091 if (!_control_scroll_target) {
1092 _control_scroll_target = _session->transport_sample();
1093 _dragging_playhead = true;
1096 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1097 *_control_scroll_target = 0;
1098 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1099 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1101 *_control_scroll_target += (samplepos_t) trunc (step);
1104 /* move visuals, we'll catch up with it later */
1106 playhead_cursor->set_position (*_control_scroll_target);
1107 UpdateAllTransportClocks (*_control_scroll_target);
1109 if (*_control_scroll_target > (current_page_samples() / 2)) {
1110 /* try to center PH in window */
1111 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1117 Now we do a timeout to actually bring the session to the right place
1118 according to the playhead. This is to avoid reading disk buffers on every
1119 call to control_scroll, which is driven by ScrollTimeline and therefore
1120 probably by a control surface wheel which can generate lots of events.
1122 /* cancel the existing timeout */
1124 control_scroll_connection.disconnect ();
1126 /* add the next timeout */
1128 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1132 Editor::deferred_control_scroll (samplepos_t /*target*/)
1134 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1135 /* reset for next stream */
1136 _control_scroll_target = boost::none;
1137 _dragging_playhead = false;
1142 Editor::access_action (const std::string& action_group, const std::string& action_item)
1148 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1151 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
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 _snapshots->set_session (_session);
1341 _routes->set_session (_session);
1342 _locations->set_session (_session);
1343 _time_info_box->set_session (_session);
1345 if (rhythm_ferret) {
1346 rhythm_ferret->set_session (_session);
1349 if (analysis_window) {
1350 analysis_window->set_session (_session);
1354 sfbrowser->set_session (_session);
1357 compute_fixed_ruler_scale ();
1359 /* Make sure we have auto loop and auto punch ranges */
1361 Location* loc = _session->locations()->auto_loop_location();
1363 loc->set_name (_("Loop"));
1366 loc = _session->locations()->auto_punch_location();
1369 loc->set_name (_("Punch"));
1372 refresh_location_display ();
1374 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1375 * the selected Marker; this needs the LocationMarker list to be available.
1377 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1378 set_state (*node, Stateful::loading_state_version);
1380 /* catch up on selection state, etc. */
1383 sc.add (Properties::selected);
1384 presentation_info_changed (sc);
1386 /* catch up with the playhead */
1388 _session->request_locate (playhead_cursor->current_sample ());
1389 _pending_initial_locate = true;
1393 /* These signals can all be emitted by a non-GUI thread. Therefore the
1394 handlers for them must not attempt to directly interact with the GUI,
1395 but use PBD::Signal<T>::connect() which accepts an event loop
1396 ("context") where the handler will be asked to run.
1399 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1400 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1401 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1402 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1403 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1404 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1405 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1406 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1407 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1408 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1409 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1410 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1411 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1412 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1413 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1414 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1416 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1417 playhead_cursor->show ();
1419 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1420 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1421 snapped_cursor->show ();
1423 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1424 Config->map_parameters (pc);
1425 _session->config.map_parameters (pc);
1427 restore_ruler_visibility ();
1428 //tempo_map_changed (PropertyChange (0));
1429 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1431 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1432 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1435 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1436 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1439 /* register for undo history */
1440 _session->register_with_memento_command_factory(id(), this);
1441 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1443 LuaInstance::instance()->set_session(_session);
1445 start_updating_meters ();
1449 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1451 using namespace Menu_Helpers;
1453 void (Editor::*emf)(FadeShape);
1454 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1457 images = &_xfade_in_images;
1458 emf = &Editor::set_fade_in_shape;
1460 images = &_xfade_out_images;
1461 emf = &Editor::set_fade_out_shape;
1466 _("Linear (for highly correlated material)"),
1467 *(*images)[FadeLinear],
1468 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1476 _("Constant power"),
1477 *(*images)[FadeConstantPower],
1478 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 *(*images)[FadeSymmetric],
1487 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1496 *(*images)[FadeSlow],
1497 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1500 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 *(*images)[FadeFast],
1506 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1509 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 /** Pop up a context menu for when the user clicks on a start crossfade */
1514 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1516 using namespace Menu_Helpers;
1517 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1522 MenuList& items (xfade_in_context_menu.items());
1525 if (arv->audio_region()->fade_in_active()) {
1526 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1528 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1531 items.push_back (SeparatorElem());
1532 fill_xfade_menu (items, true);
1534 xfade_in_context_menu.popup (button, time);
1537 /** Pop up a context menu for when the user clicks on an end crossfade */
1539 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1541 using namespace Menu_Helpers;
1542 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1547 MenuList& items (xfade_out_context_menu.items());
1550 if (arv->audio_region()->fade_out_active()) {
1551 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1553 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1556 items.push_back (SeparatorElem());
1557 fill_xfade_menu (items, false);
1559 xfade_out_context_menu.popup (button, time);
1563 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1565 using namespace Menu_Helpers;
1566 Menu* (Editor::*build_menu_function)();
1569 switch (item_type) {
1571 case RegionViewName:
1572 case RegionViewNameHighlight:
1573 case LeftFrameHandle:
1574 case RightFrameHandle:
1575 if (with_selection) {
1576 build_menu_function = &Editor::build_track_selection_context_menu;
1578 build_menu_function = &Editor::build_track_region_context_menu;
1583 if (with_selection) {
1584 build_menu_function = &Editor::build_track_selection_context_menu;
1586 build_menu_function = &Editor::build_track_context_menu;
1591 if (clicked_routeview->track()) {
1592 build_menu_function = &Editor::build_track_context_menu;
1594 build_menu_function = &Editor::build_track_bus_context_menu;
1599 /* probably shouldn't happen but if it does, we don't care */
1603 menu = (this->*build_menu_function)();
1604 menu->set_name ("ArdourContextMenu");
1606 /* now handle specific situations */
1608 switch (item_type) {
1610 case RegionViewName:
1611 case RegionViewNameHighlight:
1612 case LeftFrameHandle:
1613 case RightFrameHandle:
1614 if (!with_selection) {
1615 if (region_edit_menu_split_item) {
1616 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1617 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1619 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1622 if (region_edit_menu_split_multichannel_item) {
1623 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1624 region_edit_menu_split_multichannel_item->set_sensitive (true);
1626 region_edit_menu_split_multichannel_item->set_sensitive (false);
1639 /* probably shouldn't happen but if it does, we don't care */
1643 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1645 /* Bounce to disk */
1647 using namespace Menu_Helpers;
1648 MenuList& edit_items = menu->items();
1650 edit_items.push_back (SeparatorElem());
1652 switch (clicked_routeview->audio_track()->freeze_state()) {
1653 case AudioTrack::NoFreeze:
1654 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1657 case AudioTrack::Frozen:
1658 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1661 case AudioTrack::UnFrozen:
1662 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1668 if (item_type == StreamItem && clicked_routeview) {
1669 clicked_routeview->build_underlay_menu(menu);
1672 /* When the region menu is opened, we setup the actions so that they look right
1675 sensitize_the_right_region_actions (false);
1676 _last_region_menu_was_main = false;
1678 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1679 menu->popup (button, time);
1683 Editor::build_track_context_menu ()
1685 using namespace Menu_Helpers;
1687 MenuList& edit_items = track_context_menu.items();
1690 add_dstream_context_items (edit_items);
1691 return &track_context_menu;
1695 Editor::build_track_bus_context_menu ()
1697 using namespace Menu_Helpers;
1699 MenuList& edit_items = track_context_menu.items();
1702 add_bus_context_items (edit_items);
1703 return &track_context_menu;
1707 Editor::build_track_region_context_menu ()
1709 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_region_context_menu.items();
1713 /* we've just cleared the track region context menu, so the menu that these
1714 two items were on will have disappeared; stop them dangling.
1716 region_edit_menu_split_item = 0;
1717 region_edit_menu_split_multichannel_item = 0;
1719 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1722 boost::shared_ptr<Track> tr;
1723 boost::shared_ptr<Playlist> pl;
1725 if ((tr = rtv->track())) {
1726 add_region_context_items (edit_items, tr);
1730 add_dstream_context_items (edit_items);
1732 return &track_region_context_menu;
1736 Editor::loudness_analyze_region_selection ()
1741 Selection& s (PublicEditor::instance ().get_selection ());
1742 RegionSelection ars = s.regions;
1743 ARDOUR::AnalysisGraph ag (_session);
1744 samplecnt_t total_work = 0;
1746 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1747 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1751 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1754 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1755 total_work += arv->region ()->length ();
1758 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1760 ag.set_total_samples (total_work);
1761 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1764 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1765 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1769 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1773 ag.analyze_region (ar);
1776 if (!ag.canceled ()) {
1777 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1783 Editor::loudness_analyze_range_selection ()
1788 Selection& s (PublicEditor::instance ().get_selection ());
1789 TimeSelection ts = s.time;
1790 ARDOUR::AnalysisGraph ag (_session);
1791 samplecnt_t total_work = 0;
1793 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1794 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1798 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1802 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1803 total_work += j->length ();
1807 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1809 ag.set_total_samples (total_work);
1810 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1813 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1814 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1818 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1822 ag.analyze_range (rui->route (), pl, ts);
1825 if (!ag.canceled ()) {
1826 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1832 Editor::spectral_analyze_region_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_regionmode();
1844 analysis_window->analyze();
1846 analysis_window->present();
1850 Editor::spectral_analyze_range_selection()
1852 if (analysis_window == 0) {
1853 analysis_window = new AnalysisWindow();
1856 analysis_window->set_session(_session);
1858 analysis_window->show_all();
1861 analysis_window->set_rangemode();
1862 analysis_window->analyze();
1864 analysis_window->present();
1868 Editor::build_track_selection_context_menu ()
1870 using namespace Menu_Helpers;
1871 MenuList& edit_items = track_selection_context_menu.items();
1872 edit_items.clear ();
1874 add_selection_context_items (edit_items);
1875 // edit_items.push_back (SeparatorElem());
1876 // add_dstream_context_items (edit_items);
1878 return &track_selection_context_menu;
1882 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1884 using namespace Menu_Helpers;
1886 /* OK, stick the region submenu at the top of the list, and then add
1890 RegionSelection rs = get_regions_from_selection_and_entered ();
1892 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1894 if (_popup_region_menu_item == 0) {
1895 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1896 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1897 _popup_region_menu_item->show ();
1899 _popup_region_menu_item->set_label (menu_item_name);
1902 /* No layering allowed in later is higher layering model */
1903 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1904 if (act && Config->get_layer_model() == LaterHigher) {
1905 act->set_sensitive (false);
1907 act->set_sensitive (true);
1910 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1912 edit_items.push_back (*_popup_region_menu_item);
1913 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1914 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1916 edit_items.push_back (SeparatorElem());
1919 /** Add context menu items relevant to selection ranges.
1920 * @param edit_items List to add the items to.
1923 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1925 using namespace Menu_Helpers;
1927 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1928 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1930 edit_items.push_back (SeparatorElem());
1931 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1933 edit_items.push_back (SeparatorElem());
1934 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1935 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1937 edit_items.push_back (SeparatorElem());
1939 edit_items.push_back (
1941 _("Move Range Start to Previous Region Boundary"),
1942 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1946 edit_items.push_back (
1948 _("Move Range Start to Next Region Boundary"),
1949 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1953 edit_items.push_back (
1955 _("Move Range End to Previous Region Boundary"),
1956 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1960 edit_items.push_back (
1962 _("Move Range End to Next Region Boundary"),
1963 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1967 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1969 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1971 edit_items.push_back (SeparatorElem());
1972 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1974 edit_items.push_back (SeparatorElem());
1975 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1976 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1977 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1979 edit_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1984 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1986 edit_items.push_back (SeparatorElem());
1987 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1988 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1989 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1990 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1991 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1992 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1993 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1999 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2001 using namespace Menu_Helpers;
2005 Menu *play_menu = manage (new Menu);
2006 MenuList& play_items = play_menu->items();
2007 play_menu->set_name ("ArdourContextMenu");
2009 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2010 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2011 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2012 play_items.push_back (SeparatorElem());
2013 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2015 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2019 Menu *select_menu = manage (new Menu);
2020 MenuList& select_items = select_menu->items();
2021 select_menu->set_name ("ArdourContextMenu");
2023 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2024 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2025 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2026 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2027 select_items.push_back (SeparatorElem());
2028 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2029 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2030 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2031 select_items.push_back (SeparatorElem());
2032 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2033 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2034 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2035 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2036 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2037 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2038 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2040 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2044 Menu *cutnpaste_menu = manage (new Menu);
2045 MenuList& cutnpaste_items = cutnpaste_menu->items();
2046 cutnpaste_menu->set_name ("ArdourContextMenu");
2048 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2049 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2050 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2052 cutnpaste_items.push_back (SeparatorElem());
2054 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2055 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2057 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2059 /* Adding new material */
2061 edit_items.push_back (SeparatorElem());
2062 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2063 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2067 Menu *nudge_menu = manage (new Menu());
2068 MenuList& nudge_items = nudge_menu->items();
2069 nudge_menu->set_name ("ArdourContextMenu");
2071 edit_items.push_back (SeparatorElem());
2072 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2075 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2077 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2081 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2083 using namespace Menu_Helpers;
2087 Menu *play_menu = manage (new Menu);
2088 MenuList& play_items = play_menu->items();
2089 play_menu->set_name ("ArdourContextMenu");
2091 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2092 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2093 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2097 Menu *select_menu = manage (new Menu);
2098 MenuList& select_items = select_menu->items();
2099 select_menu->set_name ("ArdourContextMenu");
2101 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2102 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2103 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2104 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2105 select_items.push_back (SeparatorElem());
2106 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2107 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2108 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2109 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2111 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2115 Menu *cutnpaste_menu = manage (new Menu);
2116 MenuList& cutnpaste_items = cutnpaste_menu->items();
2117 cutnpaste_menu->set_name ("ArdourContextMenu");
2119 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2120 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2121 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2123 Menu *nudge_menu = manage (new Menu());
2124 MenuList& nudge_items = nudge_menu->items();
2125 nudge_menu->set_name ("ArdourContextMenu");
2127 edit_items.push_back (SeparatorElem());
2128 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2129 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2130 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2131 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2133 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2137 Editor::grid_type() const
2143 Editor::grid_musical() const
2145 switch (_grid_type) {
2146 case GridTypeBeatDiv32:
2147 case GridTypeBeatDiv28:
2148 case GridTypeBeatDiv24:
2149 case GridTypeBeatDiv20:
2150 case GridTypeBeatDiv16:
2151 case GridTypeBeatDiv14:
2152 case GridTypeBeatDiv12:
2153 case GridTypeBeatDiv10:
2154 case GridTypeBeatDiv8:
2155 case GridTypeBeatDiv7:
2156 case GridTypeBeatDiv6:
2157 case GridTypeBeatDiv5:
2158 case GridTypeBeatDiv4:
2159 case GridTypeBeatDiv3:
2160 case GridTypeBeatDiv2:
2166 case GridTypeMinSec:
2167 case GridTypeSamples:
2174 Editor::grid_nonmusical() const
2176 switch (_grid_type) {
2178 case GridTypeMinSec:
2179 case GridTypeSamples:
2181 case GridTypeBeatDiv32:
2182 case GridTypeBeatDiv28:
2183 case GridTypeBeatDiv24:
2184 case GridTypeBeatDiv20:
2185 case GridTypeBeatDiv16:
2186 case GridTypeBeatDiv14:
2187 case GridTypeBeatDiv12:
2188 case GridTypeBeatDiv10:
2189 case GridTypeBeatDiv8:
2190 case GridTypeBeatDiv7:
2191 case GridTypeBeatDiv6:
2192 case GridTypeBeatDiv5:
2193 case GridTypeBeatDiv4:
2194 case GridTypeBeatDiv3:
2195 case GridTypeBeatDiv2:
2204 Editor::snap_mode() const
2210 Editor::set_grid_to (GridType gt)
2212 if (_grid_type == gt) { // already set
2216 unsigned int grid_ind = (unsigned int)gt;
2218 if (internal_editing()) {
2219 internal_grid_type = gt;
2221 pre_internal_grid_type = gt;
2226 if (grid_ind > grid_type_strings.size() - 1) {
2228 _grid_type = (GridType)grid_ind;
2231 string str = grid_type_strings[grid_ind];
2233 if (str != grid_type_selector.get_text()) {
2234 grid_type_selector.set_text (str);
2237 /* show appropriate rulers for this grid setting.
2238 * TODO: perhaps make this optional.
2239 * Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines
2241 if (grid_musical()) {
2242 ruler_tempo_action->set_active(true);
2243 ruler_meter_action->set_active(true);
2245 ruler_bbt_action->set_active(true);
2246 ruler_timecode_action->set_active(false);
2247 ruler_minsec_action->set_active(false);
2248 ruler_samples_action->set_active(false);
2249 } else if (_grid_type == GridTypeSmpte) {
2250 ruler_tempo_action->set_active(false);
2251 ruler_meter_action->set_active(false);
2253 ruler_bbt_action->set_active(false);
2254 ruler_timecode_action->set_active(true);
2255 ruler_minsec_action->set_active(false);
2256 ruler_samples_action->set_active(false);
2257 } else if (_grid_type == GridTypeMinSec) {
2258 ruler_tempo_action->set_active(false);
2259 ruler_meter_action->set_active(false);
2261 ruler_bbt_action->set_active(false);
2262 ruler_timecode_action->set_active(false);
2263 ruler_minsec_action->set_active(true);
2264 ruler_samples_action->set_active(false);
2265 } else if (_grid_type == GridTypeSamples) {
2266 ruler_tempo_action->set_active(false);
2267 ruler_meter_action->set_active(false);
2269 ruler_bbt_action->set_active(false);
2270 ruler_timecode_action->set_active(false);
2271 ruler_minsec_action->set_active(false);
2272 ruler_samples_action->set_active(true);
2277 if (grid_musical()) {
2278 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2279 update_tempo_based_rulers ();
2282 mark_region_boundary_cache_dirty ();
2284 redisplay_grid (false);
2286 SnapChanged (); /* EMIT SIGNAL */
2290 Editor::set_snap_mode (SnapMode mode)
2292 if (internal_editing()) {
2293 internal_snap_mode = mode;
2295 pre_internal_snap_mode = mode;
2300 if (_snap_mode == SnapOff) {
2301 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2303 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2310 Editor::set_edit_point_preference (EditPoint ep, bool force)
2312 bool changed = (_edit_point != ep);
2315 if (Profile->get_mixbus())
2316 if (ep == EditAtSelectedMarker)
2317 ep = EditAtPlayhead;
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-marker";
2340 action = "edit-at-mouse";
2344 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2346 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2350 bool in_track_canvas;
2352 if (!mouse_sample (foo, in_track_canvas)) {
2353 in_track_canvas = false;
2356 reset_canvas_action_sensitivity (in_track_canvas);
2357 sensitize_the_right_region_actions (false);
2363 Editor::set_state (const XMLNode& node, int version)
2366 PBD::Unwinder<bool> nsi (no_save_instant, true);
2369 Tabbable::set_state (node, version);
2372 if (_session && node.get_property ("playhead", ph_pos)) {
2374 playhead_cursor->set_position (ph_pos);
2376 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2377 playhead_cursor->set_position (0);
2380 playhead_cursor->set_position (0);
2383 node.get_property ("mixer-width", editor_mixer_strip_width);
2385 node.get_property ("zoom-focus", zoom_focus);
2386 zoom_focus_selection_done (zoom_focus);
2389 if (node.get_property ("zoom", z)) {
2390 /* older versions of ardour used floating point samples_per_pixel */
2391 reset_zoom (llrintf (z));
2393 reset_zoom (samples_per_pixel);
2397 if (node.get_property ("visible-track-count", cnt)) {
2398 set_visible_track_count (cnt);
2402 if (!node.get_property ("grid-type", grid_type)) {
2403 grid_type = _grid_type;
2405 set_grid_to (grid_type);
2408 if (node.get_property ("snap-mode", sm)) {
2409 snap_mode_selection_done(sm);
2410 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2411 * snap_mode_selection_done() will only mark an already active item as active
2412 * which does not trigger set_text().
2416 set_snap_mode (_snap_mode);
2419 node.get_property ("internal-grid-type", internal_grid_type);
2420 node.get_property ("internal-snap-mode", internal_snap_mode);
2421 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2422 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2425 if (node.get_property ("mouse-mode", mm_str)) {
2426 MouseMode m = str2mousemode(mm_str);
2427 set_mouse_mode (m, true);
2429 set_mouse_mode (MouseObject, true);
2433 if (node.get_property ("left-frame", lf_pos)) {
2437 reset_x_origin (lf_pos);
2441 if (node.get_property ("y-origin", y_origin)) {
2442 reset_y_origin (y_origin);
2445 if (node.get_property ("join-object-range", yn)) {
2446 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2448 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2449 tact->set_active (!yn);
2450 tact->set_active (yn);
2452 set_mouse_mode(mouse_mode, true);
2456 if (node.get_property ("edit-point", ep)) {
2457 set_edit_point_preference (ep, true);
2459 set_edit_point_preference (_edit_point);
2462 if (node.get_property ("follow-playhead", yn)) {
2463 set_follow_playhead (yn);
2466 if (node.get_property ("stationary-playhead", yn)) {
2467 set_stationary_playhead (yn);
2470 RegionListSortType sort_type;
2471 if (node.get_property ("region-list-sort-type", sort_type)) {
2472 _regions->reset_sort_type (sort_type, true);
2475 if (node.get_property ("show-editor-mixer", yn)) {
2477 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2480 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2482 /* do it twice to force the change */
2484 tact->set_active (!yn);
2485 tact->set_active (yn);
2488 if (node.get_property ("show-editor-list", yn)) {
2490 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2493 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 /* do it twice to force the change */
2497 tact->set_active (!yn);
2498 tact->set_active (yn);
2502 if (node.get_property (X_("editor-list-page"), el_page)) {
2503 _the_notebook.set_current_page (el_page);
2506 if (node.get_property (X_("show-marker-lines"), yn)) {
2507 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2509 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2511 tact->set_active (!yn);
2512 tact->set_active (yn);
2515 XMLNodeList children = node.children ();
2516 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2517 selection->set_state (**i, Stateful::current_state_version);
2518 _regions->set_state (**i);
2519 _locations->set_state (**i);
2522 if (node.get_property ("maximised", yn)) {
2523 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2525 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2526 bool fs = tact && tact->get_active();
2528 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2532 samplepos_t nudge_clock_value;
2533 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2534 nudge_clock->set (nudge_clock_value);
2536 nudge_clock->set_mode (AudioClock::Timecode);
2537 nudge_clock->set (_session->sample_rate() * 5, true);
2542 * Not all properties may have been in XML, but
2543 * those that are linked to a private variable may need changing
2547 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2548 yn = _follow_playhead;
2550 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2551 if (tact->get_active() != yn) {
2552 tact->set_active (yn);
2556 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2557 yn = _stationary_playhead;
2559 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2560 if (tact->get_active() != yn) {
2561 tact->set_active (yn);
2566 return LuaInstance::instance()->set_state(node);
2570 Editor::get_state ()
2572 XMLNode* node = new XMLNode (X_("Editor"));
2574 node->set_property ("id", id().to_s ());
2576 node->add_child_nocopy (Tabbable::get_state());
2578 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2579 node->set_property("notebook-shrunk", _notebook_shrunk);
2580 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2582 maybe_add_mixer_strip_width (*node);
2584 node->set_property ("zoom-focus", zoom_focus);
2586 node->set_property ("zoom", samples_per_pixel);
2587 node->set_property ("grid-type", _grid_type);
2588 node->set_property ("snap-mode", _snap_mode);
2589 node->set_property ("internal-grid-type", internal_grid_type);
2590 node->set_property ("internal-snap-mode", internal_snap_mode);
2591 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2592 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2593 node->set_property ("edit-point", _edit_point);
2594 node->set_property ("visible-track-count", _visible_track_count);
2596 node->set_property ("playhead", playhead_cursor->current_sample ());
2597 node->set_property ("left-frame", _leftmost_sample);
2598 node->set_property ("y-origin", vertical_adjustment.get_value ());
2600 node->set_property ("maximised", _maximised);
2601 node->set_property ("follow-playhead", _follow_playhead);
2602 node->set_property ("stationary-playhead", _stationary_playhead);
2603 node->set_property ("region-list-sort-type", _regions->sort_type ());
2604 node->set_property ("mouse-mode", mouse_mode);
2605 node->set_property ("join-object-range", smart_mode_action->get_active ());
2607 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2609 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2610 node->set_property (X_("show-editor-mixer"), tact->get_active());
2613 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2615 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2616 node->set_property (X_("show-editor-list"), tact->get_active());
2619 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2621 if (button_bindings) {
2622 XMLNode* bb = new XMLNode (X_("Buttons"));
2623 button_bindings->save (*bb);
2624 node->add_child_nocopy (*bb);
2627 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2629 node->add_child_nocopy (selection->get_state ());
2630 node->add_child_nocopy (_regions->get_state ());
2632 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2634 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2635 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2636 node->add_child_nocopy (_locations->get_state ());
2641 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2642 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2644 * @return pair: TimeAxisView that y is over, layer index.
2646 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2647 * in stacked or expanded region display mode, otherwise 0.
2649 std::pair<TimeAxisView *, double>
2650 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2652 if (!trackview_relative_offset) {
2653 y -= _trackview_group->canvas_origin().y;
2657 return std::make_pair ((TimeAxisView *) 0, 0);
2660 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2662 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2669 return std::make_pair ((TimeAxisView *) 0, 0);
2673 Editor::set_snapped_cursor_position (samplepos_t pos)
2675 if (_edit_point == EditAtMouse) {
2676 snapped_cursor->set_position(pos);
2681 /** Snap a position to the grid, if appropriate, taking into account current
2682 * grid settings and also the state of any snap modifier keys that may be pressed.
2683 * @param start Position to snap.
2684 * @param event Event to get current key modifier information from, or 0.
2687 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
2689 if (!_session || !event) {
2693 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2694 if (_snap_mode == SnapOff) {
2695 snap_to_internal (start, direction, pref, for_mark);
2697 start.set (start.sample, 0);
2700 if (_snap_mode != SnapOff) {
2701 snap_to_internal (start, direction, pref, for_mark);
2702 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2703 /* SnapOff, but we pressed the snap_delta modifier */
2704 snap_to_internal (start, direction, pref, for_mark);
2706 start.set (start.sample, 0);
2712 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2714 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2715 start.set (start.sample, 0);
2719 snap_to_internal (start, direction, pref, for_mark, ensure_snap);
2723 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2725 samplepos_t diff = abs (test - presnap);
2731 test = max_samplepos; // reset this so it doesn't get accidentally reused
2735 Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
2737 if (marks.empty()) return presnap;
2741 samplepos_t test = presnap;
2743 before = after = max_samplepos;
2745 /* get marks to either side of presnap */
2746 vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
2747 while (m != marks.end() && (m->position < presnap)) {
2751 if (m == marks.end ()) {
2752 /* ran out of marks */
2753 before = marks.back().position;
2756 after = m->position;
2758 if (m != marks.begin ()) {
2760 before = m->position;
2763 if (before == max_samplepos && after == max_samplepos) {
2764 /* No grid to snap to, so just don't snap */
2766 } else if (before == max_samplepos) {
2768 } else if (after == max_samplepos) {
2771 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2773 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2775 else if (direction == 0) {
2776 if ((presnap - before) < (after - presnap)) {
2788 Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
2794 _session->locations()->marks_either_side (presnap, before, after);
2796 if (before == max_samplepos && after == max_samplepos) {
2797 /* No marks to snap to, so just don't snap */
2799 } else if (before == max_samplepos) {
2801 } else if (after == max_samplepos) {
2804 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2806 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2808 } else if (direction == 0) {
2809 if ((presnap - before) < (after - presnap)) {
2821 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2823 const samplepos_t presnap = start.sample;
2825 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2826 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2827 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2829 /* check snap-to-marker */
2830 if (UIConfiguration::instance().get_snap_to_marks()) {
2835 test = marker_snap_to_internal (presnap, direction);
2836 check_best_snap(presnap, test, dist, best);
2839 /* check snap-to-region-{start/end/sync} */
2840 if (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync()) {
2841 if (!region_boundary_cache.empty()) {
2843 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2844 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2846 if (direction > 0) {
2847 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2849 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2852 if (next != region_boundary_cache.begin ()) {
2857 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2858 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2860 if (presnap > (p + n) / 2) {
2867 check_best_snap(presnap, test, dist, best);
2871 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
2873 /* if SnapToGrid is selected, the user wants to prioritize the music grid
2874 * in this case we should reset the best distance, so Grid will prevail */
2875 dist = max_samplepos;
2877 test = snap_to_grid (grid_marks, presnap, direction);
2878 check_best_snap(presnap, test, dist, best);
2881 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
2882 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
2883 * ToDo: Perhaps this should only occur if EditPointMouse?
2885 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2887 start.set (best, 0);
2889 } else if (presnap > best) {
2890 if (presnap > (best+ snap_threshold_s)) {
2893 } else if (presnap < best) {
2894 if (presnap < (best - snap_threshold_s)) {
2899 start.set (best, 0);
2904 Editor::setup_toolbar ()
2906 HBox* mode_box = manage(new HBox);
2907 mode_box->set_border_width (2);
2908 mode_box->set_spacing(2);
2910 HBox* mouse_mode_box = manage (new HBox);
2911 HBox* mouse_mode_hbox = manage (new HBox);
2912 VBox* mouse_mode_vbox = manage (new VBox);
2913 Alignment* mouse_mode_align = manage (new Alignment);
2915 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2916 mouse_mode_size_group->add_widget (smart_mode_button);
2917 mouse_mode_size_group->add_widget (mouse_move_button);
2918 mouse_mode_size_group->add_widget (mouse_cut_button);
2919 mouse_mode_size_group->add_widget (mouse_select_button);
2920 mouse_mode_size_group->add_widget (mouse_timefx_button);
2921 mouse_mode_size_group->add_widget (mouse_audition_button);
2922 mouse_mode_size_group->add_widget (mouse_draw_button);
2923 mouse_mode_size_group->add_widget (mouse_content_button);
2925 if (!Profile->get_mixbus()) {
2926 mouse_mode_size_group->add_widget (zoom_in_button);
2927 mouse_mode_size_group->add_widget (zoom_out_button);
2928 mouse_mode_size_group->add_widget (zoom_out_full_button);
2929 mouse_mode_size_group->add_widget (zoom_focus_selector);
2930 mouse_mode_size_group->add_widget (tav_shrink_button);
2931 mouse_mode_size_group->add_widget (tav_expand_button);
2933 mouse_mode_size_group->add_widget (zoom_preset_selector);
2934 mouse_mode_size_group->add_widget (visible_tracks_selector);
2937 mouse_mode_size_group->add_widget (grid_type_selector);
2938 mouse_mode_size_group->add_widget (snap_mode_button);
2940 mouse_mode_size_group->add_widget (edit_point_selector);
2941 mouse_mode_size_group->add_widget (edit_mode_selector);
2943 mouse_mode_size_group->add_widget (*nudge_clock);
2944 mouse_mode_size_group->add_widget (nudge_forward_button);
2945 mouse_mode_size_group->add_widget (nudge_backward_button);
2947 mouse_mode_hbox->set_spacing (2);
2949 if (!ARDOUR::Profile->get_trx()) {
2950 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2953 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2954 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2956 if (!ARDOUR::Profile->get_mixbus()) {
2957 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2958 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2961 if (!ARDOUR::Profile->get_trx()) {
2962 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2963 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2964 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2967 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2969 mouse_mode_align->add (*mouse_mode_vbox);
2970 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2972 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2974 edit_mode_selector.set_name ("mouse mode button");
2976 if (!ARDOUR::Profile->get_trx()) {
2977 mode_box->pack_start (edit_mode_selector, false, false);
2978 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2979 mode_box->pack_start (edit_point_selector, false, false);
2980 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2983 mode_box->pack_start (*mouse_mode_box, false, false);
2987 _zoom_box.set_spacing (2);
2988 _zoom_box.set_border_width (2);
2992 zoom_preset_selector.set_name ("zoom button");
2993 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
2995 zoom_in_button.set_name ("zoom button");
2996 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2997 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2998 zoom_in_button.set_related_action (act);
3000 zoom_out_button.set_name ("zoom button");
3001 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3002 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3003 zoom_out_button.set_related_action (act);
3005 zoom_out_full_button.set_name ("zoom button");
3006 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3007 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3008 zoom_out_full_button.set_related_action (act);
3010 zoom_focus_selector.set_name ("zoom button");
3012 if (ARDOUR::Profile->get_mixbus()) {
3013 _zoom_box.pack_start (zoom_preset_selector, false, false);
3014 } else if (ARDOUR::Profile->get_trx()) {
3015 mode_box->pack_start (zoom_out_button, false, false);
3016 mode_box->pack_start (zoom_in_button, false, false);
3018 _zoom_box.pack_start (zoom_out_button, false, false);
3019 _zoom_box.pack_start (zoom_in_button, false, false);
3020 _zoom_box.pack_start (zoom_out_full_button, false, false);
3021 _zoom_box.pack_start (zoom_focus_selector, false, false);
3024 /* Track zoom buttons */
3025 _track_box.set_spacing (2);
3026 _track_box.set_border_width (2);
3028 visible_tracks_selector.set_name ("zoom button");
3029 if (Profile->get_mixbus()) {
3030 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3032 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3035 tav_expand_button.set_name ("zoom button");
3036 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3037 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3038 tav_expand_button.set_related_action (act);
3040 tav_shrink_button.set_name ("zoom button");
3041 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3042 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3043 tav_shrink_button.set_related_action (act);
3045 if (ARDOUR::Profile->get_mixbus()) {
3046 _track_box.pack_start (visible_tracks_selector);
3047 } else if (ARDOUR::Profile->get_trx()) {
3048 _track_box.pack_start (tav_shrink_button);
3049 _track_box.pack_start (tav_expand_button);
3051 _track_box.pack_start (visible_tracks_selector);
3052 _track_box.pack_start (tav_shrink_button);
3053 _track_box.pack_start (tav_expand_button);
3056 snap_box.set_spacing (2);
3057 snap_box.set_border_width (2);
3059 grid_type_selector.set_name ("mouse mode button");
3061 snap_mode_button.set_name ("mouse mode button");
3063 edit_point_selector.set_name ("mouse mode button");
3065 snap_box.pack_start (snap_mode_button, false, false);
3066 snap_box.pack_start (grid_type_selector, false, false);
3070 HBox *nudge_box = manage (new HBox);
3071 nudge_box->set_spacing (2);
3072 nudge_box->set_border_width (2);
3074 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3075 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3077 nudge_box->pack_start (nudge_backward_button, false, false);
3078 nudge_box->pack_start (nudge_forward_button, false, false);
3079 nudge_box->pack_start (*nudge_clock, false, false);
3082 /* Pack everything in... */
3084 toolbar_hbox.set_spacing (2);
3085 toolbar_hbox.set_border_width (2);
3087 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3088 tool_shadow->set_size_request (4, -1);
3089 tool_shadow->show();
3091 ebox_hpacker.pack_start (*tool_shadow, false, false);
3092 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3094 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3095 spacer->set_name("EditorWindow");
3096 spacer->set_size_request(-1,4);
3099 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3100 ebox_vpacker.pack_start(*spacer, false, false);
3101 ebox_vpacker.show();
3103 toolbar_hbox.pack_start (*mode_box, false, false);
3105 if (!ARDOUR::Profile->get_trx()) {
3107 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3109 toolbar_hbox.pack_start (snap_box, false, false);
3111 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3113 toolbar_hbox.pack_start (*nudge_box, false, false);
3115 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3117 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3119 toolbar_hbox.pack_end (_track_box, false, false);
3123 toolbar_hbox.show_all ();
3127 Editor::build_edit_point_menu ()
3129 using namespace Menu_Helpers;
3131 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3132 if(!Profile->get_mixbus())
3133 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3134 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3136 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3140 Editor::build_edit_mode_menu ()
3142 using namespace Menu_Helpers;
3144 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3145 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3146 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3147 /* Note: Splice was removed */
3149 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3153 Editor::build_grid_type_menu ()
3155 using namespace Menu_Helpers;
3157 /* main grid: bars, quarter-notes, etc */
3158 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3159 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3160 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3161 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3162 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3163 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3164 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3165 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3168 grid_type_selector.AddMenuElem(SeparatorElem());
3169 Gtk::Menu *_triplet_menu = manage (new Menu);
3170 MenuList& triplet_items (_triplet_menu->items());
3172 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3173 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3174 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3175 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3177 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3179 /* quintuplet grid */
3180 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3181 MenuList& quintuplet_items (_quintuplet_menu->items());
3183 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3184 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3185 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3187 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3189 /* septuplet grid */
3190 Gtk::Menu *_septuplet_menu = manage (new Menu);
3191 MenuList& septuplet_items (_septuplet_menu->items());
3193 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3194 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3195 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3197 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3199 grid_type_selector.AddMenuElem(SeparatorElem());
3200 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeSmpte], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSmpte)));
3201 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3202 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeSamples], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSamples)));
3204 set_size_request_to_display_given_text (grid_type_selector, _("Long Grid"), COMBO_TRIANGLE_WIDTH, 2); // problem: some of the rarely-used grid names are very long. Just do something arbitary, translators: rename this if needed
3208 Editor::setup_tooltips ()
3210 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3211 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3212 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3213 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3214 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3215 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3216 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3217 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3218 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3219 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3220 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3221 set_tooltip (zoom_in_button, _("Zoom In"));
3222 set_tooltip (zoom_out_button, _("Zoom Out"));
3223 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3224 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3225 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3226 set_tooltip (tav_expand_button, _("Expand Tracks"));
3227 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3228 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3229 set_tooltip (grid_type_selector, _("Grid Mode"));
3230 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3231 set_tooltip (edit_point_selector, _("Edit Point"));
3232 set_tooltip (edit_mode_selector, _("Edit Mode"));
3233 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3237 Editor::convert_drop_to_paths (
3238 vector<string>& paths,
3239 const RefPtr<Gdk::DragContext>& /*context*/,
3242 const SelectionData& data,
3246 if (_session == 0) {
3250 vector<string> uris = data.get_uris();
3254 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3255 are actually URI lists. So do it by hand.
3258 if (data.get_target() != "text/plain") {
3262 /* Parse the "uri-list" format that Nautilus provides,
3263 where each pathname is delimited by \r\n.
3265 THERE MAY BE NO NULL TERMINATING CHAR!!!
3268 string txt = data.get_text();
3272 p = (char *) malloc (txt.length() + 1);
3273 txt.copy (p, txt.length(), 0);
3274 p[txt.length()] = '\0';
3280 while (g_ascii_isspace (*p))
3284 while (*q && (*q != '\n') && (*q != '\r')) {
3291 while (q > p && g_ascii_isspace (*q))
3296 uris.push_back (string (p, q - p + 1));
3300 p = strchr (p, '\n');
3312 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3313 if ((*i).substr (0,7) == "file://") {
3314 paths.push_back (Glib::filename_from_uri (*i));
3322 Editor::new_tempo_section ()
3327 Editor::map_transport_state ()
3329 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3331 if (_session && _session->transport_stopped()) {
3332 have_pending_keyboard_selection = false;
3335 update_loop_range_view ();
3339 Editor::transport_looped ()
3341 /* reset Playhead position interpolation.
3342 * see Editor::super_rapid_screen_update
3344 _last_update_time = 0;
3350 Editor::begin_selection_op_history ()
3352 selection_op_cmd_depth = 0;
3353 selection_op_history_it = 0;
3355 while(!selection_op_history.empty()) {
3356 delete selection_op_history.front();
3357 selection_op_history.pop_front();
3360 selection_undo_action->set_sensitive (false);
3361 selection_redo_action->set_sensitive (false);
3362 selection_op_history.push_front (&_selection_memento->get_state ());
3366 Editor::begin_reversible_selection_op (string name)
3369 //cerr << name << endl;
3370 /* begin/commit pairs can be nested */
3371 selection_op_cmd_depth++;
3376 Editor::commit_reversible_selection_op ()
3379 if (selection_op_cmd_depth == 1) {
3381 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3382 /* The user has undone some selection ops and then made a new one,
3383 * making anything earlier in the list invalid.
3386 list<XMLNode *>::iterator it = selection_op_history.begin();
3387 list<XMLNode *>::iterator e_it = it;
3388 advance (e_it, selection_op_history_it);
3390 for (; it != e_it; ++it) {
3393 selection_op_history.erase (selection_op_history.begin(), e_it);
3396 selection_op_history.push_front (&_selection_memento->get_state ());
3397 selection_op_history_it = 0;
3399 selection_undo_action->set_sensitive (true);
3400 selection_redo_action->set_sensitive (false);
3403 if (selection_op_cmd_depth > 0) {
3404 selection_op_cmd_depth--;
3410 Editor::undo_selection_op ()
3413 selection_op_history_it++;
3415 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3416 if (n == selection_op_history_it) {
3417 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3418 selection_redo_action->set_sensitive (true);
3422 /* is there an earlier entry? */
3423 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3424 selection_undo_action->set_sensitive (false);
3430 Editor::redo_selection_op ()
3433 if (selection_op_history_it > 0) {
3434 selection_op_history_it--;
3437 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3438 if (n == selection_op_history_it) {
3439 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3440 selection_undo_action->set_sensitive (true);
3445 if (selection_op_history_it == 0) {
3446 selection_redo_action->set_sensitive (false);
3452 Editor::begin_reversible_command (string name)
3455 before.push_back (&_selection_memento->get_state ());
3456 _session->begin_reversible_command (name);
3461 Editor::begin_reversible_command (GQuark q)
3464 before.push_back (&_selection_memento->get_state ());
3465 _session->begin_reversible_command (q);
3470 Editor::abort_reversible_command ()
3473 while(!before.empty()) {
3474 delete before.front();
3477 _session->abort_reversible_command ();
3482 Editor::commit_reversible_command ()
3485 if (before.size() == 1) {
3486 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3487 redo_action->set_sensitive(false);
3488 undo_action->set_sensitive(true);
3489 begin_selection_op_history ();
3492 if (before.empty()) {
3493 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3498 _session->commit_reversible_command ();
3503 Editor::history_changed ()
3507 if (undo_action && _session) {
3508 if (_session->undo_depth() == 0) {
3509 label = S_("Command|Undo");
3511 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3513 undo_action->property_label() = label;
3516 if (redo_action && _session) {
3517 if (_session->redo_depth() == 0) {
3519 redo_action->set_sensitive (false);
3521 label = string_compose(_("Redo (%1)"), _session->next_redo());
3522 redo_action->set_sensitive (true);
3524 redo_action->property_label() = label;
3529 Editor::duplicate_range (bool with_dialog)
3533 RegionSelection rs = get_regions_from_selection_and_entered ();
3535 if (selection->time.length() == 0 && rs.empty()) {
3541 ArdourDialog win (_("Duplicate"));
3542 Label label (_("Number of duplications:"));
3543 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3544 SpinButton spinner (adjustment, 0.0, 1);
3547 win.get_vbox()->set_spacing (12);
3548 win.get_vbox()->pack_start (hbox);
3549 hbox.set_border_width (6);
3550 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3552 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3553 place, visually. so do this by hand.
3556 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3557 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3558 spinner.grab_focus();
3564 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3565 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3566 win.set_default_response (RESPONSE_ACCEPT);
3568 spinner.grab_focus ();
3570 switch (win.run ()) {
3571 case RESPONSE_ACCEPT:
3577 times = adjustment.get_value();
3580 if ((current_mouse_mode() == MouseRange)) {
3581 if (selection->time.length()) {
3582 duplicate_selection (times);
3584 } else if (get_smart_mode()) {
3585 if (selection->time.length()) {
3586 duplicate_selection (times);
3588 duplicate_some_regions (rs, times);
3590 duplicate_some_regions (rs, times);
3595 Editor::set_edit_mode (EditMode m)
3597 Config->set_edit_mode (m);
3601 Editor::cycle_edit_mode ()
3603 switch (Config->get_edit_mode()) {
3605 Config->set_edit_mode (Ripple);
3609 Config->set_edit_mode (Lock);
3612 Config->set_edit_mode (Slide);
3618 Editor::edit_mode_selection_done (EditMode m)
3620 Config->set_edit_mode (m);
3624 Editor::grid_type_selection_done (GridType gridtype)
3626 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3628 ract->set_active ();
3633 Editor::snap_mode_selection_done (SnapMode mode)
3635 RefPtr<RadioAction> ract = snap_mode_action (mode);
3638 ract->set_active (true);
3643 Editor::cycle_edit_point (bool with_marker)
3645 if(Profile->get_mixbus())
3646 with_marker = false;
3648 switch (_edit_point) {
3650 set_edit_point_preference (EditAtPlayhead);
3652 case EditAtPlayhead:
3654 set_edit_point_preference (EditAtSelectedMarker);
3656 set_edit_point_preference (EditAtMouse);
3659 case EditAtSelectedMarker:
3660 set_edit_point_preference (EditAtMouse);
3666 Editor::edit_point_selection_done (EditPoint ep)
3668 set_edit_point_preference (ep);
3672 Editor::build_zoom_focus_menu ()
3674 using namespace Menu_Helpers;
3676 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3677 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3678 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3679 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3680 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3681 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3683 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3687 Editor::zoom_focus_selection_done (ZoomFocus f)
3689 RefPtr<RadioAction> ract = zoom_focus_action (f);
3691 ract->set_active ();
3696 Editor::build_track_count_menu ()
3698 using namespace Menu_Helpers;
3700 if (!Profile->get_mixbus()) {
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3709 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3724 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3731 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3732 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3733 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3734 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3735 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3736 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3737 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3742 Editor::set_zoom_preset (int64_t ms)
3745 temporal_zoom_session();
3749 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3750 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3754 Editor::set_visible_track_count (int32_t n)
3756 _visible_track_count = n;
3758 /* if the canvas hasn't really been allocated any size yet, just
3759 record the desired number of visible tracks and return. when canvas
3760 allocation happens, we will get called again and then we can do the
3764 if (_visible_canvas_height <= 1) {
3770 DisplaySuspender ds;
3772 if (_visible_track_count > 0) {
3773 h = trackviews_height() / _visible_track_count;
3774 std::ostringstream s;
3775 s << _visible_track_count;
3777 } else if (_visible_track_count == 0) {
3779 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3780 if ((*i)->marked_for_display()) {
3782 TimeAxisView::Children cl ((*i)->get_child_list ());
3783 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3784 if ((*j)->marked_for_display()) {
3791 visible_tracks_selector.set_text (X_("*"));
3794 h = trackviews_height() / n;
3797 /* negative value means that the visible track count has
3798 been overridden by explicit track height changes.
3800 visible_tracks_selector.set_text (X_("*"));
3804 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3805 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3808 if (str != visible_tracks_selector.get_text()) {
3809 visible_tracks_selector.set_text (str);
3814 Editor::override_visible_track_count ()
3816 _visible_track_count = -1;
3817 visible_tracks_selector.set_text (_("*"));
3821 Editor::edit_controls_button_release (GdkEventButton* ev)
3823 if (Keyboard::is_context_menu_event (ev)) {
3824 ARDOUR_UI::instance()->add_route ();
3825 } else if (ev->button == 1) {
3826 selection->clear_tracks ();
3833 Editor::mouse_select_button_release (GdkEventButton* ev)
3835 /* this handles just right-clicks */
3837 if (ev->button != 3) {
3845 Editor::set_zoom_focus (ZoomFocus f)
3847 string str = zoom_focus_strings[(int)f];
3849 if (str != zoom_focus_selector.get_text()) {
3850 zoom_focus_selector.set_text (str);
3853 if (zoom_focus != f) {
3860 Editor::cycle_zoom_focus ()
3862 switch (zoom_focus) {
3864 set_zoom_focus (ZoomFocusRight);
3866 case ZoomFocusRight:
3867 set_zoom_focus (ZoomFocusCenter);
3869 case ZoomFocusCenter:
3870 set_zoom_focus (ZoomFocusPlayhead);
3872 case ZoomFocusPlayhead:
3873 set_zoom_focus (ZoomFocusMouse);
3875 case ZoomFocusMouse:
3876 set_zoom_focus (ZoomFocusEdit);
3879 set_zoom_focus (ZoomFocusLeft);
3885 Editor::update_grid ()
3887 if (grid_musical()) {
3888 std::vector<TempoMap::BBTPoint> grid;
3889 if (bbt_ruler_scale != bbt_show_many) {
3890 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3892 maybe_draw_grid_lines ();
3893 } else if (grid_nonmusical()) {
3894 maybe_draw_grid_lines ();
3901 Editor::toggle_follow_playhead ()
3903 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3905 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3906 set_follow_playhead (tact->get_active());
3910 /** @param yn true to follow playhead, otherwise false.
3911 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3914 Editor::set_follow_playhead (bool yn, bool catch_up)
3916 if (_follow_playhead != yn) {
3917 if ((_follow_playhead = yn) == true && catch_up) {
3919 reset_x_origin_to_follow_playhead ();
3926 Editor::toggle_stationary_playhead ()
3928 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3930 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3931 set_stationary_playhead (tact->get_active());
3936 Editor::set_stationary_playhead (bool yn)
3938 if (_stationary_playhead != yn) {
3939 if ((_stationary_playhead = yn) == true) {
3940 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
3941 // update_current_screen ();
3948 Editor::playlist_selector () const
3950 return *_playlist_selector;
3954 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
3956 if (paste_count == 0) {
3957 /* don't bother calculating an offset that will be zero anyway */
3961 /* calculate basic unsnapped multi-paste offset */
3962 samplecnt_t offset = paste_count * duration;
3964 /* snap offset so pos + offset is aligned to the grid */
3965 MusicSample offset_pos (pos + offset, 0);
3966 snap_to(offset_pos, RoundUpMaybe);
3967 offset = offset_pos.sample - pos;
3973 Editor::get_grid_beat_divisions(samplepos_t position)
3975 switch (_grid_type) {
3976 case GridTypeBeatDiv32: return 32;
3977 case GridTypeBeatDiv28: return 28;
3978 case GridTypeBeatDiv24: return 24;
3979 case GridTypeBeatDiv20: return 20;
3980 case GridTypeBeatDiv16: return 16;
3981 case GridTypeBeatDiv14: return 14;
3982 case GridTypeBeatDiv12: return 12;
3983 case GridTypeBeatDiv10: return 10;
3984 case GridTypeBeatDiv8: return 8;
3985 case GridTypeBeatDiv7: return 7;
3986 case GridTypeBeatDiv6: return 6;
3987 case GridTypeBeatDiv5: return 5;
3988 case GridTypeBeatDiv4: return 4;
3989 case GridTypeBeatDiv3: return 3;
3990 case GridTypeBeatDiv2: return 2;
3992 case GridTypeNone: return 0;
3993 case GridTypeSmpte: return 0;
3994 case GridTypeMinSec: return 0;
3995 case GridTypeSamples: return 0;
4001 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4002 if the grid is non-musical, returns 0.
4003 if the grid is snapped to bars, returns -1.
4004 @param event_state the current keyboard modifier mask.
4007 Editor::get_grid_music_divisions (uint32_t event_state)
4009 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4013 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4017 switch (_grid_type) {
4018 case GridTypeBeatDiv32: return 32;
4019 case GridTypeBeatDiv28: return 28;
4020 case GridTypeBeatDiv24: return 24;
4021 case GridTypeBeatDiv20: return 20;
4022 case GridTypeBeatDiv16: return 16;
4023 case GridTypeBeatDiv14: return 14;
4024 case GridTypeBeatDiv12: return 12;
4025 case GridTypeBeatDiv10: return 10;
4026 case GridTypeBeatDiv8: return 8;
4027 case GridTypeBeatDiv7: return 7;
4028 case GridTypeBeatDiv6: return 6;
4029 case GridTypeBeatDiv5: return 5;
4030 case GridTypeBeatDiv4: return 4;
4031 case GridTypeBeatDiv3: return 3;
4032 case GridTypeBeatDiv2: return 2;
4033 case GridTypeBeat: return 1;
4034 case GridTypeBar : return -1;
4036 case GridTypeNone: return 0;
4037 case GridTypeSmpte: return 0;
4038 case GridTypeMinSec: return 0;
4039 case GridTypeSamples: return 0;
4045 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4049 const unsigned divisions = get_grid_beat_divisions(position);
4051 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4054 switch (_grid_type) {
4056 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4059 const Meter& m = _session->tempo_map().meter_at_sample (position);
4060 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4068 return Temporal::Beats();
4072 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4076 ret = nudge_clock->current_duration (pos);
4077 next = ret + 1; /* XXXX fix me */
4083 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4085 ArdourDialog dialog (_("Playlist Deletion"));
4086 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4087 "If it is kept, its audio files will not be cleaned.\n"
4088 "If it is deleted, audio files used by it alone will be cleaned."),
4091 dialog.set_position (WIN_POS_CENTER);
4092 dialog.get_vbox()->pack_start (label);
4096 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4097 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4098 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4099 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4100 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4102 /* by default gtk uses the left most button */
4103 keep->grab_focus ();
4105 switch (dialog.run ()) {
4107 /* keep this and all remaining ones */
4112 /* delete this and all others */
4116 case RESPONSE_ACCEPT:
4117 /* delete the playlist */
4121 case RESPONSE_REJECT:
4122 /* keep the playlist */
4134 Editor::audio_region_selection_covers (samplepos_t where)
4136 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4137 if ((*a)->region()->covers (where)) {
4146 Editor::prepare_for_cleanup ()
4148 cut_buffer->clear_regions ();
4149 cut_buffer->clear_playlists ();
4151 selection->clear_regions ();
4152 selection->clear_playlists ();
4154 _regions->suspend_redisplay ();
4158 Editor::finish_cleanup ()
4160 _regions->resume_redisplay ();
4164 Editor::transport_loop_location()
4167 return _session->locations()->auto_loop_location();
4174 Editor::transport_punch_location()
4177 return _session->locations()->auto_punch_location();
4184 Editor::control_layout_scroll (GdkEventScroll* ev)
4186 /* Just forward to the normal canvas scroll method. The coordinate
4187 systems are different but since the canvas is always larger than the
4188 track headers, and aligned with the trackview area, this will work.
4190 In the not too distant future this layout is going away anyway and
4191 headers will be on the canvas.
4193 return canvas_scroll_event (ev, false);
4197 Editor::session_state_saved (string)
4200 _snapshots->redisplay ();
4204 Editor::maximise_editing_space ()
4210 Gtk::Window* toplevel = current_toplevel();
4213 toplevel->fullscreen ();
4219 Editor::restore_editing_space ()
4225 Gtk::Window* toplevel = current_toplevel();
4228 toplevel->unfullscreen();
4234 * Make new playlists for a given track and also any others that belong
4235 * to the same active route group with the `select' property.
4240 Editor::new_playlists (TimeAxisView* v)
4242 begin_reversible_command (_("new playlists"));
4243 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4244 _session->playlists->get (playlists);
4245 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4246 commit_reversible_command ();
4250 * Use a copy of the current playlist for a given track and also any others that belong
4251 * to the same active route group with the `select' property.
4256 Editor::copy_playlists (TimeAxisView* v)
4258 begin_reversible_command (_("copy playlists"));
4259 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4260 _session->playlists->get (playlists);
4261 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4262 commit_reversible_command ();
4265 /** Clear the current playlist for a given track and also any others that belong
4266 * to the same active route group with the `select' property.
4271 Editor::clear_playlists (TimeAxisView* v)
4273 begin_reversible_command (_("clear playlists"));
4274 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4275 _session->playlists->get (playlists);
4276 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4277 commit_reversible_command ();
4281 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4283 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4287 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4289 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4293 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4295 atv.clear_playlist ();
4299 Editor::get_y_origin () const
4301 return vertical_adjustment.get_value ();
4304 /** Queue up a change to the viewport x origin.
4305 * @param sample New x origin.
4308 Editor::reset_x_origin (samplepos_t sample)
4310 pending_visual_change.add (VisualChange::TimeOrigin);
4311 pending_visual_change.time_origin = sample;
4312 ensure_visual_change_idle_handler ();
4316 Editor::reset_y_origin (double y)
4318 pending_visual_change.add (VisualChange::YOrigin);
4319 pending_visual_change.y_origin = y;
4320 ensure_visual_change_idle_handler ();
4324 Editor::reset_zoom (samplecnt_t spp)
4326 if (spp == samples_per_pixel) {
4330 pending_visual_change.add (VisualChange::ZoomLevel);
4331 pending_visual_change.samples_per_pixel = spp;
4332 ensure_visual_change_idle_handler ();
4336 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4338 reset_x_origin (sample);
4341 if (!no_save_visual) {
4342 undo_visual_stack.push_back (current_visual_state(false));
4346 Editor::VisualState::VisualState (bool with_tracks)
4347 : gui_state (with_tracks ? new GUIObjectState : 0)
4351 Editor::VisualState::~VisualState ()
4356 Editor::VisualState*
4357 Editor::current_visual_state (bool with_tracks)
4359 VisualState* vs = new VisualState (with_tracks);
4360 vs->y_position = vertical_adjustment.get_value();
4361 vs->samples_per_pixel = samples_per_pixel;
4362 vs->_leftmost_sample = _leftmost_sample;
4363 vs->zoom_focus = zoom_focus;
4366 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4373 Editor::undo_visual_state ()
4375 if (undo_visual_stack.empty()) {
4379 VisualState* vs = undo_visual_stack.back();
4380 undo_visual_stack.pop_back();
4383 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4386 use_visual_state (*vs);
4391 Editor::redo_visual_state ()
4393 if (redo_visual_stack.empty()) {
4397 VisualState* vs = redo_visual_stack.back();
4398 redo_visual_stack.pop_back();
4400 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4401 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4404 use_visual_state (*vs);
4409 Editor::swap_visual_state ()
4411 if (undo_visual_stack.empty()) {
4412 redo_visual_state ();
4414 undo_visual_state ();
4419 Editor::use_visual_state (VisualState& vs)
4421 PBD::Unwinder<bool> nsv (no_save_visual, true);
4422 DisplaySuspender ds;
4424 vertical_adjustment.set_value (vs.y_position);
4426 set_zoom_focus (vs.zoom_focus);
4427 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4430 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4432 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4433 (*i)->clear_property_cache();
4434 (*i)->reset_visual_state ();
4438 _routes->update_visibility ();
4441 /** This is the core function that controls the zoom level of the canvas. It is called
4442 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4443 * @param spp new number of samples per pixel
4446 Editor::set_samples_per_pixel (samplecnt_t spp)
4452 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4453 const samplecnt_t lots_of_pixels = 4000;
4455 /* if the zoom level is greater than what you'd get trying to display 3
4456 * days of audio on a really big screen, then it's too big.
4459 if (spp * lots_of_pixels > three_days) {
4463 samples_per_pixel = spp;
4467 Editor::on_samples_per_pixel_changed ()
4469 bool const showing_time_selection = selection->time.length() > 0;
4471 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4472 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4473 (*i)->reshow_selection (selection->time);
4477 ZoomChanged (); /* EMIT_SIGNAL */
4479 ArdourCanvas::GtkCanvasViewport* c;
4481 c = get_track_canvas();
4483 c->canvas()->zoomed ();
4486 if (playhead_cursor) {
4487 playhead_cursor->set_position (playhead_cursor->current_sample ());
4490 refresh_location_display();
4491 _summary->set_overlays_dirty ();
4493 update_marker_labels ();
4499 Editor::playhead_cursor_sample () const
4501 return playhead_cursor->current_sample();
4505 Editor::queue_visual_videotimeline_update ()
4507 pending_visual_change.add (VisualChange::VideoTimeline);
4508 ensure_visual_change_idle_handler ();
4512 Editor::ensure_visual_change_idle_handler ()
4514 if (pending_visual_change.idle_handler_id < 0) {
4515 /* see comment in add_to_idle_resize above. */
4516 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4517 pending_visual_change.being_handled = false;
4522 Editor::_idle_visual_changer (void* arg)
4524 return static_cast<Editor*>(arg)->idle_visual_changer ();
4528 Editor::pre_render ()
4530 visual_change_queued = false;
4532 if (pending_visual_change.pending != 0) {
4533 ensure_visual_change_idle_handler();
4538 Editor::idle_visual_changer ()
4540 pending_visual_change.idle_handler_id = -1;
4542 if (pending_visual_change.pending == 0) {
4546 /* set_horizontal_position() below (and maybe other calls) call
4547 gtk_main_iteration(), so it's possible that a signal will be handled
4548 half-way through this method. If this signal wants an
4549 idle_visual_changer we must schedule another one after this one, so
4550 mark the idle_handler_id as -1 here to allow that. Also make a note
4551 that we are doing the visual change, so that changes in response to
4552 super-rapid-screen-update can be dropped if we are still processing
4556 if (visual_change_queued) {
4560 pending_visual_change.being_handled = true;
4562 VisualChange vc = pending_visual_change;
4564 pending_visual_change.pending = (VisualChange::Type) 0;
4566 visual_changer (vc);
4568 pending_visual_change.being_handled = false;
4570 visual_change_queued = true;
4572 return 0; /* this is always a one-shot call */
4576 Editor::visual_changer (const VisualChange& vc)
4579 * Changed first so the correct horizontal canvas position is calculated in
4580 * Editor::set_horizontal_position
4582 if (vc.pending & VisualChange::ZoomLevel) {
4583 set_samples_per_pixel (vc.samples_per_pixel);
4586 if (vc.pending & VisualChange::TimeOrigin) {
4587 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4588 set_horizontal_position (new_time_origin);
4591 if (vc.pending & VisualChange::YOrigin) {
4592 vertical_adjustment.set_value (vc.y_origin);
4596 * Now the canvas is in the final state before render the canvas items that
4597 * support the Item::prepare_for_render interface can calculate the correct
4598 * item to visible canvas intersection.
4600 if (vc.pending & VisualChange::ZoomLevel) {
4601 on_samples_per_pixel_changed ();
4603 compute_fixed_ruler_scale ();
4605 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4606 update_tempo_based_rulers ();
4609 if (!(vc.pending & VisualChange::ZoomLevel)) {
4610 /* If the canvas is not being zoomed then the canvas items will not change
4611 * and cause Item::prepare_for_render to be called so do it here manually.
4612 * Not ideal, but I can't think of a better solution atm.
4614 _track_canvas->prepare_for_render();
4617 /* If we are only scrolling vertically there is no need to update these */
4618 if (vc.pending != VisualChange::YOrigin) {
4619 update_fixed_rulers ();
4620 redisplay_grid (true);
4622 /* video frames & position need to be updated for zoom, horiz-scroll
4623 * and (explicitly) VisualChange::VideoTimeline.
4625 update_video_timeline();
4628 _summary->set_overlays_dirty ();
4631 struct EditorOrderTimeAxisSorter {
4632 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4633 return a->order () < b->order ();
4638 Editor::sort_track_selection (TrackViewList& sel)
4640 EditorOrderTimeAxisSorter cmp;
4645 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4648 samplepos_t where = 0;
4649 EditPoint ep = _edit_point;
4651 if (Profile->get_mixbus()) {
4652 if (ep == EditAtSelectedMarker) {
4653 ep = EditAtPlayhead;
4657 if (from_outside_canvas && (ep == EditAtMouse)) {
4658 ep = EditAtPlayhead;
4659 } else if (from_context_menu && (ep == EditAtMouse)) {
4660 return canvas_event_sample (&context_click_event, 0, 0);
4663 if (entered_marker) {
4664 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4665 return entered_marker->position();
4668 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4669 ep = EditAtSelectedMarker;
4672 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4673 ep = EditAtPlayhead;
4676 MusicSample snap_mf (0, 0);
4679 case EditAtPlayhead:
4680 if (_dragging_playhead && _control_scroll_target) {
4681 where = *_control_scroll_target;
4683 where = _session->audible_sample();
4685 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4688 case EditAtSelectedMarker:
4689 if (!selection->markers.empty()) {
4691 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4694 where = loc->start();
4698 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4706 if (!mouse_sample (where, ignored)) {
4707 /* XXX not right but what can we do ? */
4710 snap_mf.sample = where;
4712 where = snap_mf.sample;
4713 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4721 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4723 if (!_session) return;
4725 begin_reversible_command (cmd);
4729 if ((tll = transport_loop_location()) == 0) {
4730 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4731 XMLNode &before = _session->locations()->get_state();
4732 _session->locations()->add (loc, true);
4733 _session->set_auto_loop_location (loc);
4734 XMLNode &after = _session->locations()->get_state();
4735 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4737 XMLNode &before = tll->get_state();
4738 tll->set_hidden (false, this);
4739 tll->set (start, end);
4740 XMLNode &after = tll->get_state();
4741 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4744 commit_reversible_command ();
4748 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4750 if (!_session) return;
4752 begin_reversible_command (cmd);
4756 if ((tpl = transport_punch_location()) == 0) {
4757 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4758 XMLNode &before = _session->locations()->get_state();
4759 _session->locations()->add (loc, true);
4760 _session->set_auto_punch_location (loc);
4761 XMLNode &after = _session->locations()->get_state();
4762 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4764 XMLNode &before = tpl->get_state();
4765 tpl->set_hidden (false, this);
4766 tpl->set (start, end);
4767 XMLNode &after = tpl->get_state();
4768 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4771 commit_reversible_command ();
4774 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4775 * @param rs List to which found regions are added.
4776 * @param where Time to look at.
4777 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4780 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4782 const TrackViewList* tracks;
4785 tracks = &track_views;
4790 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4792 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4795 boost::shared_ptr<Track> tr;
4796 boost::shared_ptr<Playlist> pl;
4798 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4800 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4802 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4803 RegionView* rv = rtv->view()->find_view (*i);
4814 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4816 const TrackViewList* tracks;
4819 tracks = &track_views;
4824 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4825 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4827 boost::shared_ptr<Track> tr;
4828 boost::shared_ptr<Playlist> pl;
4830 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4832 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4834 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4836 RegionView* rv = rtv->view()->find_view (*i);
4847 /** Get regions using the following method:
4849 * Make a region list using:
4850 * (a) any selected regions
4851 * (b) the intersection of any selected tracks and the edit point(*)
4852 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4854 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4856 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4860 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4862 RegionSelection regions;
4864 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4865 regions.add (entered_regionview);
4867 regions = selection->regions;
4870 if (regions.empty()) {
4871 TrackViewList tracks = selection->tracks;
4873 if (!tracks.empty()) {
4874 /* no region selected or entered, but some selected tracks:
4875 * act on all regions on the selected tracks at the edit point
4877 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4878 get_regions_at(regions, where, tracks);
4885 /** Get regions using the following method:
4887 * Make a region list using:
4888 * (a) any selected regions
4889 * (b) the intersection of any selected tracks and the edit point(*)
4890 * (c) if neither exists, then whatever region is under the mouse
4892 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4894 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4897 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4899 RegionSelection regions;
4901 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4902 regions.add (entered_regionview);
4904 regions = selection->regions;
4907 if (regions.empty()) {
4908 TrackViewList tracks = selection->tracks;
4910 if (!tracks.empty()) {
4911 /* no region selected or entered, but some selected tracks:
4912 * act on all regions on the selected tracks at the edit point
4914 get_regions_at(regions, pos, tracks);
4921 /** Start with regions that are selected, or the entered regionview if none are selected.
4922 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4923 * of the regions that we started with.
4927 Editor::get_regions_from_selection_and_entered () const
4929 RegionSelection regions = selection->regions;
4931 if (regions.empty() && entered_regionview) {
4932 regions.add (entered_regionview);
4939 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4941 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4942 RouteTimeAxisView* rtav;
4944 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4945 boost::shared_ptr<Playlist> pl;
4946 std::vector<boost::shared_ptr<Region> > results;
4947 boost::shared_ptr<Track> tr;
4949 if ((tr = rtav->track()) == 0) {
4954 if ((pl = (tr->playlist())) != 0) {
4955 boost::shared_ptr<Region> r = pl->region_by_id (id);
4957 RegionView* rv = rtav->view()->find_view (r);
4959 regions.push_back (rv);
4968 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4971 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4972 MidiTimeAxisView* mtav;
4974 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4976 mtav->get_per_region_note_selection (selection);
4983 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4985 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4987 RouteTimeAxisView* tatv;
4989 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4991 boost::shared_ptr<Playlist> pl;
4992 vector<boost::shared_ptr<Region> > results;
4994 boost::shared_ptr<Track> tr;
4996 if ((tr = tatv->track()) == 0) {
5001 if ((pl = (tr->playlist())) != 0) {
5002 if (src_comparison) {
5003 pl->get_source_equivalent_regions (region, results);
5005 pl->get_region_list_equivalent_regions (region, results);
5009 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5010 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5011 regions.push_back (marv);
5020 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5022 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5023 RouteTimeAxisView* tatv;
5024 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5025 if (!tatv->track()) {
5028 RegionView* marv = tatv->view()->find_view (region);
5038 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5040 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5041 RouteTimeAxisView* rtav;
5042 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5043 if (rtav->route() == route) {
5052 Editor::show_rhythm_ferret ()
5054 if (rhythm_ferret == 0) {
5055 rhythm_ferret = new RhythmFerret(*this);
5058 rhythm_ferret->set_session (_session);
5059 rhythm_ferret->show ();
5060 rhythm_ferret->present ();
5064 Editor::first_idle ()
5066 MessageDialog* dialog = 0;
5068 if (track_views.size() > 1) {
5069 Timers::TimerSuspender t;
5070 dialog = new MessageDialog (
5071 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5075 ARDOUR_UI::instance()->flush_pending (60);
5078 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5082 /* now that all regionviews should exist, setup region selection */
5086 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5087 /* this is cumulative: rs is NOT cleared each time */
5088 get_regionviews_by_id (*pr, rs);
5091 selection->set (rs);
5093 /* first idle adds route children (automation tracks), so we need to redisplay here */
5094 _routes->redisplay ();
5098 if (_session->undo_depth() == 0) {
5099 undo_action->set_sensitive(false);
5101 redo_action->set_sensitive(false);
5102 begin_selection_op_history ();
5108 Editor::_idle_resize (gpointer arg)
5110 return ((Editor*)arg)->idle_resize ();
5114 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5116 if (resize_idle_id < 0) {
5117 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5118 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5119 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5121 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5122 _pending_resize_amount = 0;
5125 /* make a note of the smallest resulting height, so that we can clamp the
5126 lower limit at TimeAxisView::hSmall */
5128 int32_t min_resulting = INT32_MAX;
5130 _pending_resize_amount += h;
5131 _pending_resize_view = view;
5133 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5135 if (selection->tracks.contains (_pending_resize_view)) {
5136 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5137 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5141 if (min_resulting < 0) {
5146 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5147 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5151 /** Handle pending resizing of tracks */
5153 Editor::idle_resize ()
5155 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5157 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5158 selection->tracks.contains (_pending_resize_view)) {
5160 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5161 if (*i != _pending_resize_view) {
5162 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5167 _pending_resize_amount = 0;
5168 _group_tabs->set_dirty ();
5169 resize_idle_id = -1;
5177 ENSURE_GUI_THREAD (*this, &Editor::located);
5180 playhead_cursor->set_position (_session->audible_sample ());
5181 if (_follow_playhead && !_pending_initial_locate) {
5182 reset_x_origin_to_follow_playhead ();
5186 _pending_locate_request = false;
5187 _pending_initial_locate = false;
5188 _last_update_time = 0;
5192 Editor::region_view_added (RegionView * rv)
5194 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5196 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5197 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5198 if (rv->region()->id () == (*rnote).first) {
5199 mrv->select_notes ((*rnote).second);
5200 selection->pending_midi_note_selection.erase(rnote);
5206 _summary->set_background_dirty ();
5208 mark_region_boundary_cache_dirty ();
5212 Editor::region_view_removed ()
5214 _summary->set_background_dirty ();
5216 mark_region_boundary_cache_dirty ();
5220 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5222 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5223 if ((*j)->stripable() == s) {
5232 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5234 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5235 if ((*j)->control() == c) {
5239 TimeAxisView::Children kids = (*j)->get_child_list ();
5241 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5242 if ((*k)->control() == c) {
5252 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5256 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5257 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5267 Editor::suspend_route_redisplay ()
5270 _routes->suspend_redisplay();
5275 Editor::resume_route_redisplay ()
5278 _routes->redisplay(); // queue redisplay
5279 _routes->resume_redisplay();
5284 Editor::add_vcas (VCAList& vlist)
5288 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5289 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5292 add_stripables (sl);
5296 Editor::add_routes (RouteList& rlist)
5300 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5304 add_stripables (sl);
5308 Editor::add_stripables (StripableList& sl)
5310 list<TimeAxisView*> new_views;
5311 boost::shared_ptr<VCA> v;
5312 boost::shared_ptr<Route> r;
5313 TrackViewList new_selection;
5314 bool from_scratch = (track_views.size() == 0);
5316 sl.sort (Stripable::Sorter());
5318 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5320 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5322 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5324 new_views.push_back (vtv);
5326 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5328 if (r->is_auditioner() || r->is_monitor()) {
5332 RouteTimeAxisView* rtv;
5333 DataType dt = r->input()->default_type();
5335 if (dt == ARDOUR::DataType::AUDIO) {
5336 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5338 } else if (dt == ARDOUR::DataType::MIDI) {
5339 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5342 throw unknown_type();
5345 new_views.push_back (rtv);
5346 track_views.push_back (rtv);
5347 new_selection.push_back (rtv);
5349 rtv->effective_gain_display ();
5351 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5352 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5356 if (new_views.size() > 0) {
5357 _routes->time_axis_views_added (new_views);
5358 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5361 /* note: !new_selection.empty() means that we got some routes rather
5365 if (!from_scratch && !new_selection.empty()) {
5366 selection->set (new_selection);
5367 begin_selection_op_history();
5370 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5371 show_editor_mixer (true);
5374 editor_list_button.set_sensitive (true);
5378 Editor::timeaxisview_deleted (TimeAxisView *tv)
5380 if (tv == entered_track) {
5384 if (_session && _session->deletion_in_progress()) {
5385 /* the situation is under control */
5389 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5391 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5393 _routes->route_removed (tv);
5395 TimeAxisView::Children c = tv->get_child_list ();
5396 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5397 if (entered_track == i->get()) {
5402 /* remove it from the list of track views */
5404 TrackViewList::iterator i;
5406 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5407 i = track_views.erase (i);
5410 /* update whatever the current mixer strip is displaying, if revelant */
5412 boost::shared_ptr<Route> route;
5415 route = rtav->route ();
5418 if (current_mixer_strip && current_mixer_strip->route() == route) {
5420 TimeAxisView* next_tv;
5422 if (track_views.empty()) {
5424 } else if (i == track_views.end()) {
5425 next_tv = track_views.front();
5430 // skip VCAs (cannot be selected, n/a in editor-mixer)
5431 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5432 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5433 next_tv = track_views.front();
5435 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5436 /* just in case: no master, only a VCA remains */
5442 set_selected_mixer_strip (*next_tv);
5444 /* make the editor mixer strip go away setting the
5445 * button to inactive (which also unticks the menu option)
5448 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5454 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5460 DisplaySuspender ds;
5461 PresentationInfo::ChangeSuspender cs;
5463 if (apply_to_selection) {
5464 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5466 TrackSelection::iterator j = i;
5469 hide_track_in_display (*i, false);
5474 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5476 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5477 /* this will hide the mixer strip */
5478 set_selected_mixer_strip (*tv);
5481 _routes->hide_track_in_display (*tv);
5486 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5491 _routes->show_track_in_display (*tv);
5492 if (move_into_view) {
5493 ensure_time_axis_view_is_visible (*tv, false);
5498 Editor::sync_track_view_list_and_routes ()
5500 track_views = TrackViewList (_routes->views ());
5502 _summary->set_background_dirty();
5503 _group_tabs->set_dirty ();
5505 return false; // do not call again (until needed)
5509 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5511 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5516 /** Find a StripableTimeAxisView by the ID of its stripable */
5517 StripableTimeAxisView*
5518 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5520 StripableTimeAxisView* v;
5522 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5523 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5524 if(v->stripable()->id() == id) {
5534 Editor::fit_route_group (RouteGroup *g)
5536 TrackViewList ts = axis_views_from_routes (g->route_list ());
5541 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5543 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5546 _session->cancel_audition ();
5550 if (_session->is_auditioning()) {
5551 _session->cancel_audition ();
5552 if (r == last_audition_region) {
5557 _session->audition_region (r);
5558 last_audition_region = r;
5563 Editor::hide_a_region (boost::shared_ptr<Region> r)
5565 r->set_hidden (true);
5569 Editor::show_a_region (boost::shared_ptr<Region> r)
5571 r->set_hidden (false);
5575 Editor::audition_region_from_region_list ()
5577 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5581 Editor::hide_region_from_region_list ()
5583 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5587 Editor::show_region_in_region_list ()
5589 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5593 Editor::step_edit_status_change (bool yn)
5596 start_step_editing ();
5598 stop_step_editing ();
5603 Editor::start_step_editing ()
5605 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5609 Editor::stop_step_editing ()
5611 step_edit_connection.disconnect ();
5615 Editor::check_step_edit ()
5617 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5618 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5620 mtv->check_step_edit ();
5624 return true; // do it again, till we stop
5628 Editor::scroll_press (Direction dir)
5630 ++_scroll_callbacks;
5632 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5633 /* delay the first auto-repeat */
5639 scroll_backward (1);
5647 scroll_up_one_track ();
5651 scroll_down_one_track ();
5655 /* do hacky auto-repeat */
5656 if (!_scroll_connection.connected ()) {
5658 _scroll_connection = Glib::signal_timeout().connect (
5659 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5662 _scroll_callbacks = 0;
5669 Editor::scroll_release ()
5671 _scroll_connection.disconnect ();
5674 /** Queue a change for the Editor viewport x origin to follow the playhead */
5676 Editor::reset_x_origin_to_follow_playhead ()
5678 samplepos_t const sample = playhead_cursor->current_sample ();
5680 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5682 if (_session->transport_speed() < 0) {
5684 if (sample > (current_page_samples() / 2)) {
5685 center_screen (sample-(current_page_samples()/2));
5687 center_screen (current_page_samples()/2);
5694 if (sample < _leftmost_sample) {
5696 if (_session->transport_rolling()) {
5697 /* rolling; end up with the playhead at the right of the page */
5698 l = sample - current_page_samples ();
5700 /* not rolling: end up with the playhead 1/4 of the way along the page */
5701 l = sample - current_page_samples() / 4;
5705 if (_session->transport_rolling()) {
5706 /* rolling: end up with the playhead on the left of the page */
5709 /* not rolling: end up with the playhead 3/4 of the way along the page */
5710 l = sample - 3 * current_page_samples() / 4;
5718 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5724 Editor::super_rapid_screen_update ()
5726 if (!_session || !_session->engine().running()) {
5730 /* METERING / MIXER STRIPS */
5732 /* update track meters, if required */
5733 if (contents().is_mapped() && meters_running) {
5734 RouteTimeAxisView* rtv;
5735 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5736 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5737 rtv->fast_update ();
5742 /* and any current mixer strip */
5743 if (current_mixer_strip) {
5744 current_mixer_strip->fast_update ();
5747 bool latent_locate = false;
5748 samplepos_t sample = _session->audible_sample (&latent_locate);
5749 const int64_t now = g_get_monotonic_time ();
5752 if (_session->exporting ()) {
5753 /* freewheel/export may be faster or slower than transport_speed() / SR.
5754 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5756 _last_update_time = 0;
5759 if (!_session->transport_rolling ()) {
5760 /* Do not interpolate the playhead position; just set it */
5761 _last_update_time = 0;
5764 if (_last_update_time > 0) {
5765 /* interpolate and smoothen playhead position */
5766 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5767 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5768 err = sample - guess;
5770 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5771 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5774 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5776 err, _err_screen_engine);
5781 _err_screen_engine = 0;
5784 if (err > 8192 || latent_locate) {
5785 // in case of x-runs or freewheeling
5786 _last_update_time = 0;
5787 sample = _session->audible_sample ();
5789 _last_update_time = now;
5792 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5794 MusicSample where (sample, 0);
5795 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5796 snapped_cursor->hide ();
5797 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5798 snap_to (where); // can't use snap_to_with_modifier?
5799 snapped_cursor->set_position (where.sample);
5800 snapped_cursor->show ();
5801 } else if (_edit_point == EditAtSelectedMarker) {
5802 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5803 * however, the current editing code -does- snap so I'll draw it that way for now.
5805 if (!selection->markers.empty()) {
5806 MusicSample ms (selection->markers.front()->position(), 0);
5807 snap_to (ms); // should use snap_to_with_modifier?
5808 snapped_cursor->set_position (ms.sample);
5809 snapped_cursor->show ();
5811 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5812 snapped_cursor->show ();
5813 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5814 snapped_cursor->hide ();
5817 /* There are a few reasons why we might not update the playhead / viewport stuff:
5819 * 1. we don't update things when there's a pending locate request, otherwise
5820 * when the editor requests a locate there is a chance that this method
5821 * will move the playhead before the locate request is processed, causing
5823 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5824 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5826 if (_pending_locate_request) {
5827 _last_update_time = 0;
5831 if (_dragging_playhead) {
5832 _last_update_time = 0;
5836 if (playhead_cursor->current_sample () == sample) {
5840 playhead_cursor->set_position (sample);
5842 if (_session->requested_return_sample() >= 0) {
5843 _last_update_time = 0;
5847 if (!_follow_playhead || pending_visual_change.being_handled) {
5848 /* We only do this if we aren't already
5849 * handling a visual change (ie if
5850 * pending_visual_change.being_handled is
5851 * false) so that these requests don't stack
5852 * up there are too many of them to handle in
5858 if (!_stationary_playhead) {
5859 reset_x_origin_to_follow_playhead ();
5861 samplepos_t const sample = playhead_cursor->current_sample ();
5862 double target = ((double)sample - (double)current_page_samples() / 2.0);
5863 if (target <= 0.0) {
5866 /* compare to EditorCursor::set_position() */
5867 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5868 double const new_pos = sample_to_pixel_unrounded (target);
5869 if (rint (new_pos) != rint (old_pos)) {
5870 reset_x_origin (pixel_to_sample (new_pos));
5877 Editor::session_going_away ()
5879 _have_idled = false;
5881 _session_connections.drop_connections ();
5883 super_rapid_screen_update_connection.disconnect ();
5885 selection->clear ();
5886 cut_buffer->clear ();
5888 clicked_regionview = 0;
5889 clicked_axisview = 0;
5890 clicked_routeview = 0;
5891 entered_regionview = 0;
5893 _last_update_time = 0;
5896 playhead_cursor->hide ();
5898 /* rip everything out of the list displays */
5902 _route_groups->clear ();
5904 /* do this first so that deleting a track doesn't reset cms to null
5905 and thus cause a leak.
5908 if (current_mixer_strip) {
5909 if (current_mixer_strip->get_parent() != 0) {
5910 global_hpacker.remove (*current_mixer_strip);
5912 delete current_mixer_strip;
5913 current_mixer_strip = 0;
5916 /* delete all trackviews */
5918 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5921 track_views.clear ();
5923 nudge_clock->set_session (0);
5925 editor_list_button.set_active(false);
5926 editor_list_button.set_sensitive(false);
5928 /* clear tempo/meter rulers */
5929 remove_metric_marks ();
5930 clear_marker_display ();
5936 stop_step_editing ();
5940 /* get rid of any existing editor mixer strip */
5942 WindowTitle title(Glib::get_application_name());
5943 title += _("Editor");
5945 own_window()->set_title (title.get_string());
5948 SessionHandlePtr::session_going_away ();
5952 Editor::trigger_script (int i)
5954 LuaInstance::instance()-> call_action (i);
5958 Editor::show_editor_list (bool yn)
5961 _editor_list_vbox.show ();
5963 _editor_list_vbox.hide ();
5968 Editor::change_region_layering_order (bool from_context_menu)
5970 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5972 if (!clicked_routeview) {
5973 if (layering_order_editor) {
5974 layering_order_editor->hide ();
5979 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5985 boost::shared_ptr<Playlist> pl = track->playlist();
5991 if (layering_order_editor == 0) {
5992 layering_order_editor = new RegionLayeringOrderEditor (*this);
5995 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5996 layering_order_editor->maybe_present ();
6000 Editor::update_region_layering_order_editor ()
6002 if (layering_order_editor && layering_order_editor->is_visible ()) {
6003 change_region_layering_order (true);
6008 Editor::setup_fade_images ()
6010 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6011 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6012 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6013 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6014 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6016 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6017 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6018 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6019 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6020 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6024 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6026 Editor::action_menu_item (std::string const & name)
6028 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6031 return *manage (a->create_menu_item ());
6035 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6037 EventBox* b = manage (new EventBox);
6038 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6039 Label* l = manage (new Label (name));
6043 _the_notebook.append_page (widget, *b);
6047 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6049 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6050 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6053 if (ev->type == GDK_2BUTTON_PRESS) {
6055 /* double-click on a notebook tab shrinks or expands the notebook */
6057 if (_notebook_shrunk) {
6058 if (pre_notebook_shrink_pane_width) {
6059 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6061 _notebook_shrunk = false;
6063 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6065 /* this expands the LHS of the edit pane to cover the notebook
6066 PAGE but leaves the tabs visible.
6068 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6069 _notebook_shrunk = true;
6077 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6079 using namespace Menu_Helpers;
6081 MenuList& items = _control_point_context_menu.items ();
6084 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6085 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6086 if (!can_remove_control_point (item)) {
6087 items.back().set_sensitive (false);
6090 _control_point_context_menu.popup (event->button.button, event->button.time);
6094 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6096 using namespace Menu_Helpers;
6098 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6103 /* We need to get the selection here and pass it to the operations, since
6104 popping up the menu will cause a region leave event which clears
6105 entered_regionview. */
6107 MidiRegionView& mrv = note->region_view();
6108 const RegionSelection rs = get_regions_from_selection_and_entered ();
6109 const uint32_t sel_size = mrv.selection_size ();
6111 MenuList& items = _note_context_menu.items();
6115 items.push_back(MenuElem(_("Delete"),
6116 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6119 items.push_back(MenuElem(_("Edit..."),
6120 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6121 if (sel_size != 1) {
6122 items.back().set_sensitive (false);
6125 items.push_back(MenuElem(_("Transpose..."),
6126 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6129 items.push_back(MenuElem(_("Legatize"),
6130 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6132 items.back().set_sensitive (false);
6135 items.push_back(MenuElem(_("Quantize..."),
6136 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6138 items.push_back(MenuElem(_("Remove Overlap"),
6139 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6141 items.back().set_sensitive (false);
6144 items.push_back(MenuElem(_("Transform..."),
6145 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6147 _note_context_menu.popup (event->button.button, event->button.time);
6151 Editor::zoom_vertical_modifier_released()
6153 _stepping_axis_view = 0;
6157 Editor::ui_parameter_changed (string parameter)
6159 if (parameter == "icon-set") {
6160 while (!_cursor_stack.empty()) {
6161 _cursor_stack.pop_back();
6163 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6164 _cursor_stack.push_back(_cursors->grabber);
6165 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6166 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6168 } else if (parameter == "draggable-playhead") {
6169 if (_verbose_cursor) {
6170 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6176 Editor::use_own_window (bool and_fill_it)
6178 bool new_window = !own_window();
6180 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6182 if (win && new_window) {
6183 win->set_name ("EditorWindow");
6185 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6187 // win->signal_realize().connect (*this, &Editor::on_realize);
6188 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6189 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6190 win->set_data ("ardour-bindings", bindings);
6195 DisplaySuspender ds;
6196 contents().show_all ();
6198 /* XXX: this is a bit unfortunate; it would probably
6199 be nicer if we could just call show () above rather
6200 than needing the show_all ()
6203 /* re-hide stuff if necessary */
6204 editor_list_button_toggled ();
6205 parameter_changed ("show-summary");
6206 parameter_changed ("show-group-tabs");
6207 parameter_changed ("show-zoom-tools");
6209 /* now reset all audio_time_axis heights, because widgets might need
6215 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6216 tv = (static_cast<TimeAxisView*>(*i));
6217 tv->reset_height ();
6220 if (current_mixer_strip) {
6221 current_mixer_strip->hide_things ();
6222 current_mixer_strip->parameter_changed ("mixer-element-visibility");