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:
2165 case GridTypeTimecode:
2166 case GridTypeMinSec:
2167 case GridTypeCDFrame:
2174 Editor::grid_nonmusical() const
2176 switch (_grid_type) {
2177 case GridTypeTimecode:
2178 case GridTypeMinSec:
2179 case GridTypeCDFrame:
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 == GridTypeTimecode) {
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 == GridTypeCDFrame) {
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(true);
2273 ruler_cd_marker_action->set_active(true);
2274 ruler_samples_action->set_active(false);
2279 if (grid_musical()) {
2280 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2281 update_tempo_based_rulers ();
2284 mark_region_boundary_cache_dirty ();
2286 redisplay_grid (false);
2288 SnapChanged (); /* EMIT SIGNAL */
2292 Editor::set_snap_mode (SnapMode mode)
2294 if (internal_editing()) {
2295 internal_snap_mode = mode;
2297 pre_internal_snap_mode = mode;
2302 if (_snap_mode == SnapOff) {
2303 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2305 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2312 Editor::set_edit_point_preference (EditPoint ep, bool force)
2314 bool changed = (_edit_point != ep);
2317 if (Profile->get_mixbus())
2318 if (ep == EditAtSelectedMarker)
2319 ep = EditAtPlayhead;
2321 string str = edit_point_strings[(int)ep];
2322 if (str != edit_point_selector.get_text ()) {
2323 edit_point_selector.set_text (str);
2326 update_all_enter_cursors();
2328 if (!force && !changed) {
2332 const char* action=NULL;
2334 switch (_edit_point) {
2335 case EditAtPlayhead:
2336 action = "edit-at-playhead";
2338 case EditAtSelectedMarker:
2339 action = "edit-at-marker";
2342 action = "edit-at-mouse";
2346 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2348 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2352 bool in_track_canvas;
2354 if (!mouse_sample (foo, in_track_canvas)) {
2355 in_track_canvas = false;
2358 reset_canvas_action_sensitivity (in_track_canvas);
2359 sensitize_the_right_region_actions (false);
2365 Editor::set_state (const XMLNode& node, int version)
2368 PBD::Unwinder<bool> nsi (no_save_instant, true);
2371 Tabbable::set_state (node, version);
2374 if (_session && node.get_property ("playhead", ph_pos)) {
2376 playhead_cursor->set_position (ph_pos);
2378 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2379 playhead_cursor->set_position (0);
2382 playhead_cursor->set_position (0);
2385 node.get_property ("mixer-width", editor_mixer_strip_width);
2387 node.get_property ("zoom-focus", zoom_focus);
2388 zoom_focus_selection_done (zoom_focus);
2391 if (node.get_property ("zoom", z)) {
2392 /* older versions of ardour used floating point samples_per_pixel */
2393 reset_zoom (llrintf (z));
2395 reset_zoom (samples_per_pixel);
2399 if (node.get_property ("visible-track-count", cnt)) {
2400 set_visible_track_count (cnt);
2404 if (!node.get_property ("grid-type", grid_type)) {
2405 grid_type = _grid_type;
2407 set_grid_to (grid_type);
2410 if (node.get_property ("snap-mode", sm)) {
2411 snap_mode_selection_done(sm);
2412 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2413 * snap_mode_selection_done() will only mark an already active item as active
2414 * which does not trigger set_text().
2418 set_snap_mode (_snap_mode);
2421 node.get_property ("internal-grid-type", internal_grid_type);
2422 node.get_property ("internal-snap-mode", internal_snap_mode);
2423 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2424 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2427 if (node.get_property ("mouse-mode", mm_str)) {
2428 MouseMode m = str2mousemode(mm_str);
2429 set_mouse_mode (m, true);
2431 set_mouse_mode (MouseObject, true);
2435 if (node.get_property ("left-frame", lf_pos)) {
2439 reset_x_origin (lf_pos);
2443 if (node.get_property ("y-origin", y_origin)) {
2444 reset_y_origin (y_origin);
2447 if (node.get_property ("join-object-range", yn)) {
2448 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2450 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2451 tact->set_active (!yn);
2452 tact->set_active (yn);
2454 set_mouse_mode(mouse_mode, true);
2458 if (node.get_property ("edit-point", ep)) {
2459 set_edit_point_preference (ep, true);
2461 set_edit_point_preference (_edit_point);
2464 if (node.get_property ("follow-playhead", yn)) {
2465 set_follow_playhead (yn);
2468 if (node.get_property ("stationary-playhead", yn)) {
2469 set_stationary_playhead (yn);
2472 RegionListSortType sort_type;
2473 if (node.get_property ("region-list-sort-type", sort_type)) {
2474 _regions->reset_sort_type (sort_type, true);
2477 if (node.get_property ("show-editor-mixer", yn)) {
2479 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2482 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2484 /* do it twice to force the change */
2486 tact->set_active (!yn);
2487 tact->set_active (yn);
2490 if (node.get_property ("show-editor-list", yn)) {
2492 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2495 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 /* do it twice to force the change */
2499 tact->set_active (!yn);
2500 tact->set_active (yn);
2504 if (node.get_property (X_("editor-list-page"), el_page)) {
2505 _the_notebook.set_current_page (el_page);
2508 if (node.get_property (X_("show-marker-lines"), yn)) {
2509 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2511 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2513 tact->set_active (!yn);
2514 tact->set_active (yn);
2517 XMLNodeList children = node.children ();
2518 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2519 selection->set_state (**i, Stateful::current_state_version);
2520 _regions->set_state (**i);
2521 _locations->set_state (**i);
2524 if (node.get_property ("maximised", yn)) {
2525 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2527 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2528 bool fs = tact && tact->get_active();
2530 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2534 samplepos_t nudge_clock_value;
2535 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2536 nudge_clock->set (nudge_clock_value);
2538 nudge_clock->set_mode (AudioClock::Timecode);
2539 nudge_clock->set (_session->sample_rate() * 5, true);
2544 * Not all properties may have been in XML, but
2545 * those that are linked to a private variable may need changing
2549 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2550 yn = _follow_playhead;
2552 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2553 if (tact->get_active() != yn) {
2554 tact->set_active (yn);
2558 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2559 yn = _stationary_playhead;
2561 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2562 if (tact->get_active() != yn) {
2563 tact->set_active (yn);
2568 return LuaInstance::instance()->set_state(node);
2572 Editor::get_state ()
2574 XMLNode* node = new XMLNode (X_("Editor"));
2576 node->set_property ("id", id().to_s ());
2578 node->add_child_nocopy (Tabbable::get_state());
2580 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2581 node->set_property("notebook-shrunk", _notebook_shrunk);
2582 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2584 maybe_add_mixer_strip_width (*node);
2586 node->set_property ("zoom-focus", zoom_focus);
2588 node->set_property ("zoom", samples_per_pixel);
2589 node->set_property ("grid-type", _grid_type);
2590 node->set_property ("snap-mode", _snap_mode);
2591 node->set_property ("internal-grid-type", internal_grid_type);
2592 node->set_property ("internal-snap-mode", internal_snap_mode);
2593 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2594 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2595 node->set_property ("edit-point", _edit_point);
2596 node->set_property ("visible-track-count", _visible_track_count);
2598 node->set_property ("playhead", playhead_cursor->current_sample ());
2599 node->set_property ("left-frame", _leftmost_sample);
2600 node->set_property ("y-origin", vertical_adjustment.get_value ());
2602 node->set_property ("maximised", _maximised);
2603 node->set_property ("follow-playhead", _follow_playhead);
2604 node->set_property ("stationary-playhead", _stationary_playhead);
2605 node->set_property ("region-list-sort-type", _regions->sort_type ());
2606 node->set_property ("mouse-mode", mouse_mode);
2607 node->set_property ("join-object-range", smart_mode_action->get_active ());
2609 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2611 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2612 node->set_property (X_("show-editor-mixer"), tact->get_active());
2615 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2617 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2618 node->set_property (X_("show-editor-list"), tact->get_active());
2621 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2623 if (button_bindings) {
2624 XMLNode* bb = new XMLNode (X_("Buttons"));
2625 button_bindings->save (*bb);
2626 node->add_child_nocopy (*bb);
2629 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2631 node->add_child_nocopy (selection->get_state ());
2632 node->add_child_nocopy (_regions->get_state ());
2634 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2636 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2637 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2638 node->add_child_nocopy (_locations->get_state ());
2643 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2644 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2646 * @return pair: TimeAxisView that y is over, layer index.
2648 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2649 * in stacked or expanded region display mode, otherwise 0.
2651 std::pair<TimeAxisView *, double>
2652 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2654 if (!trackview_relative_offset) {
2655 y -= _trackview_group->canvas_origin().y;
2659 return std::make_pair ((TimeAxisView *) 0, 0);
2662 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2664 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2671 return std::make_pair ((TimeAxisView *) 0, 0);
2675 Editor::set_snapped_cursor_position (samplepos_t pos)
2677 if (_edit_point == EditAtMouse) {
2678 snapped_cursor->set_position(pos);
2683 /** Snap a position to the grid, if appropriate, taking into account current
2684 * grid settings and also the state of any snap modifier keys that may be pressed.
2685 * @param start Position to snap.
2686 * @param event Event to get current key modifier information from, or 0.
2689 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
2691 if (!_session || !event) {
2695 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2696 if (_snap_mode == SnapOff) {
2697 snap_to_internal (start, direction, pref, for_mark);
2699 start.set (start.sample, 0);
2702 if (_snap_mode != SnapOff) {
2703 snap_to_internal (start, direction, pref, for_mark);
2704 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2705 /* SnapOff, but we pressed the snap_delta modifier */
2706 snap_to_internal (start, direction, pref, for_mark);
2708 start.set (start.sample, 0);
2714 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2716 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2717 start.set (start.sample, 0);
2721 snap_to_internal (start, direction, pref, for_mark, ensure_snap);
2725 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2727 samplepos_t diff = abs (test - presnap);
2733 test = max_samplepos; // reset this so it doesn't get accidentally reused
2737 Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
2739 if (marks.empty()) return presnap;
2743 samplepos_t test = presnap;
2745 before = after = max_samplepos;
2747 /* get marks to either side of presnap */
2748 vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
2749 while (m != marks.end() && (m->position < presnap)) {
2753 if (m == marks.end ()) {
2754 /* ran out of marks */
2755 before = marks.back().position;
2758 after = m->position;
2760 if (m != marks.begin ()) {
2762 before = m->position;
2765 if (before == max_samplepos && after == max_samplepos) {
2766 /* No grid to snap to, so just don't snap */
2768 } else if (before == max_samplepos) {
2770 } else if (after == max_samplepos) {
2773 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2775 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2777 else if (direction == 0) {
2778 if ((presnap - before) < (after - presnap)) {
2790 Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
2796 _session->locations()->marks_either_side (presnap, before, after);
2798 if (before == max_samplepos && after == max_samplepos) {
2799 /* No marks to snap to, so just don't snap */
2801 } else if (before == max_samplepos) {
2803 } else if (after == max_samplepos) {
2806 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2808 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2810 } else if (direction == 0) {
2811 if ((presnap - before) < (after - presnap)) {
2823 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2825 const samplepos_t presnap = start.sample;
2827 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2828 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2829 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2831 /* check snap-to-marker */
2832 if (UIConfiguration::instance().get_snap_to_marks()) {
2837 test = marker_snap_to_internal (presnap, direction);
2838 check_best_snap(presnap, test, dist, best);
2841 /* check snap-to-region-{start/end/sync} */
2842 if (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync()) {
2843 if (!region_boundary_cache.empty()) {
2845 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2846 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2848 if (direction > 0) {
2849 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2851 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2854 if (next != region_boundary_cache.begin ()) {
2859 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2860 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2862 if (presnap > (p + n) / 2) {
2869 check_best_snap(presnap, test, dist, best);
2873 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
2874 test = snap_to_grid (grid_marks, presnap, direction);
2875 check_best_snap(presnap, test, dist, best);
2878 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
2879 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
2880 * ToDo: Perhaps this should only occur if EditPointMouse?
2882 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2884 start.set (best, 0);
2886 } else if (presnap > best) {
2887 if (presnap > (best+ snap_threshold_s)) {
2890 } else if (presnap < best) {
2891 if (presnap < (best - snap_threshold_s)) {
2896 start.set (best, 0);
2901 Editor::setup_toolbar ()
2903 HBox* mode_box = manage(new HBox);
2904 mode_box->set_border_width (2);
2905 mode_box->set_spacing(2);
2907 HBox* mouse_mode_box = manage (new HBox);
2908 HBox* mouse_mode_hbox = manage (new HBox);
2909 VBox* mouse_mode_vbox = manage (new VBox);
2910 Alignment* mouse_mode_align = manage (new Alignment);
2912 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2913 mouse_mode_size_group->add_widget (smart_mode_button);
2914 mouse_mode_size_group->add_widget (mouse_move_button);
2915 mouse_mode_size_group->add_widget (mouse_cut_button);
2916 mouse_mode_size_group->add_widget (mouse_select_button);
2917 mouse_mode_size_group->add_widget (mouse_timefx_button);
2918 mouse_mode_size_group->add_widget (mouse_audition_button);
2919 mouse_mode_size_group->add_widget (mouse_draw_button);
2920 mouse_mode_size_group->add_widget (mouse_content_button);
2922 if (!Profile->get_mixbus()) {
2923 mouse_mode_size_group->add_widget (zoom_in_button);
2924 mouse_mode_size_group->add_widget (zoom_out_button);
2925 mouse_mode_size_group->add_widget (zoom_out_full_button);
2926 mouse_mode_size_group->add_widget (zoom_focus_selector);
2927 mouse_mode_size_group->add_widget (tav_shrink_button);
2928 mouse_mode_size_group->add_widget (tav_expand_button);
2930 mouse_mode_size_group->add_widget (zoom_preset_selector);
2931 mouse_mode_size_group->add_widget (visible_tracks_selector);
2934 mouse_mode_size_group->add_widget (grid_type_selector);
2935 mouse_mode_size_group->add_widget (snap_mode_button);
2937 mouse_mode_size_group->add_widget (edit_point_selector);
2938 mouse_mode_size_group->add_widget (edit_mode_selector);
2940 mouse_mode_size_group->add_widget (*nudge_clock);
2941 mouse_mode_size_group->add_widget (nudge_forward_button);
2942 mouse_mode_size_group->add_widget (nudge_backward_button);
2944 mouse_mode_hbox->set_spacing (2);
2946 if (!ARDOUR::Profile->get_trx()) {
2947 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2950 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2951 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2953 if (!ARDOUR::Profile->get_mixbus()) {
2954 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2955 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2958 if (!ARDOUR::Profile->get_trx()) {
2959 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2960 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2961 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2964 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2966 mouse_mode_align->add (*mouse_mode_vbox);
2967 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2969 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2971 edit_mode_selector.set_name ("mouse mode button");
2973 if (!ARDOUR::Profile->get_trx()) {
2974 mode_box->pack_start (edit_mode_selector, false, false);
2975 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2976 mode_box->pack_start (edit_point_selector, false, false);
2977 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2980 mode_box->pack_start (*mouse_mode_box, false, false);
2984 _zoom_box.set_spacing (2);
2985 _zoom_box.set_border_width (2);
2989 zoom_preset_selector.set_name ("zoom button");
2990 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
2992 zoom_in_button.set_name ("zoom button");
2993 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2994 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2995 zoom_in_button.set_related_action (act);
2997 zoom_out_button.set_name ("zoom button");
2998 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2999 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3000 zoom_out_button.set_related_action (act);
3002 zoom_out_full_button.set_name ("zoom button");
3003 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3004 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3005 zoom_out_full_button.set_related_action (act);
3007 zoom_focus_selector.set_name ("zoom button");
3009 if (ARDOUR::Profile->get_mixbus()) {
3010 _zoom_box.pack_start (zoom_preset_selector, false, false);
3011 } else if (ARDOUR::Profile->get_trx()) {
3012 mode_box->pack_start (zoom_out_button, false, false);
3013 mode_box->pack_start (zoom_in_button, false, false);
3015 _zoom_box.pack_start (zoom_out_button, false, false);
3016 _zoom_box.pack_start (zoom_in_button, false, false);
3017 _zoom_box.pack_start (zoom_out_full_button, false, false);
3018 _zoom_box.pack_start (zoom_focus_selector, false, false);
3021 /* Track zoom buttons */
3022 _track_box.set_spacing (2);
3023 _track_box.set_border_width (2);
3025 visible_tracks_selector.set_name ("zoom button");
3026 if (Profile->get_mixbus()) {
3027 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3029 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3032 tav_expand_button.set_name ("zoom button");
3033 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3034 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3035 tav_expand_button.set_related_action (act);
3037 tav_shrink_button.set_name ("zoom button");
3038 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3039 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3040 tav_shrink_button.set_related_action (act);
3042 if (ARDOUR::Profile->get_mixbus()) {
3043 _track_box.pack_start (visible_tracks_selector);
3044 } else if (ARDOUR::Profile->get_trx()) {
3045 _track_box.pack_start (tav_shrink_button);
3046 _track_box.pack_start (tav_expand_button);
3048 _track_box.pack_start (visible_tracks_selector);
3049 _track_box.pack_start (tav_shrink_button);
3050 _track_box.pack_start (tav_expand_button);
3053 snap_box.set_spacing (2);
3054 snap_box.set_border_width (2);
3056 grid_type_selector.set_name ("mouse mode button");
3058 snap_mode_button.set_name ("mouse mode button");
3060 edit_point_selector.set_name ("mouse mode button");
3062 snap_box.pack_start (snap_mode_button, false, false);
3063 snap_box.pack_start (grid_type_selector, false, false);
3067 HBox *nudge_box = manage (new HBox);
3068 nudge_box->set_spacing (2);
3069 nudge_box->set_border_width (2);
3071 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3072 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3074 nudge_box->pack_start (nudge_backward_button, false, false);
3075 nudge_box->pack_start (nudge_forward_button, false, false);
3076 nudge_box->pack_start (*nudge_clock, false, false);
3079 /* Pack everything in... */
3081 toolbar_hbox.set_spacing (2);
3082 toolbar_hbox.set_border_width (2);
3084 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3085 tool_shadow->set_size_request (4, -1);
3086 tool_shadow->show();
3088 ebox_hpacker.pack_start (*tool_shadow, false, false);
3089 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3091 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3092 spacer->set_name("EditorWindow");
3093 spacer->set_size_request(-1,4);
3096 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3097 ebox_vpacker.pack_start(*spacer, false, false);
3098 ebox_vpacker.show();
3100 toolbar_hbox.pack_start (*mode_box, false, false);
3102 if (!ARDOUR::Profile->get_trx()) {
3104 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3106 toolbar_hbox.pack_start (snap_box, false, false);
3108 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3110 toolbar_hbox.pack_start (*nudge_box, false, false);
3112 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3114 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3116 toolbar_hbox.pack_end (_track_box, false, false);
3120 toolbar_hbox.show_all ();
3124 Editor::build_edit_point_menu ()
3126 using namespace Menu_Helpers;
3128 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3129 if(!Profile->get_mixbus())
3130 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3131 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3133 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3137 Editor::build_edit_mode_menu ()
3139 using namespace Menu_Helpers;
3141 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3142 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3143 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3144 /* Note: Splice was removed */
3146 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3150 Editor::build_grid_type_menu ()
3152 using namespace Menu_Helpers;
3154 /* main grid: bars, quarter-notes, etc */
3155 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3156 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3157 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3158 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3159 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3160 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3161 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3162 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3165 grid_type_selector.AddMenuElem(SeparatorElem());
3166 Gtk::Menu *_triplet_menu = manage (new Menu);
3167 MenuList& triplet_items (_triplet_menu->items());
3169 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3170 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3171 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3172 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3174 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3176 /* quintuplet grid */
3177 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3178 MenuList& quintuplet_items (_quintuplet_menu->items());
3180 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3181 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3182 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3184 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3186 /* septuplet grid */
3187 Gtk::Menu *_septuplet_menu = manage (new Menu);
3188 MenuList& septuplet_items (_septuplet_menu->items());
3190 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3191 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3192 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3194 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3196 grid_type_selector.AddMenuElem(SeparatorElem());
3197 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3198 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3199 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3201 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
3205 Editor::setup_tooltips ()
3207 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3208 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3209 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3210 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3211 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3212 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3213 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3214 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3215 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3216 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3217 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3218 set_tooltip (zoom_in_button, _("Zoom In"));
3219 set_tooltip (zoom_out_button, _("Zoom Out"));
3220 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3221 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3222 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3223 set_tooltip (tav_expand_button, _("Expand Tracks"));
3224 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3225 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3226 set_tooltip (grid_type_selector, _("Grid Mode"));
3227 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3228 set_tooltip (edit_point_selector, _("Edit Point"));
3229 set_tooltip (edit_mode_selector, _("Edit Mode"));
3230 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3234 Editor::convert_drop_to_paths (
3235 vector<string>& paths,
3236 const RefPtr<Gdk::DragContext>& /*context*/,
3239 const SelectionData& data,
3243 if (_session == 0) {
3247 vector<string> uris = data.get_uris();
3251 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3252 are actually URI lists. So do it by hand.
3255 if (data.get_target() != "text/plain") {
3259 /* Parse the "uri-list" format that Nautilus provides,
3260 where each pathname is delimited by \r\n.
3262 THERE MAY BE NO NULL TERMINATING CHAR!!!
3265 string txt = data.get_text();
3269 p = (char *) malloc (txt.length() + 1);
3270 txt.copy (p, txt.length(), 0);
3271 p[txt.length()] = '\0';
3277 while (g_ascii_isspace (*p))
3281 while (*q && (*q != '\n') && (*q != '\r')) {
3288 while (q > p && g_ascii_isspace (*q))
3293 uris.push_back (string (p, q - p + 1));
3297 p = strchr (p, '\n');
3309 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3310 if ((*i).substr (0,7) == "file://") {
3311 paths.push_back (Glib::filename_from_uri (*i));
3319 Editor::new_tempo_section ()
3324 Editor::map_transport_state ()
3326 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3328 if (_session && _session->transport_stopped()) {
3329 have_pending_keyboard_selection = false;
3332 update_loop_range_view ();
3336 Editor::transport_looped ()
3338 /* reset Playhead position interpolation.
3339 * see Editor::super_rapid_screen_update
3341 _last_update_time = 0;
3347 Editor::begin_selection_op_history ()
3349 selection_op_cmd_depth = 0;
3350 selection_op_history_it = 0;
3352 while(!selection_op_history.empty()) {
3353 delete selection_op_history.front();
3354 selection_op_history.pop_front();
3357 selection_undo_action->set_sensitive (false);
3358 selection_redo_action->set_sensitive (false);
3359 selection_op_history.push_front (&_selection_memento->get_state ());
3363 Editor::begin_reversible_selection_op (string name)
3366 //cerr << name << endl;
3367 /* begin/commit pairs can be nested */
3368 selection_op_cmd_depth++;
3373 Editor::commit_reversible_selection_op ()
3376 if (selection_op_cmd_depth == 1) {
3378 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3379 /* The user has undone some selection ops and then made a new one,
3380 * making anything earlier in the list invalid.
3383 list<XMLNode *>::iterator it = selection_op_history.begin();
3384 list<XMLNode *>::iterator e_it = it;
3385 advance (e_it, selection_op_history_it);
3387 for (; it != e_it; ++it) {
3390 selection_op_history.erase (selection_op_history.begin(), e_it);
3393 selection_op_history.push_front (&_selection_memento->get_state ());
3394 selection_op_history_it = 0;
3396 selection_undo_action->set_sensitive (true);
3397 selection_redo_action->set_sensitive (false);
3400 if (selection_op_cmd_depth > 0) {
3401 selection_op_cmd_depth--;
3407 Editor::undo_selection_op ()
3410 selection_op_history_it++;
3412 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3413 if (n == selection_op_history_it) {
3414 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3415 selection_redo_action->set_sensitive (true);
3419 /* is there an earlier entry? */
3420 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3421 selection_undo_action->set_sensitive (false);
3427 Editor::redo_selection_op ()
3430 if (selection_op_history_it > 0) {
3431 selection_op_history_it--;
3434 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3435 if (n == selection_op_history_it) {
3436 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3437 selection_undo_action->set_sensitive (true);
3442 if (selection_op_history_it == 0) {
3443 selection_redo_action->set_sensitive (false);
3449 Editor::begin_reversible_command (string name)
3452 before.push_back (&_selection_memento->get_state ());
3453 _session->begin_reversible_command (name);
3458 Editor::begin_reversible_command (GQuark q)
3461 before.push_back (&_selection_memento->get_state ());
3462 _session->begin_reversible_command (q);
3467 Editor::abort_reversible_command ()
3470 while(!before.empty()) {
3471 delete before.front();
3474 _session->abort_reversible_command ();
3479 Editor::commit_reversible_command ()
3482 if (before.size() == 1) {
3483 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3484 redo_action->set_sensitive(false);
3485 undo_action->set_sensitive(true);
3486 begin_selection_op_history ();
3489 if (before.empty()) {
3490 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3495 _session->commit_reversible_command ();
3500 Editor::history_changed ()
3504 if (undo_action && _session) {
3505 if (_session->undo_depth() == 0) {
3506 label = S_("Command|Undo");
3508 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3510 undo_action->property_label() = label;
3513 if (redo_action && _session) {
3514 if (_session->redo_depth() == 0) {
3516 redo_action->set_sensitive (false);
3518 label = string_compose(_("Redo (%1)"), _session->next_redo());
3519 redo_action->set_sensitive (true);
3521 redo_action->property_label() = label;
3526 Editor::duplicate_range (bool with_dialog)
3530 RegionSelection rs = get_regions_from_selection_and_entered ();
3532 if (selection->time.length() == 0 && rs.empty()) {
3538 ArdourDialog win (_("Duplicate"));
3539 Label label (_("Number of duplications:"));
3540 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3541 SpinButton spinner (adjustment, 0.0, 1);
3544 win.get_vbox()->set_spacing (12);
3545 win.get_vbox()->pack_start (hbox);
3546 hbox.set_border_width (6);
3547 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3549 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3550 place, visually. so do this by hand.
3553 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3554 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3555 spinner.grab_focus();
3561 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3562 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3563 win.set_default_response (RESPONSE_ACCEPT);
3565 spinner.grab_focus ();
3567 switch (win.run ()) {
3568 case RESPONSE_ACCEPT:
3574 times = adjustment.get_value();
3577 if ((current_mouse_mode() == MouseRange)) {
3578 if (selection->time.length()) {
3579 duplicate_selection (times);
3581 } else if (get_smart_mode()) {
3582 if (selection->time.length()) {
3583 duplicate_selection (times);
3585 duplicate_some_regions (rs, times);
3587 duplicate_some_regions (rs, times);
3592 Editor::set_edit_mode (EditMode m)
3594 Config->set_edit_mode (m);
3598 Editor::cycle_edit_mode ()
3600 switch (Config->get_edit_mode()) {
3602 Config->set_edit_mode (Ripple);
3606 Config->set_edit_mode (Lock);
3609 Config->set_edit_mode (Slide);
3615 Editor::edit_mode_selection_done (EditMode m)
3617 Config->set_edit_mode (m);
3621 Editor::grid_type_selection_done (GridType gridtype)
3623 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3625 ract->set_active ();
3630 Editor::snap_mode_selection_done (SnapMode mode)
3632 RefPtr<RadioAction> ract = snap_mode_action (mode);
3635 ract->set_active (true);
3640 Editor::cycle_edit_point (bool with_marker)
3642 if(Profile->get_mixbus())
3643 with_marker = false;
3645 switch (_edit_point) {
3647 set_edit_point_preference (EditAtPlayhead);
3649 case EditAtPlayhead:
3651 set_edit_point_preference (EditAtSelectedMarker);
3653 set_edit_point_preference (EditAtMouse);
3656 case EditAtSelectedMarker:
3657 set_edit_point_preference (EditAtMouse);
3663 Editor::edit_point_selection_done (EditPoint ep)
3665 set_edit_point_preference (ep);
3669 Editor::build_zoom_focus_menu ()
3671 using namespace Menu_Helpers;
3673 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3674 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3675 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3676 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3677 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3678 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3680 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3684 Editor::zoom_focus_selection_done (ZoomFocus f)
3686 RefPtr<RadioAction> ract = zoom_focus_action (f);
3688 ract->set_active ();
3693 Editor::build_track_count_menu ()
3695 using namespace Menu_Helpers;
3697 if (!Profile->get_mixbus()) {
3698 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3699 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3700 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3709 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3723 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3724 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3725 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3731 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3732 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3733 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3734 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3739 Editor::set_zoom_preset (int64_t ms)
3742 temporal_zoom_session();
3746 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3747 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3751 Editor::set_visible_track_count (int32_t n)
3753 _visible_track_count = n;
3755 /* if the canvas hasn't really been allocated any size yet, just
3756 record the desired number of visible tracks and return. when canvas
3757 allocation happens, we will get called again and then we can do the
3761 if (_visible_canvas_height <= 1) {
3767 DisplaySuspender ds;
3769 if (_visible_track_count > 0) {
3770 h = trackviews_height() / _visible_track_count;
3771 std::ostringstream s;
3772 s << _visible_track_count;
3774 } else if (_visible_track_count == 0) {
3776 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3777 if ((*i)->marked_for_display()) {
3779 TimeAxisView::Children cl ((*i)->get_child_list ());
3780 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3781 if ((*j)->marked_for_display()) {
3788 visible_tracks_selector.set_text (X_("*"));
3791 h = trackviews_height() / n;
3794 /* negative value means that the visible track count has
3795 been overridden by explicit track height changes.
3797 visible_tracks_selector.set_text (X_("*"));
3801 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3802 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3805 if (str != visible_tracks_selector.get_text()) {
3806 visible_tracks_selector.set_text (str);
3811 Editor::override_visible_track_count ()
3813 _visible_track_count = -1;
3814 visible_tracks_selector.set_text (_("*"));
3818 Editor::edit_controls_button_release (GdkEventButton* ev)
3820 if (Keyboard::is_context_menu_event (ev)) {
3821 ARDOUR_UI::instance()->add_route ();
3822 } else if (ev->button == 1) {
3823 selection->clear_tracks ();
3830 Editor::mouse_select_button_release (GdkEventButton* ev)
3832 /* this handles just right-clicks */
3834 if (ev->button != 3) {
3842 Editor::set_zoom_focus (ZoomFocus f)
3844 string str = zoom_focus_strings[(int)f];
3846 if (str != zoom_focus_selector.get_text()) {
3847 zoom_focus_selector.set_text (str);
3850 if (zoom_focus != f) {
3857 Editor::cycle_zoom_focus ()
3859 switch (zoom_focus) {
3861 set_zoom_focus (ZoomFocusRight);
3863 case ZoomFocusRight:
3864 set_zoom_focus (ZoomFocusCenter);
3866 case ZoomFocusCenter:
3867 set_zoom_focus (ZoomFocusPlayhead);
3869 case ZoomFocusPlayhead:
3870 set_zoom_focus (ZoomFocusMouse);
3872 case ZoomFocusMouse:
3873 set_zoom_focus (ZoomFocusEdit);
3876 set_zoom_focus (ZoomFocusLeft);
3882 Editor::update_grid ()
3884 if (grid_musical()) {
3885 std::vector<TempoMap::BBTPoint> grid;
3886 if (bbt_ruler_scale != bbt_show_many) {
3887 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3889 maybe_draw_grid_lines ();
3890 } else if (grid_nonmusical()) {
3891 maybe_draw_grid_lines ();
3898 Editor::toggle_follow_playhead ()
3900 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3902 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3903 set_follow_playhead (tact->get_active());
3907 /** @param yn true to follow playhead, otherwise false.
3908 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3911 Editor::set_follow_playhead (bool yn, bool catch_up)
3913 if (_follow_playhead != yn) {
3914 if ((_follow_playhead = yn) == true && catch_up) {
3916 reset_x_origin_to_follow_playhead ();
3923 Editor::toggle_stationary_playhead ()
3925 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3927 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3928 set_stationary_playhead (tact->get_active());
3933 Editor::set_stationary_playhead (bool yn)
3935 if (_stationary_playhead != yn) {
3936 if ((_stationary_playhead = yn) == true) {
3937 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
3938 // update_current_screen ();
3945 Editor::playlist_selector () const
3947 return *_playlist_selector;
3951 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
3953 if (paste_count == 0) {
3954 /* don't bother calculating an offset that will be zero anyway */
3958 /* calculate basic unsnapped multi-paste offset */
3959 samplecnt_t offset = paste_count * duration;
3961 /* snap offset so pos + offset is aligned to the grid */
3962 MusicSample offset_pos (pos + offset, 0);
3963 snap_to(offset_pos, RoundUpMaybe);
3964 offset = offset_pos.sample - pos;
3970 Editor::get_grid_beat_divisions(samplepos_t position)
3972 switch (_grid_type) {
3973 case GridTypeBeatDiv32: return 32;
3974 case GridTypeBeatDiv28: return 28;
3975 case GridTypeBeatDiv24: return 24;
3976 case GridTypeBeatDiv20: return 20;
3977 case GridTypeBeatDiv16: return 16;
3978 case GridTypeBeatDiv14: return 14;
3979 case GridTypeBeatDiv12: return 12;
3980 case GridTypeBeatDiv10: return 10;
3981 case GridTypeBeatDiv8: return 8;
3982 case GridTypeBeatDiv7: return 7;
3983 case GridTypeBeatDiv6: return 6;
3984 case GridTypeBeatDiv5: return 5;
3985 case GridTypeBeatDiv4: return 4;
3986 case GridTypeBeatDiv3: return 3;
3987 case GridTypeBeatDiv2: return 2;
3989 case GridTypeNone: return 0;
3990 case GridTypeTimecode: return 0;
3991 case GridTypeMinSec: return 0;
3992 case GridTypeCDFrame: return 0;
3998 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
3999 if the grid is non-musical, returns 0.
4000 if the grid is snapped to bars, returns -1.
4001 @param event_state the current keyboard modifier mask.
4004 Editor::get_grid_music_divisions (uint32_t event_state)
4006 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4010 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4014 switch (_grid_type) {
4015 case GridTypeBeatDiv32: return 32;
4016 case GridTypeBeatDiv28: return 28;
4017 case GridTypeBeatDiv24: return 24;
4018 case GridTypeBeatDiv20: return 20;
4019 case GridTypeBeatDiv16: return 16;
4020 case GridTypeBeatDiv14: return 14;
4021 case GridTypeBeatDiv12: return 12;
4022 case GridTypeBeatDiv10: return 10;
4023 case GridTypeBeatDiv8: return 8;
4024 case GridTypeBeatDiv7: return 7;
4025 case GridTypeBeatDiv6: return 6;
4026 case GridTypeBeatDiv5: return 5;
4027 case GridTypeBeatDiv4: return 4;
4028 case GridTypeBeatDiv3: return 3;
4029 case GridTypeBeatDiv2: return 2;
4030 case GridTypeBeat: return 1;
4031 case GridTypeBar : return -1;
4033 case GridTypeNone: return 0;
4034 case GridTypeTimecode: return 0;
4035 case GridTypeMinSec: return 0;
4036 case GridTypeCDFrame: return 0;
4042 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4046 const unsigned divisions = get_grid_beat_divisions(position);
4048 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4051 switch (_grid_type) {
4053 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4056 const Meter& m = _session->tempo_map().meter_at_sample (position);
4057 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4065 return Temporal::Beats();
4069 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4073 ret = nudge_clock->current_duration (pos);
4074 next = ret + 1; /* XXXX fix me */
4080 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4082 ArdourDialog dialog (_("Playlist Deletion"));
4083 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4084 "If it is kept, its audio files will not be cleaned.\n"
4085 "If it is deleted, audio files used by it alone will be cleaned."),
4088 dialog.set_position (WIN_POS_CENTER);
4089 dialog.get_vbox()->pack_start (label);
4093 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4094 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4095 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4096 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4097 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4099 /* by default gtk uses the left most button */
4100 keep->grab_focus ();
4102 switch (dialog.run ()) {
4104 /* keep this and all remaining ones */
4109 /* delete this and all others */
4113 case RESPONSE_ACCEPT:
4114 /* delete the playlist */
4118 case RESPONSE_REJECT:
4119 /* keep the playlist */
4131 Editor::audio_region_selection_covers (samplepos_t where)
4133 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4134 if ((*a)->region()->covers (where)) {
4143 Editor::prepare_for_cleanup ()
4145 cut_buffer->clear_regions ();
4146 cut_buffer->clear_playlists ();
4148 selection->clear_regions ();
4149 selection->clear_playlists ();
4151 _regions->suspend_redisplay ();
4155 Editor::finish_cleanup ()
4157 _regions->resume_redisplay ();
4161 Editor::transport_loop_location()
4164 return _session->locations()->auto_loop_location();
4171 Editor::transport_punch_location()
4174 return _session->locations()->auto_punch_location();
4181 Editor::control_layout_scroll (GdkEventScroll* ev)
4183 /* Just forward to the normal canvas scroll method. The coordinate
4184 systems are different but since the canvas is always larger than the
4185 track headers, and aligned with the trackview area, this will work.
4187 In the not too distant future this layout is going away anyway and
4188 headers will be on the canvas.
4190 return canvas_scroll_event (ev, false);
4194 Editor::session_state_saved (string)
4197 _snapshots->redisplay ();
4201 Editor::maximise_editing_space ()
4207 Gtk::Window* toplevel = current_toplevel();
4210 toplevel->fullscreen ();
4216 Editor::restore_editing_space ()
4222 Gtk::Window* toplevel = current_toplevel();
4225 toplevel->unfullscreen();
4231 * Make new playlists for a given track and also any others that belong
4232 * to the same active route group with the `select' property.
4237 Editor::new_playlists (TimeAxisView* v)
4239 begin_reversible_command (_("new playlists"));
4240 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4241 _session->playlists->get (playlists);
4242 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4243 commit_reversible_command ();
4247 * Use a copy of the current playlist for a given track and also any others that belong
4248 * to the same active route group with the `select' property.
4253 Editor::copy_playlists (TimeAxisView* v)
4255 begin_reversible_command (_("copy playlists"));
4256 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4257 _session->playlists->get (playlists);
4258 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4259 commit_reversible_command ();
4262 /** Clear the current playlist for a given track and also any others that belong
4263 * to the same active route group with the `select' property.
4268 Editor::clear_playlists (TimeAxisView* v)
4270 begin_reversible_command (_("clear playlists"));
4271 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4272 _session->playlists->get (playlists);
4273 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4274 commit_reversible_command ();
4278 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4280 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4284 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4286 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4290 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4292 atv.clear_playlist ();
4296 Editor::get_y_origin () const
4298 return vertical_adjustment.get_value ();
4301 /** Queue up a change to the viewport x origin.
4302 * @param sample New x origin.
4305 Editor::reset_x_origin (samplepos_t sample)
4307 pending_visual_change.add (VisualChange::TimeOrigin);
4308 pending_visual_change.time_origin = sample;
4309 ensure_visual_change_idle_handler ();
4313 Editor::reset_y_origin (double y)
4315 pending_visual_change.add (VisualChange::YOrigin);
4316 pending_visual_change.y_origin = y;
4317 ensure_visual_change_idle_handler ();
4321 Editor::reset_zoom (samplecnt_t spp)
4323 if (spp == samples_per_pixel) {
4327 pending_visual_change.add (VisualChange::ZoomLevel);
4328 pending_visual_change.samples_per_pixel = spp;
4329 ensure_visual_change_idle_handler ();
4333 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4335 reset_x_origin (sample);
4338 if (!no_save_visual) {
4339 undo_visual_stack.push_back (current_visual_state(false));
4343 Editor::VisualState::VisualState (bool with_tracks)
4344 : gui_state (with_tracks ? new GUIObjectState : 0)
4348 Editor::VisualState::~VisualState ()
4353 Editor::VisualState*
4354 Editor::current_visual_state (bool with_tracks)
4356 VisualState* vs = new VisualState (with_tracks);
4357 vs->y_position = vertical_adjustment.get_value();
4358 vs->samples_per_pixel = samples_per_pixel;
4359 vs->_leftmost_sample = _leftmost_sample;
4360 vs->zoom_focus = zoom_focus;
4363 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4370 Editor::undo_visual_state ()
4372 if (undo_visual_stack.empty()) {
4376 VisualState* vs = undo_visual_stack.back();
4377 undo_visual_stack.pop_back();
4380 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4383 use_visual_state (*vs);
4388 Editor::redo_visual_state ()
4390 if (redo_visual_stack.empty()) {
4394 VisualState* vs = redo_visual_stack.back();
4395 redo_visual_stack.pop_back();
4397 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4398 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4401 use_visual_state (*vs);
4406 Editor::swap_visual_state ()
4408 if (undo_visual_stack.empty()) {
4409 redo_visual_state ();
4411 undo_visual_state ();
4416 Editor::use_visual_state (VisualState& vs)
4418 PBD::Unwinder<bool> nsv (no_save_visual, true);
4419 DisplaySuspender ds;
4421 vertical_adjustment.set_value (vs.y_position);
4423 set_zoom_focus (vs.zoom_focus);
4424 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4427 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4429 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4430 (*i)->clear_property_cache();
4431 (*i)->reset_visual_state ();
4435 _routes->update_visibility ();
4438 /** This is the core function that controls the zoom level of the canvas. It is called
4439 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4440 * @param spp new number of samples per pixel
4443 Editor::set_samples_per_pixel (samplecnt_t spp)
4449 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4450 const samplecnt_t lots_of_pixels = 4000;
4452 /* if the zoom level is greater than what you'd get trying to display 3
4453 * days of audio on a really big screen, then it's too big.
4456 if (spp * lots_of_pixels > three_days) {
4460 samples_per_pixel = spp;
4464 Editor::on_samples_per_pixel_changed ()
4466 bool const showing_time_selection = selection->time.length() > 0;
4468 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4469 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4470 (*i)->reshow_selection (selection->time);
4474 ZoomChanged (); /* EMIT_SIGNAL */
4476 ArdourCanvas::GtkCanvasViewport* c;
4478 c = get_track_canvas();
4480 c->canvas()->zoomed ();
4483 if (playhead_cursor) {
4484 playhead_cursor->set_position (playhead_cursor->current_sample ());
4487 refresh_location_display();
4488 _summary->set_overlays_dirty ();
4490 update_marker_labels ();
4496 Editor::playhead_cursor_sample () const
4498 return playhead_cursor->current_sample();
4502 Editor::queue_visual_videotimeline_update ()
4504 pending_visual_change.add (VisualChange::VideoTimeline);
4505 ensure_visual_change_idle_handler ();
4509 Editor::ensure_visual_change_idle_handler ()
4511 if (pending_visual_change.idle_handler_id < 0) {
4512 /* see comment in add_to_idle_resize above. */
4513 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4514 pending_visual_change.being_handled = false;
4519 Editor::_idle_visual_changer (void* arg)
4521 return static_cast<Editor*>(arg)->idle_visual_changer ();
4525 Editor::pre_render ()
4527 visual_change_queued = false;
4529 if (pending_visual_change.pending != 0) {
4530 ensure_visual_change_idle_handler();
4535 Editor::idle_visual_changer ()
4537 pending_visual_change.idle_handler_id = -1;
4539 if (pending_visual_change.pending == 0) {
4543 /* set_horizontal_position() below (and maybe other calls) call
4544 gtk_main_iteration(), so it's possible that a signal will be handled
4545 half-way through this method. If this signal wants an
4546 idle_visual_changer we must schedule another one after this one, so
4547 mark the idle_handler_id as -1 here to allow that. Also make a note
4548 that we are doing the visual change, so that changes in response to
4549 super-rapid-screen-update can be dropped if we are still processing
4553 if (visual_change_queued) {
4557 pending_visual_change.being_handled = true;
4559 VisualChange vc = pending_visual_change;
4561 pending_visual_change.pending = (VisualChange::Type) 0;
4563 visual_changer (vc);
4565 pending_visual_change.being_handled = false;
4567 visual_change_queued = true;
4569 return 0; /* this is always a one-shot call */
4573 Editor::visual_changer (const VisualChange& vc)
4576 * Changed first so the correct horizontal canvas position is calculated in
4577 * Editor::set_horizontal_position
4579 if (vc.pending & VisualChange::ZoomLevel) {
4580 set_samples_per_pixel (vc.samples_per_pixel);
4583 if (vc.pending & VisualChange::TimeOrigin) {
4584 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4585 set_horizontal_position (new_time_origin);
4588 if (vc.pending & VisualChange::YOrigin) {
4589 vertical_adjustment.set_value (vc.y_origin);
4593 * Now the canvas is in the final state before render the canvas items that
4594 * support the Item::prepare_for_render interface can calculate the correct
4595 * item to visible canvas intersection.
4597 if (vc.pending & VisualChange::ZoomLevel) {
4598 on_samples_per_pixel_changed ();
4600 compute_fixed_ruler_scale ();
4602 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4603 update_tempo_based_rulers ();
4606 if (!(vc.pending & VisualChange::ZoomLevel)) {
4607 /* If the canvas is not being zoomed then the canvas items will not change
4608 * and cause Item::prepare_for_render to be called so do it here manually.
4609 * Not ideal, but I can't think of a better solution atm.
4611 _track_canvas->prepare_for_render();
4614 /* If we are only scrolling vertically there is no need to update these */
4615 if (vc.pending != VisualChange::YOrigin) {
4616 update_fixed_rulers ();
4617 redisplay_grid (true);
4619 /* video frames & position need to be updated for zoom, horiz-scroll
4620 * and (explicitly) VisualChange::VideoTimeline.
4622 update_video_timeline();
4625 _summary->set_overlays_dirty ();
4628 struct EditorOrderTimeAxisSorter {
4629 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4630 return a->order () < b->order ();
4635 Editor::sort_track_selection (TrackViewList& sel)
4637 EditorOrderTimeAxisSorter cmp;
4642 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4645 samplepos_t where = 0;
4646 EditPoint ep = _edit_point;
4648 if (Profile->get_mixbus()) {
4649 if (ep == EditAtSelectedMarker) {
4650 ep = EditAtPlayhead;
4654 if (from_outside_canvas && (ep == EditAtMouse)) {
4655 ep = EditAtPlayhead;
4656 } else if (from_context_menu && (ep == EditAtMouse)) {
4657 return canvas_event_sample (&context_click_event, 0, 0);
4660 if (entered_marker) {
4661 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4662 return entered_marker->position();
4665 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4666 ep = EditAtSelectedMarker;
4669 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4670 ep = EditAtPlayhead;
4673 MusicSample snap_mf (0, 0);
4676 case EditAtPlayhead:
4677 if (_dragging_playhead) {
4678 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4679 where = playhead_cursor->current_sample();
4681 where = _session->audible_sample();
4683 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4686 case EditAtSelectedMarker:
4687 if (!selection->markers.empty()) {
4689 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4692 where = loc->start();
4696 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4704 if (!mouse_sample (where, ignored)) {
4705 /* XXX not right but what can we do ? */
4708 snap_mf.sample = where;
4710 where = snap_mf.sample;
4711 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4719 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4721 if (!_session) return;
4723 begin_reversible_command (cmd);
4727 if ((tll = transport_loop_location()) == 0) {
4728 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4729 XMLNode &before = _session->locations()->get_state();
4730 _session->locations()->add (loc, true);
4731 _session->set_auto_loop_location (loc);
4732 XMLNode &after = _session->locations()->get_state();
4733 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4735 XMLNode &before = tll->get_state();
4736 tll->set_hidden (false, this);
4737 tll->set (start, end);
4738 XMLNode &after = tll->get_state();
4739 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4742 commit_reversible_command ();
4746 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4748 if (!_session) return;
4750 begin_reversible_command (cmd);
4754 if ((tpl = transport_punch_location()) == 0) {
4755 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4756 XMLNode &before = _session->locations()->get_state();
4757 _session->locations()->add (loc, true);
4758 _session->set_auto_punch_location (loc);
4759 XMLNode &after = _session->locations()->get_state();
4760 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4762 XMLNode &before = tpl->get_state();
4763 tpl->set_hidden (false, this);
4764 tpl->set (start, end);
4765 XMLNode &after = tpl->get_state();
4766 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4769 commit_reversible_command ();
4772 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4773 * @param rs List to which found regions are added.
4774 * @param where Time to look at.
4775 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4778 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4780 const TrackViewList* tracks;
4783 tracks = &track_views;
4788 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4790 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4793 boost::shared_ptr<Track> tr;
4794 boost::shared_ptr<Playlist> pl;
4796 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4798 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4800 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4801 RegionView* rv = rtv->view()->find_view (*i);
4812 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4814 const TrackViewList* tracks;
4817 tracks = &track_views;
4822 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4823 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4825 boost::shared_ptr<Track> tr;
4826 boost::shared_ptr<Playlist> pl;
4828 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4830 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4832 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4834 RegionView* rv = rtv->view()->find_view (*i);
4845 /** Get regions using the following method:
4847 * Make a region list using:
4848 * (a) any selected regions
4849 * (b) the intersection of any selected tracks and the edit point(*)
4850 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4852 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4854 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4858 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4860 RegionSelection regions;
4862 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4863 regions.add (entered_regionview);
4865 regions = selection->regions;
4868 if (regions.empty()) {
4869 TrackViewList tracks = selection->tracks;
4871 if (!tracks.empty()) {
4872 /* no region selected or entered, but some selected tracks:
4873 * act on all regions on the selected tracks at the edit point
4875 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4876 get_regions_at(regions, where, tracks);
4883 /** Get regions using the following method:
4885 * Make a region list using:
4886 * (a) any selected regions
4887 * (b) the intersection of any selected tracks and the edit point(*)
4888 * (c) if neither exists, then whatever region is under the mouse
4890 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4892 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4895 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4897 RegionSelection regions;
4899 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4900 regions.add (entered_regionview);
4902 regions = selection->regions;
4905 if (regions.empty()) {
4906 TrackViewList tracks = selection->tracks;
4908 if (!tracks.empty()) {
4909 /* no region selected or entered, but some selected tracks:
4910 * act on all regions on the selected tracks at the edit point
4912 get_regions_at(regions, pos, tracks);
4919 /** Start with regions that are selected, or the entered regionview if none are selected.
4920 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4921 * of the regions that we started with.
4925 Editor::get_regions_from_selection_and_entered () const
4927 RegionSelection regions = selection->regions;
4929 if (regions.empty() && entered_regionview) {
4930 regions.add (entered_regionview);
4937 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4939 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4940 RouteTimeAxisView* rtav;
4942 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4943 boost::shared_ptr<Playlist> pl;
4944 std::vector<boost::shared_ptr<Region> > results;
4945 boost::shared_ptr<Track> tr;
4947 if ((tr = rtav->track()) == 0) {
4952 if ((pl = (tr->playlist())) != 0) {
4953 boost::shared_ptr<Region> r = pl->region_by_id (id);
4955 RegionView* rv = rtav->view()->find_view (r);
4957 regions.push_back (rv);
4966 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4969 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4970 MidiTimeAxisView* mtav;
4972 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4974 mtav->get_per_region_note_selection (selection);
4981 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4983 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4985 RouteTimeAxisView* tatv;
4987 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4989 boost::shared_ptr<Playlist> pl;
4990 vector<boost::shared_ptr<Region> > results;
4992 boost::shared_ptr<Track> tr;
4994 if ((tr = tatv->track()) == 0) {
4999 if ((pl = (tr->playlist())) != 0) {
5000 if (src_comparison) {
5001 pl->get_source_equivalent_regions (region, results);
5003 pl->get_region_list_equivalent_regions (region, results);
5007 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5008 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5009 regions.push_back (marv);
5018 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5020 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5021 RouteTimeAxisView* tatv;
5022 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5023 if (!tatv->track()) {
5026 RegionView* marv = tatv->view()->find_view (region);
5036 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5038 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5039 RouteTimeAxisView* rtav;
5040 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5041 if (rtav->route() == route) {
5050 Editor::show_rhythm_ferret ()
5052 if (rhythm_ferret == 0) {
5053 rhythm_ferret = new RhythmFerret(*this);
5056 rhythm_ferret->set_session (_session);
5057 rhythm_ferret->show ();
5058 rhythm_ferret->present ();
5062 Editor::first_idle ()
5064 MessageDialog* dialog = 0;
5066 if (track_views.size() > 1) {
5067 Timers::TimerSuspender t;
5068 dialog = new MessageDialog (
5069 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5073 ARDOUR_UI::instance()->flush_pending (60);
5076 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5080 /* now that all regionviews should exist, setup region selection */
5084 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5085 /* this is cumulative: rs is NOT cleared each time */
5086 get_regionviews_by_id (*pr, rs);
5089 selection->set (rs);
5091 /* first idle adds route children (automation tracks), so we need to redisplay here */
5092 _routes->redisplay ();
5096 if (_session->undo_depth() == 0) {
5097 undo_action->set_sensitive(false);
5099 redo_action->set_sensitive(false);
5100 begin_selection_op_history ();
5106 Editor::_idle_resize (gpointer arg)
5108 return ((Editor*)arg)->idle_resize ();
5112 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5114 if (resize_idle_id < 0) {
5115 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5116 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5117 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5119 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5120 _pending_resize_amount = 0;
5123 /* make a note of the smallest resulting height, so that we can clamp the
5124 lower limit at TimeAxisView::hSmall */
5126 int32_t min_resulting = INT32_MAX;
5128 _pending_resize_amount += h;
5129 _pending_resize_view = view;
5131 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5133 if (selection->tracks.contains (_pending_resize_view)) {
5134 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5135 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5139 if (min_resulting < 0) {
5144 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5145 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5149 /** Handle pending resizing of tracks */
5151 Editor::idle_resize ()
5153 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5155 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5156 selection->tracks.contains (_pending_resize_view)) {
5158 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5159 if (*i != _pending_resize_view) {
5160 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5165 _pending_resize_amount = 0;
5166 _group_tabs->set_dirty ();
5167 resize_idle_id = -1;
5175 ENSURE_GUI_THREAD (*this, &Editor::located);
5178 playhead_cursor->set_position (_session->audible_sample ());
5179 if (_follow_playhead && !_pending_initial_locate) {
5180 reset_x_origin_to_follow_playhead ();
5184 _pending_locate_request = false;
5185 _pending_initial_locate = false;
5186 _last_update_time = 0;
5190 Editor::region_view_added (RegionView * rv)
5192 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5194 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5195 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5196 if (rv->region()->id () == (*rnote).first) {
5197 mrv->select_notes ((*rnote).second);
5198 selection->pending_midi_note_selection.erase(rnote);
5204 _summary->set_background_dirty ();
5206 mark_region_boundary_cache_dirty ();
5210 Editor::region_view_removed ()
5212 _summary->set_background_dirty ();
5214 mark_region_boundary_cache_dirty ();
5218 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5220 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5221 if ((*j)->stripable() == s) {
5230 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5232 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5233 if ((*j)->control() == c) {
5237 TimeAxisView::Children kids = (*j)->get_child_list ();
5239 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5240 if ((*k)->control() == c) {
5250 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5254 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5255 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5265 Editor::suspend_route_redisplay ()
5268 _routes->suspend_redisplay();
5273 Editor::resume_route_redisplay ()
5276 _routes->redisplay(); // queue redisplay
5277 _routes->resume_redisplay();
5282 Editor::add_vcas (VCAList& vlist)
5286 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5287 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5290 add_stripables (sl);
5294 Editor::add_routes (RouteList& rlist)
5298 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5302 add_stripables (sl);
5306 Editor::add_stripables (StripableList& sl)
5308 list<TimeAxisView*> new_views;
5309 boost::shared_ptr<VCA> v;
5310 boost::shared_ptr<Route> r;
5311 TrackViewList new_selection;
5312 bool from_scratch = (track_views.size() == 0);
5314 sl.sort (Stripable::Sorter());
5316 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5318 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5320 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5322 new_views.push_back (vtv);
5324 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5326 if (r->is_auditioner() || r->is_monitor()) {
5330 RouteTimeAxisView* rtv;
5331 DataType dt = r->input()->default_type();
5333 if (dt == ARDOUR::DataType::AUDIO) {
5334 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5336 } else if (dt == ARDOUR::DataType::MIDI) {
5337 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5340 throw unknown_type();
5343 new_views.push_back (rtv);
5344 track_views.push_back (rtv);
5345 new_selection.push_back (rtv);
5347 rtv->effective_gain_display ();
5349 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5350 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5354 if (new_views.size() > 0) {
5355 _routes->time_axis_views_added (new_views);
5356 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5359 /* note: !new_selection.empty() means that we got some routes rather
5363 if (!from_scratch && !new_selection.empty()) {
5364 selection->set (new_selection);
5365 begin_selection_op_history();
5368 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5369 show_editor_mixer (true);
5372 editor_list_button.set_sensitive (true);
5376 Editor::timeaxisview_deleted (TimeAxisView *tv)
5378 if (tv == entered_track) {
5382 if (_session && _session->deletion_in_progress()) {
5383 /* the situation is under control */
5387 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5389 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5391 _routes->route_removed (tv);
5393 TimeAxisView::Children c = tv->get_child_list ();
5394 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5395 if (entered_track == i->get()) {
5400 /* remove it from the list of track views */
5402 TrackViewList::iterator i;
5404 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5405 i = track_views.erase (i);
5408 /* update whatever the current mixer strip is displaying, if revelant */
5410 boost::shared_ptr<Route> route;
5413 route = rtav->route ();
5416 if (current_mixer_strip && current_mixer_strip->route() == route) {
5418 TimeAxisView* next_tv;
5420 if (track_views.empty()) {
5422 } else if (i == track_views.end()) {
5423 next_tv = track_views.front();
5428 // skip VCAs (cannot be selected, n/a in editor-mixer)
5429 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5430 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5431 next_tv = track_views.front();
5433 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5434 /* just in case: no master, only a VCA remains */
5440 set_selected_mixer_strip (*next_tv);
5442 /* make the editor mixer strip go away setting the
5443 * button to inactive (which also unticks the menu option)
5446 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5452 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5458 DisplaySuspender ds;
5459 PresentationInfo::ChangeSuspender cs;
5461 if (apply_to_selection) {
5462 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5464 TrackSelection::iterator j = i;
5467 hide_track_in_display (*i, false);
5472 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5474 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5475 /* this will hide the mixer strip */
5476 set_selected_mixer_strip (*tv);
5479 _routes->hide_track_in_display (*tv);
5484 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5489 _routes->show_track_in_display (*tv);
5490 if (move_into_view) {
5491 ensure_time_axis_view_is_visible (*tv, false);
5496 Editor::sync_track_view_list_and_routes ()
5498 track_views = TrackViewList (_routes->views ());
5500 _summary->set_background_dirty();
5501 _group_tabs->set_dirty ();
5503 return false; // do not call again (until needed)
5507 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5509 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5514 /** Find a StripableTimeAxisView by the ID of its stripable */
5515 StripableTimeAxisView*
5516 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5518 StripableTimeAxisView* v;
5520 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5521 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5522 if(v->stripable()->id() == id) {
5532 Editor::fit_route_group (RouteGroup *g)
5534 TrackViewList ts = axis_views_from_routes (g->route_list ());
5539 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5541 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5544 _session->cancel_audition ();
5548 if (_session->is_auditioning()) {
5549 _session->cancel_audition ();
5550 if (r == last_audition_region) {
5555 _session->audition_region (r);
5556 last_audition_region = r;
5561 Editor::hide_a_region (boost::shared_ptr<Region> r)
5563 r->set_hidden (true);
5567 Editor::show_a_region (boost::shared_ptr<Region> r)
5569 r->set_hidden (false);
5573 Editor::audition_region_from_region_list ()
5575 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5579 Editor::hide_region_from_region_list ()
5581 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5585 Editor::show_region_in_region_list ()
5587 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5591 Editor::step_edit_status_change (bool yn)
5594 start_step_editing ();
5596 stop_step_editing ();
5601 Editor::start_step_editing ()
5603 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5607 Editor::stop_step_editing ()
5609 step_edit_connection.disconnect ();
5613 Editor::check_step_edit ()
5615 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5616 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5618 mtv->check_step_edit ();
5622 return true; // do it again, till we stop
5626 Editor::scroll_press (Direction dir)
5628 ++_scroll_callbacks;
5630 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5631 /* delay the first auto-repeat */
5637 scroll_backward (1);
5645 scroll_up_one_track ();
5649 scroll_down_one_track ();
5653 /* do hacky auto-repeat */
5654 if (!_scroll_connection.connected ()) {
5656 _scroll_connection = Glib::signal_timeout().connect (
5657 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5660 _scroll_callbacks = 0;
5667 Editor::scroll_release ()
5669 _scroll_connection.disconnect ();
5672 /** Queue a change for the Editor viewport x origin to follow the playhead */
5674 Editor::reset_x_origin_to_follow_playhead ()
5676 samplepos_t const sample = playhead_cursor->current_sample ();
5678 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5680 if (_session->transport_speed() < 0) {
5682 if (sample > (current_page_samples() / 2)) {
5683 center_screen (sample-(current_page_samples()/2));
5685 center_screen (current_page_samples()/2);
5692 if (sample < _leftmost_sample) {
5694 if (_session->transport_rolling()) {
5695 /* rolling; end up with the playhead at the right of the page */
5696 l = sample - current_page_samples ();
5698 /* not rolling: end up with the playhead 1/4 of the way along the page */
5699 l = sample - current_page_samples() / 4;
5703 if (_session->transport_rolling()) {
5704 /* rolling: end up with the playhead on the left of the page */
5707 /* not rolling: end up with the playhead 3/4 of the way along the page */
5708 l = sample - 3 * current_page_samples() / 4;
5716 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5722 Editor::super_rapid_screen_update ()
5724 if (!_session || !_session->engine().running()) {
5728 /* METERING / MIXER STRIPS */
5730 /* update track meters, if required */
5731 if (contents().is_mapped() && meters_running) {
5732 RouteTimeAxisView* rtv;
5733 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5734 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5735 rtv->fast_update ();
5740 /* and any current mixer strip */
5741 if (current_mixer_strip) {
5742 current_mixer_strip->fast_update ();
5745 bool latent_locate = false;
5746 samplepos_t sample = _session->audible_sample (&latent_locate);
5747 const int64_t now = g_get_monotonic_time ();
5750 if (_session->exporting ()) {
5751 /* freewheel/export may be faster or slower than transport_speed() / SR.
5752 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5754 _last_update_time = 0;
5757 if (!_session->transport_rolling ()) {
5758 /* Do not interpolate the playhead position; just set it */
5759 _last_update_time = 0;
5762 if (_last_update_time > 0) {
5763 /* interpolate and smoothen playhead position */
5764 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5765 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5766 err = sample - guess;
5768 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5769 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5772 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5774 err, _err_screen_engine);
5779 _err_screen_engine = 0;
5782 if (err > 8192 || latent_locate) {
5783 // in case of x-runs or freewheeling
5784 _last_update_time = 0;
5785 sample = _session->audible_sample ();
5787 _last_update_time = now;
5790 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5792 MusicSample where (sample, 0);
5793 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5794 snapped_cursor->hide ();
5795 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5796 /* EditAtPlayhead does not snap */
5797 } else if (_edit_point == EditAtSelectedMarker) {
5798 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5799 * however, the current editing code -does- snap so I'll draw it that way for now.
5801 if (!selection->markers.empty()) {
5802 MusicSample ms (selection->markers.front()->position(), 0);
5803 snap_to (ms); // should use snap_to_with_modifier?
5804 snapped_cursor->set_position (ms.sample);
5805 snapped_cursor->show ();
5807 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5808 snapped_cursor->show ();
5809 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5810 snapped_cursor->hide ();
5813 /* There are a few reasons why we might not update the playhead / viewport stuff:
5815 * 1. we don't update things when there's a pending locate request, otherwise
5816 * when the editor requests a locate there is a chance that this method
5817 * will move the playhead before the locate request is processed, causing
5819 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5820 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5822 if (_pending_locate_request) {
5823 _last_update_time = 0;
5827 if (_dragging_playhead) {
5828 _last_update_time = 0;
5832 if (playhead_cursor->current_sample () == sample) {
5836 playhead_cursor->set_position (sample);
5838 if (_session->requested_return_sample() >= 0) {
5839 _last_update_time = 0;
5843 if (!_follow_playhead || pending_visual_change.being_handled) {
5844 /* We only do this if we aren't already
5845 * handling a visual change (ie if
5846 * pending_visual_change.being_handled is
5847 * false) so that these requests don't stack
5848 * up there are too many of them to handle in
5854 if (!_stationary_playhead) {
5855 reset_x_origin_to_follow_playhead ();
5857 samplepos_t const sample = playhead_cursor->current_sample ();
5858 double target = ((double)sample - (double)current_page_samples() / 2.0);
5859 if (target <= 0.0) {
5862 /* compare to EditorCursor::set_position() */
5863 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5864 double const new_pos = sample_to_pixel_unrounded (target);
5865 if (rint (new_pos) != rint (old_pos)) {
5866 reset_x_origin (pixel_to_sample (new_pos));
5873 Editor::session_going_away ()
5875 _have_idled = false;
5877 _session_connections.drop_connections ();
5879 super_rapid_screen_update_connection.disconnect ();
5881 selection->clear ();
5882 cut_buffer->clear ();
5884 clicked_regionview = 0;
5885 clicked_axisview = 0;
5886 clicked_routeview = 0;
5887 entered_regionview = 0;
5889 _last_update_time = 0;
5892 playhead_cursor->hide ();
5894 /* rip everything out of the list displays */
5898 _route_groups->clear ();
5900 /* do this first so that deleting a track doesn't reset cms to null
5901 and thus cause a leak.
5904 if (current_mixer_strip) {
5905 if (current_mixer_strip->get_parent() != 0) {
5906 global_hpacker.remove (*current_mixer_strip);
5908 delete current_mixer_strip;
5909 current_mixer_strip = 0;
5912 /* delete all trackviews */
5914 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5917 track_views.clear ();
5919 nudge_clock->set_session (0);
5921 editor_list_button.set_active(false);
5922 editor_list_button.set_sensitive(false);
5924 /* clear tempo/meter rulers */
5925 remove_metric_marks ();
5926 clear_marker_display ();
5932 stop_step_editing ();
5936 /* get rid of any existing editor mixer strip */
5938 WindowTitle title(Glib::get_application_name());
5939 title += _("Editor");
5941 own_window()->set_title (title.get_string());
5944 SessionHandlePtr::session_going_away ();
5948 Editor::trigger_script (int i)
5950 LuaInstance::instance()-> call_action (i);
5954 Editor::show_editor_list (bool yn)
5957 _editor_list_vbox.show ();
5959 _editor_list_vbox.hide ();
5964 Editor::change_region_layering_order (bool from_context_menu)
5966 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5968 if (!clicked_routeview) {
5969 if (layering_order_editor) {
5970 layering_order_editor->hide ();
5975 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5981 boost::shared_ptr<Playlist> pl = track->playlist();
5987 if (layering_order_editor == 0) {
5988 layering_order_editor = new RegionLayeringOrderEditor (*this);
5991 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5992 layering_order_editor->maybe_present ();
5996 Editor::update_region_layering_order_editor ()
5998 if (layering_order_editor && layering_order_editor->is_visible ()) {
5999 change_region_layering_order (true);
6004 Editor::setup_fade_images ()
6006 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6007 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6008 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6009 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6010 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6012 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6013 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6014 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6015 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6016 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6020 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6022 Editor::action_menu_item (std::string const & name)
6024 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6027 return *manage (a->create_menu_item ());
6031 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6033 EventBox* b = manage (new EventBox);
6034 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6035 Label* l = manage (new Label (name));
6039 _the_notebook.append_page (widget, *b);
6043 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6045 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6046 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6049 if (ev->type == GDK_2BUTTON_PRESS) {
6051 /* double-click on a notebook tab shrinks or expands the notebook */
6053 if (_notebook_shrunk) {
6054 if (pre_notebook_shrink_pane_width) {
6055 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6057 _notebook_shrunk = false;
6059 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6061 /* this expands the LHS of the edit pane to cover the notebook
6062 PAGE but leaves the tabs visible.
6064 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6065 _notebook_shrunk = true;
6073 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6075 using namespace Menu_Helpers;
6077 MenuList& items = _control_point_context_menu.items ();
6080 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6081 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6082 if (!can_remove_control_point (item)) {
6083 items.back().set_sensitive (false);
6086 _control_point_context_menu.popup (event->button.button, event->button.time);
6090 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6092 using namespace Menu_Helpers;
6094 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6099 /* We need to get the selection here and pass it to the operations, since
6100 popping up the menu will cause a region leave event which clears
6101 entered_regionview. */
6103 MidiRegionView& mrv = note->region_view();
6104 const RegionSelection rs = get_regions_from_selection_and_entered ();
6105 const uint32_t sel_size = mrv.selection_size ();
6107 MenuList& items = _note_context_menu.items();
6111 items.push_back(MenuElem(_("Delete"),
6112 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6115 items.push_back(MenuElem(_("Edit..."),
6116 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6117 if (sel_size != 1) {
6118 items.back().set_sensitive (false);
6121 items.push_back(MenuElem(_("Transpose..."),
6122 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6125 items.push_back(MenuElem(_("Legatize"),
6126 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6128 items.back().set_sensitive (false);
6131 items.push_back(MenuElem(_("Quantize..."),
6132 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6134 items.push_back(MenuElem(_("Remove Overlap"),
6135 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6137 items.back().set_sensitive (false);
6140 items.push_back(MenuElem(_("Transform..."),
6141 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6143 _note_context_menu.popup (event->button.button, event->button.time);
6147 Editor::zoom_vertical_modifier_released()
6149 _stepping_axis_view = 0;
6153 Editor::ui_parameter_changed (string parameter)
6155 if (parameter == "icon-set") {
6156 while (!_cursor_stack.empty()) {
6157 _cursor_stack.pop_back();
6159 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6160 _cursor_stack.push_back(_cursors->grabber);
6161 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6162 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6164 } else if (parameter == "draggable-playhead") {
6165 if (_verbose_cursor) {
6166 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6172 Editor::use_own_window (bool and_fill_it)
6174 bool new_window = !own_window();
6176 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6178 if (win && new_window) {
6179 win->set_name ("EditorWindow");
6181 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6183 // win->signal_realize().connect (*this, &Editor::on_realize);
6184 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6185 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6186 win->set_data ("ardour-bindings", bindings);
6191 DisplaySuspender ds;
6192 contents().show_all ();
6194 /* XXX: this is a bit unfortunate; it would probably
6195 be nicer if we could just call show () above rather
6196 than needing the show_all ()
6199 /* re-hide stuff if necessary */
6200 editor_list_button_toggled ();
6201 parameter_changed ("show-summary");
6202 parameter_changed ("show-group-tabs");
6203 parameter_changed ("show-zoom-tools");
6205 /* now reset all audio_time_axis heights, because widgets might need
6211 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6212 tv = (static_cast<TimeAxisView*>(*i));
6213 tv->reset_height ();
6216 if (current_mixer_strip) {
6217 current_mixer_strip->hide_things ();
6218 current_mixer_strip->parameter_changed ("mixer-element-visibility");