2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/gtk_ui.h"
61 #include "gtkmm2ext/keyboard.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
66 #include "ardour/analysis_graph.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
78 #include "ardour/vca_manager.h"
79 #include "ardour/vca.h"
81 #include "canvas/debug.h"
82 #include "canvas/text.h"
84 #include "widgets/ardour_spacer.h"
85 #include "widgets/eventboxext.h"
86 #include "widgets/tooltips.h"
88 #include "control_protocol/control_protocol.h"
91 #include "analysis_window.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
101 #include "editing_convert.h"
103 #include "editor_cursors.h"
104 #include "editor_drag.h"
105 #include "editor_group_tabs.h"
106 #include "editor_locations.h"
107 #include "editor_regions.h"
108 #include "editor_route_groups.h"
109 #include "editor_routes.h"
110 #include "editor_snapshots.h"
111 #include "editor_summary.h"
112 #include "enums_convert.h"
113 #include "export_report.h"
114 #include "global_port_matrix.h"
115 #include "gui_object.h"
116 #include "gui_thread.h"
117 #include "keyboard.h"
118 #include "luainstance.h"
120 #include "midi_region_view.h"
121 #include "midi_time_axis.h"
122 #include "mixer_strip.h"
123 #include "mixer_ui.h"
124 #include "mouse_cursors.h"
125 #include "note_base.h"
126 #include "playlist_selector.h"
127 #include "public_editor.h"
128 #include "quantize_dialog.h"
129 #include "region_layering_order_editor.h"
130 #include "rgb_macros.h"
131 #include "rhythm_ferret.h"
132 #include "route_sorter.h"
133 #include "selection.h"
134 #include "simple_progress_dialog.h"
136 #include "grid_lines.h"
137 #include "time_axis_view.h"
138 #include "time_info_box.h"
140 #include "ui_config.h"
142 #include "vca_time_axis.h"
143 #include "verbose_cursor.h"
145 #include "pbd/i18n.h"
148 using namespace ARDOUR;
149 using namespace ArdourWidgets;
150 using namespace ARDOUR_UI_UTILS;
153 using namespace Glib;
154 using namespace Gtkmm2ext;
155 using namespace Editing;
157 using PBD::internationalize;
159 using Gtkmm2ext::Keyboard;
161 double Editor::timebar_height = 15.0;
163 static const gchar *_grid_type_strings[] = {
172 N_("1/3 (8th triplet)"), // or "1/12" ?
173 N_("1/6 (16th triplet)"),
174 N_("1/12 (32nd triplet)"),
175 N_("1/24 (64th triplet)"),
176 N_("1/5 (8th quintuplet)"),
177 N_("1/10 (16th quintuplet)"),
178 N_("1/20 (32nd quintuplet)"),
179 N_("1/7 (8th septuplet)"),
180 N_("1/14 (16th septuplet)"),
181 N_("1/28 (32nd septuplet)"),
188 static const gchar *_edit_point_strings[] = {
195 static const gchar *_edit_mode_strings[] = {
203 static const gchar *_zoom_focus_strings[] = {
213 #ifdef USE_RUBBERBAND
214 static const gchar *_rb_opt_strings[] = {
217 N_("Balanced multitimbral mixture"),
218 N_("Unpitched percussion with stable notes"),
219 N_("Crisp monophonic instrumental"),
220 N_("Unpitched solo percussion"),
221 N_("Resample without preserving pitch"),
226 /* Robin says: this should be odd to accomodate cairo drawing offset (width/2 rounds up to pixel boundary) */
228 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
230 #define COMBO_TRIANGLE_WIDTH 11 // as-measured for win/linux.
234 : PublicEditor (global_hpacker)
235 , editor_mixer_strip_width (Wide)
236 , constructed (false)
237 , _playlist_selector (0)
239 , no_save_visual (false)
240 , _leftmost_sample (0)
241 , samples_per_pixel (2048)
242 , zoom_focus (ZoomFocusPlayhead)
243 , mouse_mode (MouseObject)
244 , pre_internal_grid_type (GridTypeBeat)
245 , pre_internal_snap_mode (SnapOff)
246 , internal_grid_type (GridTypeBeat)
247 , internal_snap_mode (SnapOff)
248 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
249 , _notebook_shrunk (false)
250 , location_marker_color (0)
251 , location_range_color (0)
252 , location_loop_color (0)
253 , location_punch_color (0)
254 , location_cd_marker_color (0)
256 , _show_marker_lines (false)
257 , clicked_axisview (0)
258 , clicked_routeview (0)
259 , clicked_regionview (0)
260 , clicked_selection (0)
261 , clicked_control_point (0)
262 , button_release_can_deselect (true)
263 , _mouse_changed_selection (false)
264 , region_edit_menu_split_item (0)
265 , region_edit_menu_split_multichannel_item (0)
266 , track_region_edit_playlist_menu (0)
267 , track_edit_playlist_submenu (0)
268 , track_selection_edit_playlist_submenu (0)
269 , _popup_region_menu_item (0)
271 , _track_canvas_viewport (0)
272 , within_track_canvas (false)
273 , _verbose_cursor (0)
277 , range_marker_group (0)
278 , transport_marker_group (0)
279 , cd_marker_group (0)
280 , _time_markers_group (0)
281 , hv_scroll_group (0)
283 , cursor_scroll_group (0)
284 , no_scroll_group (0)
285 , _trackview_group (0)
286 , _drag_motion_group (0)
287 , _canvas_drop_zone (0)
288 , no_ruler_shown_update (false)
289 , ruler_grabbed_widget (0)
291 , minsec_mark_interval (0)
292 , minsec_mark_modulo (0)
294 , timecode_ruler_scale (timecode_show_many_hours)
295 , timecode_mark_modulo (0)
296 , timecode_nmarks (0)
297 , _samples_ruler_interval (0)
298 , bbt_ruler_scale (bbt_show_many)
301 , bbt_bar_helper_on (0)
302 , bbt_accent_modulo (0)
307 , visible_timebars (0)
308 , editor_ruler_menu (0)
312 , range_marker_bar (0)
313 , transport_marker_bar (0)
315 , minsec_label (_("Mins:Secs"))
316 , bbt_label (_("Bars:Beats"))
317 , timecode_label (_("Timecode"))
318 , samples_label (_("Samples"))
319 , tempo_label (_("Tempo"))
320 , meter_label (_("Meter"))
321 , mark_label (_("Location Markers"))
322 , range_mark_label (_("Range Markers"))
323 , transport_mark_label (_("Loop/Punch Ranges"))
324 , cd_mark_label (_("CD Markers"))
325 , videotl_label (_("Video Timeline"))
328 , playhead_cursor (0)
329 , _region_boundary_cache_dirty (true)
330 , edit_packer (4, 4, true)
331 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
332 , horizontal_adjustment (0.0, 0.0, 1e16)
333 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
334 , controls_layout (unused_adjustment, vertical_adjustment)
335 , _scroll_callbacks (0)
336 , _visible_canvas_width (0)
337 , _visible_canvas_height (0)
338 , _full_canvas_height (0)
339 , edit_controls_left_menu (0)
340 , edit_controls_right_menu (0)
341 , visual_change_queued(false)
342 , _last_update_time (0)
343 , _err_screen_engine (0)
344 , cut_buffer_start (0)
345 , cut_buffer_length (0)
346 , button_bindings (0)
347 , last_paste_pos (-1)
350 , current_interthread_info (0)
351 , analysis_window (0)
352 , select_new_marker (false)
354 , scrubbing_direction (0)
355 , scrub_reversals (0)
356 , scrub_reverse_distance (0)
357 , have_pending_keyboard_selection (false)
358 , pending_keyboard_selection_start (0)
359 , _grid_type (GridTypeBeat)
360 , _snap_mode (SnapOff)
361 , ignore_gui_changes (false)
362 , _drags (new DragManager (this))
364 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
365 , _dragging_playhead (false)
366 , _dragging_edit_point (false)
367 , _follow_playhead (true)
368 , _stationary_playhead (false)
371 , global_rect_group (0)
372 , time_line_group (0)
373 , tempo_marker_menu (0)
374 , meter_marker_menu (0)
376 , range_marker_menu (0)
377 , transport_marker_menu (0)
378 , new_transport_marker_menu (0)
380 , marker_menu_item (0)
381 , bbt_beat_subdivision (4)
382 , _visible_track_count (-1)
383 , toolbar_selection_clock_table (2,3)
384 , automation_mode_button (_("mode"))
385 , selection (new Selection (this, true))
386 , cut_buffer (new Selection (this, false))
387 , _selection_memento (new SelectionMemento())
388 , _all_region_actions_sensitized (false)
389 , _ignore_region_action (false)
390 , _last_region_menu_was_main (false)
391 , _track_selection_change_without_scroll (false)
392 , _editor_track_selection_change_without_scroll (false)
393 , cd_marker_bar_drag_rect (0)
394 , range_bar_drag_rect (0)
395 , transport_bar_drag_rect (0)
396 , transport_bar_range_rect (0)
397 , transport_bar_preroll_rect (0)
398 , transport_bar_postroll_rect (0)
399 , transport_loop_range_rect (0)
400 , transport_punch_range_rect (0)
401 , transport_punchin_line (0)
402 , transport_punchout_line (0)
403 , transport_preroll_rect (0)
404 , transport_postroll_rect (0)
406 , rubberband_rect (0)
412 , autoscroll_horizontal_allowed (false)
413 , autoscroll_vertical_allowed (false)
415 , autoscroll_widget (0)
416 , show_gain_after_trim (false)
417 , selection_op_cmd_depth (0)
418 , selection_op_history_it (0)
419 , no_save_instant (false)
421 , current_mixer_strip (0)
422 , show_editor_mixer_when_tracks_arrive (false)
423 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
424 , current_stepping_trackview (0)
425 , last_track_height_step_timestamp (0)
427 , entered_regionview (0)
428 , clear_entered_track (false)
429 , _edit_point (EditAtMouse)
430 , meters_running (false)
432 , _have_idled (false)
433 , resize_idle_id (-1)
434 , _pending_resize_amount (0)
435 , _pending_resize_view (0)
436 , _pending_locate_request (false)
437 , _pending_initial_locate (false)
441 , layering_order_editor (0)
442 , _last_cut_copy_source_track (0)
443 , _region_selection_change_updates_region_list (true)
445 , _following_mixer_selection (false)
446 , _control_point_toggled_on_press (false)
447 , _stepping_axis_view (0)
448 , quantize_dialog (0)
449 , _main_menu_disabler (0)
450 , myactions (X_("editor"))
452 /* we are a singleton */
454 PublicEditor::_instance = this;
458 last_event_time.tv_sec = 0;
459 last_event_time.tv_usec = 0;
461 selection_op_history.clear();
464 grid_type_strings = I18N (_grid_type_strings);
465 zoom_focus_strings = I18N (_zoom_focus_strings);
466 edit_mode_strings = I18N (_edit_mode_strings);
467 edit_point_strings = I18N (_edit_point_strings);
468 #ifdef USE_RUBBERBAND
469 rb_opt_strings = I18N (_rb_opt_strings);
473 build_edit_mode_menu();
474 build_zoom_focus_menu();
475 build_track_count_menu();
476 build_grid_type_menu();
477 build_edit_point_menu();
479 location_marker_color = UIConfiguration::instance().color ("location marker");
480 location_range_color = UIConfiguration::instance().color ("location range");
481 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
482 location_loop_color = UIConfiguration::instance().color ("location loop");
483 location_punch_color = UIConfiguration::instance().color ("location punch");
485 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
487 TimeAxisView::setup_sizes ();
488 ArdourMarker::setup_sizes (timebar_height);
489 TempoCurve::setup_sizes (timebar_height);
491 bbt_label.set_name ("EditorRulerLabel");
492 bbt_label.set_size_request (-1, (int)timebar_height);
493 bbt_label.set_alignment (1.0, 0.5);
494 bbt_label.set_padding (5,0);
496 bbt_label.set_no_show_all();
497 minsec_label.set_name ("EditorRulerLabel");
498 minsec_label.set_size_request (-1, (int)timebar_height);
499 minsec_label.set_alignment (1.0, 0.5);
500 minsec_label.set_padding (5,0);
501 minsec_label.hide ();
502 minsec_label.set_no_show_all();
503 timecode_label.set_name ("EditorRulerLabel");
504 timecode_label.set_size_request (-1, (int)timebar_height);
505 timecode_label.set_alignment (1.0, 0.5);
506 timecode_label.set_padding (5,0);
507 timecode_label.hide ();
508 timecode_label.set_no_show_all();
509 samples_label.set_name ("EditorRulerLabel");
510 samples_label.set_size_request (-1, (int)timebar_height);
511 samples_label.set_alignment (1.0, 0.5);
512 samples_label.set_padding (5,0);
513 samples_label.hide ();
514 samples_label.set_no_show_all();
516 tempo_label.set_name ("EditorRulerLabel");
517 tempo_label.set_size_request (-1, (int)timebar_height);
518 tempo_label.set_alignment (1.0, 0.5);
519 tempo_label.set_padding (5,0);
521 tempo_label.set_no_show_all();
523 meter_label.set_name ("EditorRulerLabel");
524 meter_label.set_size_request (-1, (int)timebar_height);
525 meter_label.set_alignment (1.0, 0.5);
526 meter_label.set_padding (5,0);
528 meter_label.set_no_show_all();
530 if (Profile->get_trx()) {
531 mark_label.set_text (_("Markers"));
533 mark_label.set_name ("EditorRulerLabel");
534 mark_label.set_size_request (-1, (int)timebar_height);
535 mark_label.set_alignment (1.0, 0.5);
536 mark_label.set_padding (5,0);
538 mark_label.set_no_show_all();
540 cd_mark_label.set_name ("EditorRulerLabel");
541 cd_mark_label.set_size_request (-1, (int)timebar_height);
542 cd_mark_label.set_alignment (1.0, 0.5);
543 cd_mark_label.set_padding (5,0);
544 cd_mark_label.hide();
545 cd_mark_label.set_no_show_all();
547 videotl_bar_height = 4;
548 videotl_label.set_name ("EditorRulerLabel");
549 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
550 videotl_label.set_alignment (1.0, 0.5);
551 videotl_label.set_padding (5,0);
552 videotl_label.hide();
553 videotl_label.set_no_show_all();
555 range_mark_label.set_name ("EditorRulerLabel");
556 range_mark_label.set_size_request (-1, (int)timebar_height);
557 range_mark_label.set_alignment (1.0, 0.5);
558 range_mark_label.set_padding (5,0);
559 range_mark_label.hide();
560 range_mark_label.set_no_show_all();
562 transport_mark_label.set_name ("EditorRulerLabel");
563 transport_mark_label.set_size_request (-1, (int)timebar_height);
564 transport_mark_label.set_alignment (1.0, 0.5);
565 transport_mark_label.set_padding (5,0);
566 transport_mark_label.hide();
567 transport_mark_label.set_no_show_all();
569 initialize_canvas ();
571 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
573 _summary = new EditorSummary (this);
575 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
576 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
578 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
580 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
581 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
583 edit_controls_vbox.set_spacing (0);
584 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
585 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
587 HBox* h = manage (new HBox);
588 _group_tabs = new EditorGroupTabs (this);
589 if (!ARDOUR::Profile->get_trx()) {
590 h->pack_start (*_group_tabs, PACK_SHRINK);
592 h->pack_start (edit_controls_vbox);
593 controls_layout.add (*h);
595 controls_layout.set_name ("EditControlsBase");
596 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
597 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
598 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
600 _cursors = new MouseCursors;
601 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
602 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
604 /* Push default cursor to ever-present bottom of cursor stack. */
605 push_canvas_cursor(_cursors->grabber);
607 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
609 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
610 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
611 pad_line_1->set_outline_color (0xFF0000FF);
617 edit_packer.set_col_spacings (0);
618 edit_packer.set_row_spacings (0);
619 edit_packer.set_homogeneous (false);
620 edit_packer.set_border_width (0);
621 edit_packer.set_name ("EditorWindow");
623 time_bars_event_box.add (time_bars_vbox);
624 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
625 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
627 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
628 axis_view_shadow->set_size_request (4, -1);
629 axis_view_shadow->set_name("EditorWindow");
630 axis_view_shadow->show();
632 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
634 /* labels for the time bars */
635 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
637 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
639 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
641 bottom_hbox.set_border_width (2);
642 bottom_hbox.set_spacing (3);
644 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
646 _route_groups = new EditorRouteGroups (this);
647 _routes = new EditorRoutes (this);
648 _regions = new EditorRegions (this);
649 _snapshots = new EditorSnapshots (this);
650 _locations = new EditorLocations (this);
651 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
653 /* these are static location signals */
655 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
657 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
659 add_notebook_page (_("Regions"), _regions->widget ());
660 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
661 add_notebook_page (_("Snapshots"), _snapshots->widget ());
662 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
663 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
665 _the_notebook.set_show_tabs (true);
666 _the_notebook.set_scrollable (true);
667 _the_notebook.popup_disable ();
668 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
669 _the_notebook.show_all ();
671 _notebook_shrunk = false;
674 /* Pick up some settings we need to cache, early */
676 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
679 settings->get_property ("notebook-shrunk", _notebook_shrunk);
682 editor_summary_pane.set_check_divider_position (true);
683 editor_summary_pane.add (edit_packer);
685 Button* summary_arrow_left = manage (new Button);
686 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
687 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
688 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 Button* summary_arrow_right = manage (new Button);
691 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
692 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
693 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
695 VBox* summary_arrows_left = manage (new VBox);
696 summary_arrows_left->pack_start (*summary_arrow_left);
698 VBox* summary_arrows_right = manage (new VBox);
699 summary_arrows_right->pack_start (*summary_arrow_right);
701 Frame* summary_sample = manage (new Frame);
702 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
704 summary_sample->add (*_summary);
705 summary_sample->show ();
707 _summary_hbox.pack_start (*summary_arrows_left, false, false);
708 _summary_hbox.pack_start (*summary_sample, true, true);
709 _summary_hbox.pack_start (*summary_arrows_right, false, false);
711 if (!ARDOUR::Profile->get_trx()) {
712 editor_summary_pane.add (_summary_hbox);
715 edit_pane.set_check_divider_position (true);
716 edit_pane.add (editor_summary_pane);
717 if (!ARDOUR::Profile->get_trx()) {
718 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
719 _editor_list_vbox.pack_start (_the_notebook);
720 edit_pane.add (_editor_list_vbox);
721 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
724 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
725 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
728 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
729 /* initial allocation is 90% to canvas, 10% to notebook */
732 edit_pane.set_divider (0, fract);
734 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
735 /* initial allocation is 90% to canvas, 10% to summary */
738 editor_summary_pane.set_divider (0, fract);
740 global_vpacker.set_spacing (0);
741 global_vpacker.set_border_width (0);
743 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
745 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
746 ebox->set_name("EditorWindow");
747 ebox->add (ebox_hpacker);
749 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
750 epane_box->set_name("EditorWindow");
751 epane_box->add (edit_pane);
753 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
754 epane_box2->set_name("EditorWindow");
755 epane_box2->add (global_vpacker);
757 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
758 toolbar_shadow->set_size_request (-1, 4);
759 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
760 toolbar_shadow->set_name("EditorWindow");
761 toolbar_shadow->show();
763 global_vpacker.pack_start (*toolbar_shadow, false, false);
764 global_vpacker.pack_start (*ebox, false, false);
765 global_vpacker.pack_start (*epane_box, true, true);
766 global_hpacker.pack_start (*epane_box2, true, true);
768 /* need to show the "contents" widget so that notebook will show if tab is switched to
771 global_hpacker.show ();
775 /* register actions now so that set_state() can find them and set toggles/checks etc */
782 _playlist_selector = new PlaylistSelector();
783 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
785 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
789 nudge_forward_button.set_name ("nudge button");
790 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
792 nudge_backward_button.set_name ("nudge button");
793 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
795 fade_context_menu.set_name ("ArdourContextMenu");
797 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
799 /* allow external control surfaces/protocols to do various things */
801 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
802 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
803 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
804 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
805 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
806 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
807 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
808 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
809 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
810 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
811 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
812 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
813 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
814 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
816 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
817 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
818 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
819 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
820 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
822 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
826 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
828 /* problematic: has to return a value and thus cannot be x-thread */
830 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
832 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
833 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
835 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
837 _ignore_region_action = false;
838 _last_region_menu_was_main = false;
839 _popup_region_menu_item = 0;
841 _show_marker_lines = false;
843 /* Button bindings */
845 button_bindings = new Bindings ("editor-mouse");
847 XMLNode* node = button_settings();
849 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
850 button_bindings->load_operation (**i);
856 /* grab current parameter state */
857 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
858 UIConfiguration::instance().map_parameters (pc);
860 setup_fade_images ();
862 set_grid_to (GridTypeNone);
869 delete button_bindings;
871 delete _route_groups;
872 delete _track_canvas_viewport;
875 delete _verbose_cursor;
876 delete quantize_dialog;
882 delete _playlist_selector;
883 delete _time_info_box;
888 LuaInstance::destroy_instance ();
890 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
893 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
896 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
902 Editor::button_settings () const
904 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
905 XMLNode* node = find_named_node (*settings, X_("Buttons"));
908 node = new XMLNode (X_("Buttons"));
915 Editor::get_smart_mode () const
917 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
921 Editor::catch_vanishing_regionview (RegionView *rv)
923 /* note: the selection will take care of the vanishing
924 audioregionview by itself.
927 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
931 if (clicked_regionview == rv) {
932 clicked_regionview = 0;
935 if (entered_regionview == rv) {
936 set_entered_regionview (0);
939 if (!_all_region_actions_sensitized) {
940 sensitize_all_region_actions (true);
945 Editor::set_entered_regionview (RegionView* rv)
947 if (rv == entered_regionview) {
951 if (entered_regionview) {
952 entered_regionview->exited ();
955 entered_regionview = rv;
957 if (entered_regionview != 0) {
958 entered_regionview->entered ();
961 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
962 /* This RegionView entry might have changed what region actions
963 are allowed, so sensitize them all in case a key is pressed.
965 sensitize_all_region_actions (true);
970 Editor::set_entered_track (TimeAxisView* tav)
973 entered_track->exited ();
979 entered_track->entered ();
984 Editor::instant_save ()
986 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
991 _session->add_instant_xml(get_state());
993 Config->add_instant_xml(get_state());
998 Editor::control_vertical_zoom_in_all ()
1000 tav_zoom_smooth (false, true);
1004 Editor::control_vertical_zoom_out_all ()
1006 tav_zoom_smooth (true, true);
1010 Editor::control_vertical_zoom_in_selected ()
1012 tav_zoom_smooth (false, false);
1016 Editor::control_vertical_zoom_out_selected ()
1018 tav_zoom_smooth (true, false);
1022 Editor::control_view (uint32_t view)
1024 goto_visual_state (view);
1028 Editor::control_unselect ()
1030 selection->clear_tracks ();
1034 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1036 TimeAxisView* tav = time_axis_view_from_stripable (s);
1040 case Selection::Add:
1041 selection->add (tav);
1043 case Selection::Toggle:
1044 selection->toggle (tav);
1046 case Selection::Extend:
1048 case Selection::Set:
1049 selection->set (tav);
1053 selection->clear_tracks ();
1058 Editor::control_step_tracks_up ()
1060 scroll_tracks_up_line ();
1064 Editor::control_step_tracks_down ()
1066 scroll_tracks_down_line ();
1070 Editor::control_scroll (float fraction)
1072 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1078 double step = fraction * current_page_samples();
1081 _control_scroll_target is an optional<T>
1083 it acts like a pointer to an samplepos_t, with
1084 a operator conversion to boolean to check
1085 that it has a value could possibly use
1086 playhead_cursor->current_sample to store the
1087 value and a boolean in the class to know
1088 when it's out of date
1091 if (!_control_scroll_target) {
1092 _control_scroll_target = _session->transport_sample();
1093 _dragging_playhead = true;
1096 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1097 *_control_scroll_target = 0;
1098 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1099 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1101 *_control_scroll_target += (samplepos_t) trunc (step);
1104 /* move visuals, we'll catch up with it later */
1106 playhead_cursor->set_position (*_control_scroll_target);
1107 UpdateAllTransportClocks (*_control_scroll_target);
1109 if (*_control_scroll_target > (current_page_samples() / 2)) {
1110 /* try to center PH in window */
1111 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1117 Now we do a timeout to actually bring the session to the right place
1118 according to the playhead. This is to avoid reading disk buffers on every
1119 call to control_scroll, which is driven by ScrollTimeline and therefore
1120 probably by a control surface wheel which can generate lots of events.
1122 /* cancel the existing timeout */
1124 control_scroll_connection.disconnect ();
1126 /* add the next timeout */
1128 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1132 Editor::deferred_control_scroll (samplepos_t /*target*/)
1134 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1135 /* reset for next stream */
1136 _control_scroll_target = boost::none;
1137 _dragging_playhead = false;
1142 Editor::access_action (const std::string& action_group, const std::string& action_item)
1148 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1151 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
1159 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1161 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1165 Editor::on_realize ()
1169 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1170 start_lock_event_timing ();
1175 Editor::start_lock_event_timing ()
1177 /* check if we should lock the GUI every 30 seconds */
1179 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1183 Editor::generic_event_handler (GdkEvent* ev)
1186 case GDK_BUTTON_PRESS:
1187 case GDK_BUTTON_RELEASE:
1188 case GDK_MOTION_NOTIFY:
1190 case GDK_KEY_RELEASE:
1191 if (contents().is_mapped()) {
1192 gettimeofday (&last_event_time, 0);
1196 case GDK_LEAVE_NOTIFY:
1197 switch (ev->crossing.detail) {
1198 case GDK_NOTIFY_UNKNOWN:
1199 case GDK_NOTIFY_INFERIOR:
1200 case GDK_NOTIFY_ANCESTOR:
1202 case GDK_NOTIFY_VIRTUAL:
1203 case GDK_NOTIFY_NONLINEAR:
1204 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1205 /* leaving window, so reset focus, thus ending any and
1206 all text entry operations.
1208 ARDOUR_UI::instance()->reset_focus (&contents());
1221 Editor::lock_timeout_callback ()
1223 struct timeval now, delta;
1225 gettimeofday (&now, 0);
1227 timersub (&now, &last_event_time, &delta);
1229 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1231 /* don't call again. Returning false will effectively
1232 disconnect us from the timer callback.
1234 unlock() will call start_lock_event_timing() to get things
1244 Editor::map_position_change (samplepos_t sample)
1246 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1248 if (_session == 0) {
1252 if (_follow_playhead) {
1253 center_screen (sample);
1256 playhead_cursor->set_position (sample);
1260 Editor::center_screen (samplepos_t sample)
1262 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1264 /* if we're off the page, then scroll.
1267 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1268 center_screen_internal (sample, page);
1273 Editor::center_screen_internal (samplepos_t sample, float page)
1277 if (sample > page) {
1278 sample -= (samplepos_t) page;
1283 reset_x_origin (sample);
1288 Editor::update_title ()
1290 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1292 if (!own_window()) {
1297 bool dirty = _session->dirty();
1299 string session_name;
1301 if (_session->snap_name() != _session->name()) {
1302 session_name = _session->snap_name();
1304 session_name = _session->name();
1308 session_name = "*" + session_name;
1311 WindowTitle title(session_name);
1312 title += S_("Window|Editor");
1313 title += Glib::get_application_name();
1314 own_window()->set_title (title.get_string());
1316 /* ::session_going_away() will have taken care of it */
1321 Editor::set_session (Session *t)
1323 SessionHandlePtr::set_session (t);
1329 /* initialize _leftmost_sample to the extents of the session
1330 * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
1331 * before the visible state has been loaded from instant.xml */
1332 _leftmost_sample = session_gui_extents().first;
1334 _playlist_selector->set_session (_session);
1335 nudge_clock->set_session (_session);
1336 _summary->set_session (_session);
1337 _group_tabs->set_session (_session);
1338 _route_groups->set_session (_session);
1339 _regions->set_session (_session);
1340 _snapshots->set_session (_session);
1341 _routes->set_session (_session);
1342 _locations->set_session (_session);
1343 _time_info_box->set_session (_session);
1345 if (rhythm_ferret) {
1346 rhythm_ferret->set_session (_session);
1349 if (analysis_window) {
1350 analysis_window->set_session (_session);
1354 sfbrowser->set_session (_session);
1357 compute_fixed_ruler_scale ();
1359 /* Make sure we have auto loop and auto punch ranges */
1361 Location* loc = _session->locations()->auto_loop_location();
1363 loc->set_name (_("Loop"));
1366 loc = _session->locations()->auto_punch_location();
1369 loc->set_name (_("Punch"));
1372 refresh_location_display ();
1374 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1375 * the selected Marker; this needs the LocationMarker list to be available.
1377 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1378 set_state (*node, Stateful::loading_state_version);
1380 /* catch up on selection state, etc. */
1383 sc.add (Properties::selected);
1384 presentation_info_changed (sc);
1386 /* catch up with the playhead */
1388 _session->request_locate (playhead_cursor->current_sample ());
1389 _pending_initial_locate = true;
1393 /* These signals can all be emitted by a non-GUI thread. Therefore the
1394 handlers for them must not attempt to directly interact with the GUI,
1395 but use PBD::Signal<T>::connect() which accepts an event loop
1396 ("context") where the handler will be asked to run.
1399 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1400 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1401 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1402 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1403 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1404 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1405 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1406 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1407 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1408 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1409 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1410 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1411 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1412 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1413 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1414 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1416 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1417 playhead_cursor->show ();
1419 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1420 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1421 snapped_cursor->show ();
1423 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1424 Config->map_parameters (pc);
1425 _session->config.map_parameters (pc);
1427 restore_ruler_visibility ();
1428 //tempo_map_changed (PropertyChange (0));
1429 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1431 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1432 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1435 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1436 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1439 /* register for undo history */
1440 _session->register_with_memento_command_factory(id(), this);
1441 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1443 LuaInstance::instance()->set_session(_session);
1445 start_updating_meters ();
1449 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1451 using namespace Menu_Helpers;
1453 void (Editor::*emf)(FadeShape);
1454 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1457 images = &_xfade_in_images;
1458 emf = &Editor::set_fade_in_shape;
1460 images = &_xfade_out_images;
1461 emf = &Editor::set_fade_out_shape;
1466 _("Linear (for highly correlated material)"),
1467 *(*images)[FadeLinear],
1468 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1476 _("Constant power"),
1477 *(*images)[FadeConstantPower],
1478 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 *(*images)[FadeSymmetric],
1487 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1496 *(*images)[FadeSlow],
1497 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1500 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 *(*images)[FadeFast],
1506 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1509 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 /** Pop up a context menu for when the user clicks on a start crossfade */
1514 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1516 using namespace Menu_Helpers;
1517 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1522 MenuList& items (xfade_in_context_menu.items());
1525 if (arv->audio_region()->fade_in_active()) {
1526 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1528 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1531 items.push_back (SeparatorElem());
1532 fill_xfade_menu (items, true);
1534 xfade_in_context_menu.popup (button, time);
1537 /** Pop up a context menu for when the user clicks on an end crossfade */
1539 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1541 using namespace Menu_Helpers;
1542 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1547 MenuList& items (xfade_out_context_menu.items());
1550 if (arv->audio_region()->fade_out_active()) {
1551 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1553 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1556 items.push_back (SeparatorElem());
1557 fill_xfade_menu (items, false);
1559 xfade_out_context_menu.popup (button, time);
1563 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1565 using namespace Menu_Helpers;
1566 Menu* (Editor::*build_menu_function)();
1569 switch (item_type) {
1571 case RegionViewName:
1572 case RegionViewNameHighlight:
1573 case LeftFrameHandle:
1574 case RightFrameHandle:
1575 if (with_selection) {
1576 build_menu_function = &Editor::build_track_selection_context_menu;
1578 build_menu_function = &Editor::build_track_region_context_menu;
1583 if (with_selection) {
1584 build_menu_function = &Editor::build_track_selection_context_menu;
1586 build_menu_function = &Editor::build_track_context_menu;
1591 if (clicked_routeview->track()) {
1592 build_menu_function = &Editor::build_track_context_menu;
1594 build_menu_function = &Editor::build_track_bus_context_menu;
1599 /* probably shouldn't happen but if it does, we don't care */
1603 menu = (this->*build_menu_function)();
1604 menu->set_name ("ArdourContextMenu");
1606 /* now handle specific situations */
1608 switch (item_type) {
1610 case RegionViewName:
1611 case RegionViewNameHighlight:
1612 case LeftFrameHandle:
1613 case RightFrameHandle:
1614 if (!with_selection) {
1615 if (region_edit_menu_split_item) {
1616 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1617 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1619 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1622 if (region_edit_menu_split_multichannel_item) {
1623 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1624 region_edit_menu_split_multichannel_item->set_sensitive (true);
1626 region_edit_menu_split_multichannel_item->set_sensitive (false);
1639 /* probably shouldn't happen but if it does, we don't care */
1643 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1645 /* Bounce to disk */
1647 using namespace Menu_Helpers;
1648 MenuList& edit_items = menu->items();
1650 edit_items.push_back (SeparatorElem());
1652 switch (clicked_routeview->audio_track()->freeze_state()) {
1653 case AudioTrack::NoFreeze:
1654 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1657 case AudioTrack::Frozen:
1658 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1661 case AudioTrack::UnFrozen:
1662 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1668 if (item_type == StreamItem && clicked_routeview) {
1669 clicked_routeview->build_underlay_menu(menu);
1672 /* When the region menu is opened, we setup the actions so that they look right
1675 sensitize_the_right_region_actions (false);
1676 _last_region_menu_was_main = false;
1678 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1679 menu->popup (button, time);
1683 Editor::build_track_context_menu ()
1685 using namespace Menu_Helpers;
1687 MenuList& edit_items = track_context_menu.items();
1690 add_dstream_context_items (edit_items);
1691 return &track_context_menu;
1695 Editor::build_track_bus_context_menu ()
1697 using namespace Menu_Helpers;
1699 MenuList& edit_items = track_context_menu.items();
1702 add_bus_context_items (edit_items);
1703 return &track_context_menu;
1707 Editor::build_track_region_context_menu ()
1709 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_region_context_menu.items();
1713 /* we've just cleared the track region context menu, so the menu that these
1714 two items were on will have disappeared; stop them dangling.
1716 region_edit_menu_split_item = 0;
1717 region_edit_menu_split_multichannel_item = 0;
1719 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1722 boost::shared_ptr<Track> tr;
1723 boost::shared_ptr<Playlist> pl;
1725 if ((tr = rtv->track())) {
1726 add_region_context_items (edit_items, tr);
1730 add_dstream_context_items (edit_items);
1732 return &track_region_context_menu;
1736 Editor::loudness_analyze_region_selection ()
1741 Selection& s (PublicEditor::instance ().get_selection ());
1742 RegionSelection ars = s.regions;
1743 ARDOUR::AnalysisGraph ag (_session);
1744 samplecnt_t total_work = 0;
1746 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1747 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1751 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1754 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1755 total_work += arv->region ()->length ();
1758 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1760 ag.set_total_samples (total_work);
1761 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1764 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1765 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1769 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1773 ag.analyze_region (ar);
1776 if (!ag.canceled ()) {
1777 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1783 Editor::loudness_analyze_range_selection ()
1788 Selection& s (PublicEditor::instance ().get_selection ());
1789 TimeSelection ts = s.time;
1790 ARDOUR::AnalysisGraph ag (_session);
1791 samplecnt_t total_work = 0;
1793 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1794 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1798 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1802 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1803 total_work += j->length ();
1807 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1809 ag.set_total_samples (total_work);
1810 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1813 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1814 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1818 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1822 ag.analyze_range (rui->route (), pl, ts);
1825 if (!ag.canceled ()) {
1826 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1832 Editor::spectral_analyze_region_selection ()
1834 if (analysis_window == 0) {
1835 analysis_window = new AnalysisWindow();
1838 analysis_window->set_session(_session);
1840 analysis_window->show_all();
1843 analysis_window->set_regionmode();
1844 analysis_window->analyze();
1846 analysis_window->present();
1850 Editor::spectral_analyze_range_selection()
1852 if (analysis_window == 0) {
1853 analysis_window = new AnalysisWindow();
1856 analysis_window->set_session(_session);
1858 analysis_window->show_all();
1861 analysis_window->set_rangemode();
1862 analysis_window->analyze();
1864 analysis_window->present();
1868 Editor::build_track_selection_context_menu ()
1870 using namespace Menu_Helpers;
1871 MenuList& edit_items = track_selection_context_menu.items();
1872 edit_items.clear ();
1874 add_selection_context_items (edit_items);
1875 // edit_items.push_back (SeparatorElem());
1876 // add_dstream_context_items (edit_items);
1878 return &track_selection_context_menu;
1882 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1884 using namespace Menu_Helpers;
1886 /* OK, stick the region submenu at the top of the list, and then add
1890 RegionSelection rs = get_regions_from_selection_and_entered ();
1892 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1894 if (_popup_region_menu_item == 0) {
1895 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1896 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1897 _popup_region_menu_item->show ();
1899 _popup_region_menu_item->set_label (menu_item_name);
1902 /* No layering allowed in later is higher layering model */
1903 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1904 if (act && Config->get_layer_model() == LaterHigher) {
1905 act->set_sensitive (false);
1907 act->set_sensitive (true);
1910 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1912 edit_items.push_back (*_popup_region_menu_item);
1913 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1914 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1916 edit_items.push_back (SeparatorElem());
1919 /** Add context menu items relevant to selection ranges.
1920 * @param edit_items List to add the items to.
1923 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1925 using namespace Menu_Helpers;
1927 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1928 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1930 edit_items.push_back (SeparatorElem());
1931 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1933 edit_items.push_back (SeparatorElem());
1934 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1935 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1937 edit_items.push_back (SeparatorElem());
1939 edit_items.push_back (
1941 _("Move Range Start to Previous Region Boundary"),
1942 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1946 edit_items.push_back (
1948 _("Move Range Start to Next Region Boundary"),
1949 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1953 edit_items.push_back (
1955 _("Move Range End to Previous Region Boundary"),
1956 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1960 edit_items.push_back (
1962 _("Move Range End to Next Region Boundary"),
1963 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1967 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1969 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1971 edit_items.push_back (SeparatorElem());
1972 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1974 edit_items.push_back (SeparatorElem());
1975 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1976 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1977 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1979 edit_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1984 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1986 edit_items.push_back (SeparatorElem());
1987 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1988 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1989 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1990 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1991 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1992 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1993 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1999 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2001 using namespace Menu_Helpers;
2005 Menu *play_menu = manage (new Menu);
2006 MenuList& play_items = play_menu->items();
2007 play_menu->set_name ("ArdourContextMenu");
2009 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2010 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2011 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2012 play_items.push_back (SeparatorElem());
2013 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2015 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2019 Menu *select_menu = manage (new Menu);
2020 MenuList& select_items = select_menu->items();
2021 select_menu->set_name ("ArdourContextMenu");
2023 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2024 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2025 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2026 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2027 select_items.push_back (SeparatorElem());
2028 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2029 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2030 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2031 select_items.push_back (SeparatorElem());
2032 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2033 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2034 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2035 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2036 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2037 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2038 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2040 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2044 Menu *cutnpaste_menu = manage (new Menu);
2045 MenuList& cutnpaste_items = cutnpaste_menu->items();
2046 cutnpaste_menu->set_name ("ArdourContextMenu");
2048 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2049 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2050 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2052 cutnpaste_items.push_back (SeparatorElem());
2054 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2055 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2057 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2059 /* Adding new material */
2061 edit_items.push_back (SeparatorElem());
2062 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2063 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2067 Menu *nudge_menu = manage (new Menu());
2068 MenuList& nudge_items = nudge_menu->items();
2069 nudge_menu->set_name ("ArdourContextMenu");
2071 edit_items.push_back (SeparatorElem());
2072 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2075 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2077 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2081 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2083 using namespace Menu_Helpers;
2087 Menu *play_menu = manage (new Menu);
2088 MenuList& play_items = play_menu->items();
2089 play_menu->set_name ("ArdourContextMenu");
2091 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2092 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2093 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2097 Menu *select_menu = manage (new Menu);
2098 MenuList& select_items = select_menu->items();
2099 select_menu->set_name ("ArdourContextMenu");
2101 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2102 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2103 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2104 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2105 select_items.push_back (SeparatorElem());
2106 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2107 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2108 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2109 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2111 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2115 Menu *cutnpaste_menu = manage (new Menu);
2116 MenuList& cutnpaste_items = cutnpaste_menu->items();
2117 cutnpaste_menu->set_name ("ArdourContextMenu");
2119 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2120 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2121 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2123 Menu *nudge_menu = manage (new Menu());
2124 MenuList& nudge_items = nudge_menu->items();
2125 nudge_menu->set_name ("ArdourContextMenu");
2127 edit_items.push_back (SeparatorElem());
2128 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2129 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2130 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2131 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2133 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2137 Editor::grid_type() const
2143 Editor::grid_musical() const
2145 switch (_grid_type) {
2146 case GridTypeBeatDiv32:
2147 case GridTypeBeatDiv28:
2148 case GridTypeBeatDiv24:
2149 case GridTypeBeatDiv20:
2150 case GridTypeBeatDiv16:
2151 case GridTypeBeatDiv14:
2152 case GridTypeBeatDiv12:
2153 case GridTypeBeatDiv10:
2154 case GridTypeBeatDiv8:
2155 case GridTypeBeatDiv7:
2156 case GridTypeBeatDiv6:
2157 case GridTypeBeatDiv5:
2158 case GridTypeBeatDiv4:
2159 case GridTypeBeatDiv3:
2160 case GridTypeBeatDiv2:
2166 case GridTypeMinSec:
2167 case GridTypeSamples:
2174 Editor::grid_nonmusical() const
2176 switch (_grid_type) {
2178 case GridTypeMinSec:
2179 case GridTypeSamples:
2181 case GridTypeBeatDiv32:
2182 case GridTypeBeatDiv28:
2183 case GridTypeBeatDiv24:
2184 case GridTypeBeatDiv20:
2185 case GridTypeBeatDiv16:
2186 case GridTypeBeatDiv14:
2187 case GridTypeBeatDiv12:
2188 case GridTypeBeatDiv10:
2189 case GridTypeBeatDiv8:
2190 case GridTypeBeatDiv7:
2191 case GridTypeBeatDiv6:
2192 case GridTypeBeatDiv5:
2193 case GridTypeBeatDiv4:
2194 case GridTypeBeatDiv3:
2195 case GridTypeBeatDiv2:
2204 Editor::snap_mode() const
2210 Editor::set_grid_to (GridType gt)
2212 if (_grid_type == gt) { // already set
2216 unsigned int grid_ind = (unsigned int)gt;
2218 if (internal_editing()) {
2219 internal_grid_type = gt;
2221 pre_internal_grid_type = gt;
2226 if (grid_ind > grid_type_strings.size() - 1) {
2228 _grid_type = (GridType)grid_ind;
2231 string str = grid_type_strings[grid_ind];
2233 if (str != grid_type_selector.get_text()) {
2234 grid_type_selector.set_text (str);
2237 /* show appropriate rulers for this grid setting.
2238 * TODO: perhaps make this optional.
2239 * Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines
2241 if (grid_musical()) {
2242 ruler_tempo_action->set_active(true);
2243 ruler_meter_action->set_active(true);
2245 ruler_bbt_action->set_active(true);
2246 ruler_timecode_action->set_active(false);
2247 ruler_minsec_action->set_active(false);
2248 ruler_samples_action->set_active(false);
2249 } else if (_grid_type == GridTypeSmpte) {
2250 ruler_tempo_action->set_active(false);
2251 ruler_meter_action->set_active(false);
2253 ruler_bbt_action->set_active(false);
2254 ruler_timecode_action->set_active(true);
2255 ruler_minsec_action->set_active(false);
2256 ruler_samples_action->set_active(false);
2257 } else if (_grid_type == GridTypeMinSec) {
2258 ruler_tempo_action->set_active(false);
2259 ruler_meter_action->set_active(false);
2261 ruler_bbt_action->set_active(false);
2262 ruler_timecode_action->set_active(false);
2263 ruler_minsec_action->set_active(true);
2264 ruler_samples_action->set_active(false);
2265 } else if (_grid_type == GridTypeSamples) {
2266 ruler_tempo_action->set_active(false);
2267 ruler_meter_action->set_active(false);
2269 ruler_bbt_action->set_active(false);
2270 ruler_timecode_action->set_active(false);
2271 ruler_minsec_action->set_active(false);
2272 ruler_samples_action->set_active(true);
2277 if (grid_musical()) {
2278 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2279 update_tempo_based_rulers ();
2282 mark_region_boundary_cache_dirty ();
2284 redisplay_grid (false);
2286 SnapChanged (); /* EMIT SIGNAL */
2290 Editor::set_snap_mode (SnapMode mode)
2292 if (internal_editing()) {
2293 internal_snap_mode = mode;
2295 pre_internal_snap_mode = mode;
2300 if (_snap_mode == SnapOff) {
2301 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2303 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2310 Editor::set_edit_point_preference (EditPoint ep, bool force)
2312 bool changed = (_edit_point != ep);
2315 if (Profile->get_mixbus())
2316 if (ep == EditAtSelectedMarker)
2317 ep = EditAtPlayhead;
2319 string str = edit_point_strings[(int)ep];
2320 if (str != edit_point_selector.get_text ()) {
2321 edit_point_selector.set_text (str);
2324 update_all_enter_cursors();
2326 if (!force && !changed) {
2330 const char* action=NULL;
2332 switch (_edit_point) {
2333 case EditAtPlayhead:
2334 action = "edit-at-playhead";
2336 case EditAtSelectedMarker:
2337 action = "edit-at-marker";
2340 action = "edit-at-mouse";
2344 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2346 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2350 bool in_track_canvas;
2352 if (!mouse_sample (foo, in_track_canvas)) {
2353 in_track_canvas = false;
2356 reset_canvas_action_sensitivity (in_track_canvas);
2357 sensitize_the_right_region_actions (false);
2363 Editor::set_state (const XMLNode& node, int version)
2366 PBD::Unwinder<bool> nsi (no_save_instant, true);
2369 Tabbable::set_state (node, version);
2372 if (_session && node.get_property ("playhead", ph_pos)) {
2374 playhead_cursor->set_position (ph_pos);
2376 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2377 playhead_cursor->set_position (0);
2380 playhead_cursor->set_position (0);
2383 node.get_property ("mixer-width", editor_mixer_strip_width);
2385 node.get_property ("zoom-focus", zoom_focus);
2386 zoom_focus_selection_done (zoom_focus);
2389 if (node.get_property ("zoom", z)) {
2390 /* older versions of ardour used floating point samples_per_pixel */
2391 reset_zoom (llrintf (z));
2393 reset_zoom (samples_per_pixel);
2397 if (node.get_property ("visible-track-count", cnt)) {
2398 set_visible_track_count (cnt);
2402 if (!node.get_property ("grid-type", grid_type)) {
2403 grid_type = _grid_type;
2405 set_grid_to (grid_type);
2408 if (node.get_property ("snap-mode", sm)) {
2409 snap_mode_selection_done(sm);
2410 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2411 * snap_mode_selection_done() will only mark an already active item as active
2412 * which does not trigger set_text().
2416 set_snap_mode (_snap_mode);
2419 node.get_property ("internal-grid-type", internal_grid_type);
2420 node.get_property ("internal-snap-mode", internal_snap_mode);
2421 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2422 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2425 if (node.get_property ("mouse-mode", mm_str)) {
2426 MouseMode m = str2mousemode(mm_str);
2427 set_mouse_mode (m, true);
2429 set_mouse_mode (MouseObject, true);
2433 if (node.get_property ("left-frame", lf_pos)) {
2437 reset_x_origin (lf_pos);
2441 if (node.get_property ("y-origin", y_origin)) {
2442 reset_y_origin (y_origin);
2445 if (node.get_property ("join-object-range", yn)) {
2446 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2448 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2449 tact->set_active (!yn);
2450 tact->set_active (yn);
2452 set_mouse_mode(mouse_mode, true);
2456 if (node.get_property ("edit-point", ep)) {
2457 set_edit_point_preference (ep, true);
2459 set_edit_point_preference (_edit_point);
2462 if (node.get_property ("follow-playhead", yn)) {
2463 set_follow_playhead (yn);
2466 if (node.get_property ("stationary-playhead", yn)) {
2467 set_stationary_playhead (yn);
2470 RegionListSortType sort_type;
2471 if (node.get_property ("region-list-sort-type", sort_type)) {
2472 _regions->reset_sort_type (sort_type, true);
2475 if (node.get_property ("show-editor-mixer", yn)) {
2477 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2480 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2482 /* do it twice to force the change */
2484 tact->set_active (!yn);
2485 tact->set_active (yn);
2488 if (node.get_property ("show-editor-list", yn)) {
2490 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2493 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2495 /* do it twice to force the change */
2497 tact->set_active (!yn);
2498 tact->set_active (yn);
2502 if (node.get_property (X_("editor-list-page"), el_page)) {
2503 _the_notebook.set_current_page (el_page);
2506 if (node.get_property (X_("show-marker-lines"), yn)) {
2507 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2509 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2511 tact->set_active (!yn);
2512 tact->set_active (yn);
2515 XMLNodeList children = node.children ();
2516 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2517 selection->set_state (**i, Stateful::current_state_version);
2518 _regions->set_state (**i);
2519 _locations->set_state (**i);
2522 if (node.get_property ("maximised", yn)) {
2523 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2525 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2526 bool fs = tact && tact->get_active();
2528 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2532 samplepos_t nudge_clock_value;
2533 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2534 nudge_clock->set (nudge_clock_value);
2536 nudge_clock->set_mode (AudioClock::Timecode);
2537 nudge_clock->set (_session->sample_rate() * 5, true);
2542 * Not all properties may have been in XML, but
2543 * those that are linked to a private variable may need changing
2547 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2548 yn = _follow_playhead;
2550 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2551 if (tact->get_active() != yn) {
2552 tact->set_active (yn);
2556 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2557 yn = _stationary_playhead;
2559 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2560 if (tact->get_active() != yn) {
2561 tact->set_active (yn);
2566 return LuaInstance::instance()->set_state(node);
2570 Editor::get_state ()
2572 XMLNode* node = new XMLNode (X_("Editor"));
2574 node->set_property ("id", id().to_s ());
2576 node->add_child_nocopy (Tabbable::get_state());
2578 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2579 node->set_property("notebook-shrunk", _notebook_shrunk);
2580 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2582 maybe_add_mixer_strip_width (*node);
2584 node->set_property ("zoom-focus", zoom_focus);
2586 node->set_property ("zoom", samples_per_pixel);
2587 node->set_property ("grid-type", _grid_type);
2588 node->set_property ("snap-mode", _snap_mode);
2589 node->set_property ("internal-grid-type", internal_grid_type);
2590 node->set_property ("internal-snap-mode", internal_snap_mode);
2591 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2592 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2593 node->set_property ("edit-point", _edit_point);
2594 node->set_property ("visible-track-count", _visible_track_count);
2596 node->set_property ("playhead", playhead_cursor->current_sample ());
2597 node->set_property ("left-frame", _leftmost_sample);
2598 node->set_property ("y-origin", vertical_adjustment.get_value ());
2600 node->set_property ("maximised", _maximised);
2601 node->set_property ("follow-playhead", _follow_playhead);
2602 node->set_property ("stationary-playhead", _stationary_playhead);
2603 node->set_property ("region-list-sort-type", _regions->sort_type ());
2604 node->set_property ("mouse-mode", mouse_mode);
2605 node->set_property ("join-object-range", smart_mode_action->get_active ());
2607 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2609 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2610 node->set_property (X_("show-editor-mixer"), tact->get_active());
2613 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2615 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2616 node->set_property (X_("show-editor-list"), tact->get_active());
2619 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2621 if (button_bindings) {
2622 XMLNode* bb = new XMLNode (X_("Buttons"));
2623 button_bindings->save (*bb);
2624 node->add_child_nocopy (*bb);
2627 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2629 node->add_child_nocopy (selection->get_state ());
2630 node->add_child_nocopy (_regions->get_state ());
2632 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2634 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2635 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2636 node->add_child_nocopy (_locations->get_state ());
2641 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2642 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2644 * @return pair: TimeAxisView that y is over, layer index.
2646 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2647 * in stacked or expanded region display mode, otherwise 0.
2649 std::pair<TimeAxisView *, double>
2650 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2652 if (!trackview_relative_offset) {
2653 y -= _trackview_group->canvas_origin().y;
2657 return std::make_pair ((TimeAxisView *) 0, 0);
2660 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2662 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2669 return std::make_pair ((TimeAxisView *) 0, 0);
2673 Editor::set_snapped_cursor_position (samplepos_t pos)
2675 if (_edit_point == EditAtMouse) {
2676 snapped_cursor->set_position(pos);
2681 /** Snap a position to the grid, if appropriate, taking into account current
2682 * grid settings and also the state of any snap modifier keys that may be pressed.
2683 * @param start Position to snap.
2684 * @param event Event to get current key modifier information from, or 0.
2687 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
2689 if (!_session || !event) {
2693 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2694 if (_snap_mode == SnapOff) {
2695 snap_to_internal (start, direction, pref, for_mark);
2697 start.set (start.sample, 0);
2700 if (_snap_mode != SnapOff) {
2701 snap_to_internal (start, direction, pref, for_mark);
2702 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2703 /* SnapOff, but we pressed the snap_delta modifier */
2704 snap_to_internal (start, direction, pref, for_mark);
2706 start.set (start.sample, 0);
2712 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2714 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2715 start.set (start.sample, 0);
2719 snap_to_internal (start, direction, pref, for_mark, ensure_snap);
2723 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2725 samplepos_t diff = abs (test - presnap);
2731 test = max_samplepos; // reset this so it doesn't get accidentally reused
2735 Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
2737 if (marks.empty()) return presnap;
2741 samplepos_t test = presnap;
2743 before = after = max_samplepos;
2745 /* get marks to either side of presnap */
2746 vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
2747 while (m != marks.end() && (m->position < presnap)) {
2751 if (m == marks.end ()) {
2752 /* ran out of marks */
2753 before = marks.back().position;
2756 after = m->position;
2758 if (m != marks.begin ()) {
2760 before = m->position;
2763 if (before == max_samplepos && after == max_samplepos) {
2764 /* No grid to snap to, so just don't snap */
2766 } else if (before == max_samplepos) {
2768 } else if (after == max_samplepos) {
2771 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2773 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2775 else if (direction == 0) {
2776 if ((presnap - before) < (after - presnap)) {
2788 Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
2794 _session->locations()->marks_either_side (presnap, before, after);
2796 if (before == max_samplepos && after == max_samplepos) {
2797 /* No marks to snap to, so just don't snap */
2799 } else if (before == max_samplepos) {
2801 } else if (after == max_samplepos) {
2804 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2806 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2808 } else if (direction == 0) {
2809 if ((presnap - before) < (after - presnap)) {
2821 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2823 const samplepos_t presnap = start.sample;
2825 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2826 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2827 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2829 /* check snap-to-marker */
2830 if (UIConfiguration::instance().get_snap_to_marks()) {
2835 test = marker_snap_to_internal (presnap, direction);
2836 check_best_snap(presnap, test, dist, best);
2839 /* check snap-to-region-{start/end/sync} */
2840 if (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync()) {
2841 if (!region_boundary_cache.empty()) {
2843 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2844 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2846 if (direction > 0) {
2847 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2849 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2852 if (next != region_boundary_cache.begin ()) {
2857 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2858 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2860 if (presnap > (p + n) / 2) {
2867 check_best_snap(presnap, test, dist, best);
2871 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
2872 test = snap_to_grid (grid_marks, presnap, direction);
2873 check_best_snap(presnap, test, dist, best);
2876 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
2877 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
2878 * ToDo: Perhaps this should only occur if EditPointMouse?
2880 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2882 start.set (best, 0);
2884 } else if (presnap > best) {
2885 if (presnap > (best+ snap_threshold_s)) {
2888 } else if (presnap < best) {
2889 if (presnap < (best - snap_threshold_s)) {
2894 start.set (best, 0);
2899 Editor::setup_toolbar ()
2901 HBox* mode_box = manage(new HBox);
2902 mode_box->set_border_width (2);
2903 mode_box->set_spacing(2);
2905 HBox* mouse_mode_box = manage (new HBox);
2906 HBox* mouse_mode_hbox = manage (new HBox);
2907 VBox* mouse_mode_vbox = manage (new VBox);
2908 Alignment* mouse_mode_align = manage (new Alignment);
2910 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2911 mouse_mode_size_group->add_widget (smart_mode_button);
2912 mouse_mode_size_group->add_widget (mouse_move_button);
2913 mouse_mode_size_group->add_widget (mouse_cut_button);
2914 mouse_mode_size_group->add_widget (mouse_select_button);
2915 mouse_mode_size_group->add_widget (mouse_timefx_button);
2916 mouse_mode_size_group->add_widget (mouse_audition_button);
2917 mouse_mode_size_group->add_widget (mouse_draw_button);
2918 mouse_mode_size_group->add_widget (mouse_content_button);
2920 if (!Profile->get_mixbus()) {
2921 mouse_mode_size_group->add_widget (zoom_in_button);
2922 mouse_mode_size_group->add_widget (zoom_out_button);
2923 mouse_mode_size_group->add_widget (zoom_out_full_button);
2924 mouse_mode_size_group->add_widget (zoom_focus_selector);
2925 mouse_mode_size_group->add_widget (tav_shrink_button);
2926 mouse_mode_size_group->add_widget (tav_expand_button);
2928 mouse_mode_size_group->add_widget (zoom_preset_selector);
2929 mouse_mode_size_group->add_widget (visible_tracks_selector);
2932 mouse_mode_size_group->add_widget (grid_type_selector);
2933 mouse_mode_size_group->add_widget (snap_mode_button);
2935 mouse_mode_size_group->add_widget (edit_point_selector);
2936 mouse_mode_size_group->add_widget (edit_mode_selector);
2938 mouse_mode_size_group->add_widget (*nudge_clock);
2939 mouse_mode_size_group->add_widget (nudge_forward_button);
2940 mouse_mode_size_group->add_widget (nudge_backward_button);
2942 mouse_mode_hbox->set_spacing (2);
2944 if (!ARDOUR::Profile->get_trx()) {
2945 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2948 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2949 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2951 if (!ARDOUR::Profile->get_mixbus()) {
2952 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2953 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2956 if (!ARDOUR::Profile->get_trx()) {
2957 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2958 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2959 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2962 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2964 mouse_mode_align->add (*mouse_mode_vbox);
2965 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2967 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2969 edit_mode_selector.set_name ("mouse mode button");
2971 if (!ARDOUR::Profile->get_trx()) {
2972 mode_box->pack_start (edit_mode_selector, false, false);
2973 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2974 mode_box->pack_start (edit_point_selector, false, false);
2975 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2978 mode_box->pack_start (*mouse_mode_box, false, false);
2982 _zoom_box.set_spacing (2);
2983 _zoom_box.set_border_width (2);
2987 zoom_preset_selector.set_name ("zoom button");
2988 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
2990 zoom_in_button.set_name ("zoom button");
2991 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2992 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2993 zoom_in_button.set_related_action (act);
2995 zoom_out_button.set_name ("zoom button");
2996 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2997 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2998 zoom_out_button.set_related_action (act);
3000 zoom_out_full_button.set_name ("zoom button");
3001 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3002 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3003 zoom_out_full_button.set_related_action (act);
3005 zoom_focus_selector.set_name ("zoom button");
3007 if (ARDOUR::Profile->get_mixbus()) {
3008 _zoom_box.pack_start (zoom_preset_selector, false, false);
3009 } else if (ARDOUR::Profile->get_trx()) {
3010 mode_box->pack_start (zoom_out_button, false, false);
3011 mode_box->pack_start (zoom_in_button, false, false);
3013 _zoom_box.pack_start (zoom_out_button, false, false);
3014 _zoom_box.pack_start (zoom_in_button, false, false);
3015 _zoom_box.pack_start (zoom_out_full_button, false, false);
3016 _zoom_box.pack_start (zoom_focus_selector, false, false);
3019 /* Track zoom buttons */
3020 _track_box.set_spacing (2);
3021 _track_box.set_border_width (2);
3023 visible_tracks_selector.set_name ("zoom button");
3024 if (Profile->get_mixbus()) {
3025 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3027 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3030 tav_expand_button.set_name ("zoom button");
3031 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3032 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3033 tav_expand_button.set_related_action (act);
3035 tav_shrink_button.set_name ("zoom button");
3036 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3037 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3038 tav_shrink_button.set_related_action (act);
3040 if (ARDOUR::Profile->get_mixbus()) {
3041 _track_box.pack_start (visible_tracks_selector);
3042 } else if (ARDOUR::Profile->get_trx()) {
3043 _track_box.pack_start (tav_shrink_button);
3044 _track_box.pack_start (tav_expand_button);
3046 _track_box.pack_start (visible_tracks_selector);
3047 _track_box.pack_start (tav_shrink_button);
3048 _track_box.pack_start (tav_expand_button);
3051 snap_box.set_spacing (2);
3052 snap_box.set_border_width (2);
3054 grid_type_selector.set_name ("mouse mode button");
3056 snap_mode_button.set_name ("mouse mode button");
3058 edit_point_selector.set_name ("mouse mode button");
3060 snap_box.pack_start (snap_mode_button, false, false);
3061 snap_box.pack_start (grid_type_selector, false, false);
3065 HBox *nudge_box = manage (new HBox);
3066 nudge_box->set_spacing (2);
3067 nudge_box->set_border_width (2);
3069 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3070 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3072 nudge_box->pack_start (nudge_backward_button, false, false);
3073 nudge_box->pack_start (nudge_forward_button, false, false);
3074 nudge_box->pack_start (*nudge_clock, false, false);
3077 /* Pack everything in... */
3079 toolbar_hbox.set_spacing (2);
3080 toolbar_hbox.set_border_width (2);
3082 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3083 tool_shadow->set_size_request (4, -1);
3084 tool_shadow->show();
3086 ebox_hpacker.pack_start (*tool_shadow, false, false);
3087 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3089 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3090 spacer->set_name("EditorWindow");
3091 spacer->set_size_request(-1,4);
3094 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3095 ebox_vpacker.pack_start(*spacer, false, false);
3096 ebox_vpacker.show();
3098 toolbar_hbox.pack_start (*mode_box, false, false);
3100 if (!ARDOUR::Profile->get_trx()) {
3102 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3104 toolbar_hbox.pack_start (snap_box, false, false);
3106 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3108 toolbar_hbox.pack_start (*nudge_box, false, false);
3110 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3112 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3114 toolbar_hbox.pack_end (_track_box, false, false);
3118 toolbar_hbox.show_all ();
3122 Editor::build_edit_point_menu ()
3124 using namespace Menu_Helpers;
3126 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3127 if(!Profile->get_mixbus())
3128 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3129 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3131 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3135 Editor::build_edit_mode_menu ()
3137 using namespace Menu_Helpers;
3139 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3140 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3141 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3142 /* Note: Splice was removed */
3144 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3148 Editor::build_grid_type_menu ()
3150 using namespace Menu_Helpers;
3152 /* main grid: bars, quarter-notes, etc */
3153 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3154 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3155 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3156 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3157 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3158 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3159 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3160 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3163 grid_type_selector.AddMenuElem(SeparatorElem());
3164 Gtk::Menu *_triplet_menu = manage (new Menu);
3165 MenuList& triplet_items (_triplet_menu->items());
3167 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3168 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3169 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3170 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3172 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3174 /* quintuplet grid */
3175 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3176 MenuList& quintuplet_items (_quintuplet_menu->items());
3178 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3179 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3180 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3182 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3184 /* septuplet grid */
3185 Gtk::Menu *_septuplet_menu = manage (new Menu);
3186 MenuList& septuplet_items (_septuplet_menu->items());
3188 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3189 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3190 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3192 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3194 grid_type_selector.AddMenuElem(SeparatorElem());
3195 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeSmpte], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSmpte)));
3196 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3197 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeSamples], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSamples)));
3199 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
3203 Editor::setup_tooltips ()
3205 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3206 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3207 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3208 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3209 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3210 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3211 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3212 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3213 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3214 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3215 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3216 set_tooltip (zoom_in_button, _("Zoom In"));
3217 set_tooltip (zoom_out_button, _("Zoom Out"));
3218 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3219 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3220 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3221 set_tooltip (tav_expand_button, _("Expand Tracks"));
3222 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3223 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3224 set_tooltip (grid_type_selector, _("Grid Mode"));
3225 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3226 set_tooltip (edit_point_selector, _("Edit Point"));
3227 set_tooltip (edit_mode_selector, _("Edit Mode"));
3228 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3232 Editor::convert_drop_to_paths (
3233 vector<string>& paths,
3234 const RefPtr<Gdk::DragContext>& /*context*/,
3237 const SelectionData& data,
3241 if (_session == 0) {
3245 vector<string> uris = data.get_uris();
3249 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3250 are actually URI lists. So do it by hand.
3253 if (data.get_target() != "text/plain") {
3257 /* Parse the "uri-list" format that Nautilus provides,
3258 where each pathname is delimited by \r\n.
3260 THERE MAY BE NO NULL TERMINATING CHAR!!!
3263 string txt = data.get_text();
3267 p = (char *) malloc (txt.length() + 1);
3268 txt.copy (p, txt.length(), 0);
3269 p[txt.length()] = '\0';
3275 while (g_ascii_isspace (*p))
3279 while (*q && (*q != '\n') && (*q != '\r')) {
3286 while (q > p && g_ascii_isspace (*q))
3291 uris.push_back (string (p, q - p + 1));
3295 p = strchr (p, '\n');
3307 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3308 if ((*i).substr (0,7) == "file://") {
3309 paths.push_back (Glib::filename_from_uri (*i));
3317 Editor::new_tempo_section ()
3322 Editor::map_transport_state ()
3324 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3326 if (_session && _session->transport_stopped()) {
3327 have_pending_keyboard_selection = false;
3330 update_loop_range_view ();
3334 Editor::transport_looped ()
3336 /* reset Playhead position interpolation.
3337 * see Editor::super_rapid_screen_update
3339 _last_update_time = 0;
3345 Editor::begin_selection_op_history ()
3347 selection_op_cmd_depth = 0;
3348 selection_op_history_it = 0;
3350 while(!selection_op_history.empty()) {
3351 delete selection_op_history.front();
3352 selection_op_history.pop_front();
3355 selection_undo_action->set_sensitive (false);
3356 selection_redo_action->set_sensitive (false);
3357 selection_op_history.push_front (&_selection_memento->get_state ());
3361 Editor::begin_reversible_selection_op (string name)
3364 //cerr << name << endl;
3365 /* begin/commit pairs can be nested */
3366 selection_op_cmd_depth++;
3371 Editor::commit_reversible_selection_op ()
3374 if (selection_op_cmd_depth == 1) {
3376 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3377 /* The user has undone some selection ops and then made a new one,
3378 * making anything earlier in the list invalid.
3381 list<XMLNode *>::iterator it = selection_op_history.begin();
3382 list<XMLNode *>::iterator e_it = it;
3383 advance (e_it, selection_op_history_it);
3385 for (; it != e_it; ++it) {
3388 selection_op_history.erase (selection_op_history.begin(), e_it);
3391 selection_op_history.push_front (&_selection_memento->get_state ());
3392 selection_op_history_it = 0;
3394 selection_undo_action->set_sensitive (true);
3395 selection_redo_action->set_sensitive (false);
3398 if (selection_op_cmd_depth > 0) {
3399 selection_op_cmd_depth--;
3405 Editor::undo_selection_op ()
3408 selection_op_history_it++;
3410 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3411 if (n == selection_op_history_it) {
3412 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3413 selection_redo_action->set_sensitive (true);
3417 /* is there an earlier entry? */
3418 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3419 selection_undo_action->set_sensitive (false);
3425 Editor::redo_selection_op ()
3428 if (selection_op_history_it > 0) {
3429 selection_op_history_it--;
3432 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3433 if (n == selection_op_history_it) {
3434 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3435 selection_undo_action->set_sensitive (true);
3440 if (selection_op_history_it == 0) {
3441 selection_redo_action->set_sensitive (false);
3447 Editor::begin_reversible_command (string name)
3450 before.push_back (&_selection_memento->get_state ());
3451 _session->begin_reversible_command (name);
3456 Editor::begin_reversible_command (GQuark q)
3459 before.push_back (&_selection_memento->get_state ());
3460 _session->begin_reversible_command (q);
3465 Editor::abort_reversible_command ()
3468 while(!before.empty()) {
3469 delete before.front();
3472 _session->abort_reversible_command ();
3477 Editor::commit_reversible_command ()
3480 if (before.size() == 1) {
3481 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3482 redo_action->set_sensitive(false);
3483 undo_action->set_sensitive(true);
3484 begin_selection_op_history ();
3487 if (before.empty()) {
3488 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3493 _session->commit_reversible_command ();
3498 Editor::history_changed ()
3502 if (undo_action && _session) {
3503 if (_session->undo_depth() == 0) {
3504 label = S_("Command|Undo");
3506 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3508 undo_action->property_label() = label;
3511 if (redo_action && _session) {
3512 if (_session->redo_depth() == 0) {
3514 redo_action->set_sensitive (false);
3516 label = string_compose(_("Redo (%1)"), _session->next_redo());
3517 redo_action->set_sensitive (true);
3519 redo_action->property_label() = label;
3524 Editor::duplicate_range (bool with_dialog)
3528 RegionSelection rs = get_regions_from_selection_and_entered ();
3530 if (selection->time.length() == 0 && rs.empty()) {
3536 ArdourDialog win (_("Duplicate"));
3537 Label label (_("Number of duplications:"));
3538 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3539 SpinButton spinner (adjustment, 0.0, 1);
3542 win.get_vbox()->set_spacing (12);
3543 win.get_vbox()->pack_start (hbox);
3544 hbox.set_border_width (6);
3545 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3547 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3548 place, visually. so do this by hand.
3551 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3552 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3553 spinner.grab_focus();
3559 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3560 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3561 win.set_default_response (RESPONSE_ACCEPT);
3563 spinner.grab_focus ();
3565 switch (win.run ()) {
3566 case RESPONSE_ACCEPT:
3572 times = adjustment.get_value();
3575 if ((current_mouse_mode() == MouseRange)) {
3576 if (selection->time.length()) {
3577 duplicate_selection (times);
3579 } else if (get_smart_mode()) {
3580 if (selection->time.length()) {
3581 duplicate_selection (times);
3583 duplicate_some_regions (rs, times);
3585 duplicate_some_regions (rs, times);
3590 Editor::set_edit_mode (EditMode m)
3592 Config->set_edit_mode (m);
3596 Editor::cycle_edit_mode ()
3598 switch (Config->get_edit_mode()) {
3600 Config->set_edit_mode (Ripple);
3604 Config->set_edit_mode (Lock);
3607 Config->set_edit_mode (Slide);
3613 Editor::edit_mode_selection_done (EditMode m)
3615 Config->set_edit_mode (m);
3619 Editor::grid_type_selection_done (GridType gridtype)
3621 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3623 ract->set_active ();
3628 Editor::snap_mode_selection_done (SnapMode mode)
3630 RefPtr<RadioAction> ract = snap_mode_action (mode);
3633 ract->set_active (true);
3638 Editor::cycle_edit_point (bool with_marker)
3640 if(Profile->get_mixbus())
3641 with_marker = false;
3643 switch (_edit_point) {
3645 set_edit_point_preference (EditAtPlayhead);
3647 case EditAtPlayhead:
3649 set_edit_point_preference (EditAtSelectedMarker);
3651 set_edit_point_preference (EditAtMouse);
3654 case EditAtSelectedMarker:
3655 set_edit_point_preference (EditAtMouse);
3661 Editor::edit_point_selection_done (EditPoint ep)
3663 set_edit_point_preference (ep);
3667 Editor::build_zoom_focus_menu ()
3669 using namespace Menu_Helpers;
3671 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3672 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3673 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3674 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3675 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3676 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3678 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3682 Editor::zoom_focus_selection_done (ZoomFocus f)
3684 RefPtr<RadioAction> ract = zoom_focus_action (f);
3686 ract->set_active ();
3691 Editor::build_track_count_menu ()
3693 using namespace Menu_Helpers;
3695 if (!Profile->get_mixbus()) {
3696 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3697 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3698 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3699 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3700 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3721 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3722 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3723 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3724 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3725 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3731 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3732 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3737 Editor::set_zoom_preset (int64_t ms)
3740 temporal_zoom_session();
3744 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3745 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3749 Editor::set_visible_track_count (int32_t n)
3751 _visible_track_count = n;
3753 /* if the canvas hasn't really been allocated any size yet, just
3754 record the desired number of visible tracks and return. when canvas
3755 allocation happens, we will get called again and then we can do the
3759 if (_visible_canvas_height <= 1) {
3765 DisplaySuspender ds;
3767 if (_visible_track_count > 0) {
3768 h = trackviews_height() / _visible_track_count;
3769 std::ostringstream s;
3770 s << _visible_track_count;
3772 } else if (_visible_track_count == 0) {
3774 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3775 if ((*i)->marked_for_display()) {
3777 TimeAxisView::Children cl ((*i)->get_child_list ());
3778 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3779 if ((*j)->marked_for_display()) {
3786 visible_tracks_selector.set_text (X_("*"));
3789 h = trackviews_height() / n;
3792 /* negative value means that the visible track count has
3793 been overridden by explicit track height changes.
3795 visible_tracks_selector.set_text (X_("*"));
3799 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3800 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3803 if (str != visible_tracks_selector.get_text()) {
3804 visible_tracks_selector.set_text (str);
3809 Editor::override_visible_track_count ()
3811 _visible_track_count = -1;
3812 visible_tracks_selector.set_text (_("*"));
3816 Editor::edit_controls_button_release (GdkEventButton* ev)
3818 if (Keyboard::is_context_menu_event (ev)) {
3819 ARDOUR_UI::instance()->add_route ();
3820 } else if (ev->button == 1) {
3821 selection->clear_tracks ();
3828 Editor::mouse_select_button_release (GdkEventButton* ev)
3830 /* this handles just right-clicks */
3832 if (ev->button != 3) {
3840 Editor::set_zoom_focus (ZoomFocus f)
3842 string str = zoom_focus_strings[(int)f];
3844 if (str != zoom_focus_selector.get_text()) {
3845 zoom_focus_selector.set_text (str);
3848 if (zoom_focus != f) {
3855 Editor::cycle_zoom_focus ()
3857 switch (zoom_focus) {
3859 set_zoom_focus (ZoomFocusRight);
3861 case ZoomFocusRight:
3862 set_zoom_focus (ZoomFocusCenter);
3864 case ZoomFocusCenter:
3865 set_zoom_focus (ZoomFocusPlayhead);
3867 case ZoomFocusPlayhead:
3868 set_zoom_focus (ZoomFocusMouse);
3870 case ZoomFocusMouse:
3871 set_zoom_focus (ZoomFocusEdit);
3874 set_zoom_focus (ZoomFocusLeft);
3880 Editor::update_grid ()
3882 if (grid_musical()) {
3883 std::vector<TempoMap::BBTPoint> grid;
3884 if (bbt_ruler_scale != bbt_show_many) {
3885 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3887 maybe_draw_grid_lines ();
3888 } else if (grid_nonmusical()) {
3889 maybe_draw_grid_lines ();
3896 Editor::toggle_follow_playhead ()
3898 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3900 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3901 set_follow_playhead (tact->get_active());
3905 /** @param yn true to follow playhead, otherwise false.
3906 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3909 Editor::set_follow_playhead (bool yn, bool catch_up)
3911 if (_follow_playhead != yn) {
3912 if ((_follow_playhead = yn) == true && catch_up) {
3914 reset_x_origin_to_follow_playhead ();
3921 Editor::toggle_stationary_playhead ()
3923 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3925 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3926 set_stationary_playhead (tact->get_active());
3931 Editor::set_stationary_playhead (bool yn)
3933 if (_stationary_playhead != yn) {
3934 if ((_stationary_playhead = yn) == true) {
3935 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
3936 // update_current_screen ();
3943 Editor::playlist_selector () const
3945 return *_playlist_selector;
3949 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
3951 if (paste_count == 0) {
3952 /* don't bother calculating an offset that will be zero anyway */
3956 /* calculate basic unsnapped multi-paste offset */
3957 samplecnt_t offset = paste_count * duration;
3959 /* snap offset so pos + offset is aligned to the grid */
3960 MusicSample offset_pos (pos + offset, 0);
3961 snap_to(offset_pos, RoundUpMaybe);
3962 offset = offset_pos.sample - pos;
3968 Editor::get_grid_beat_divisions(samplepos_t position)
3970 switch (_grid_type) {
3971 case GridTypeBeatDiv32: return 32;
3972 case GridTypeBeatDiv28: return 28;
3973 case GridTypeBeatDiv24: return 24;
3974 case GridTypeBeatDiv20: return 20;
3975 case GridTypeBeatDiv16: return 16;
3976 case GridTypeBeatDiv14: return 14;
3977 case GridTypeBeatDiv12: return 12;
3978 case GridTypeBeatDiv10: return 10;
3979 case GridTypeBeatDiv8: return 8;
3980 case GridTypeBeatDiv7: return 7;
3981 case GridTypeBeatDiv6: return 6;
3982 case GridTypeBeatDiv5: return 5;
3983 case GridTypeBeatDiv4: return 4;
3984 case GridTypeBeatDiv3: return 3;
3985 case GridTypeBeatDiv2: return 2;
3987 case GridTypeNone: return 0;
3988 case GridTypeSmpte: return 0;
3989 case GridTypeMinSec: return 0;
3990 case GridTypeSamples: return 0;
3996 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
3997 if the grid is non-musical, returns 0.
3998 if the grid is snapped to bars, returns -1.
3999 @param event_state the current keyboard modifier mask.
4002 Editor::get_grid_music_divisions (uint32_t event_state)
4004 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4008 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4012 switch (_grid_type) {
4013 case GridTypeBeatDiv32: return 32;
4014 case GridTypeBeatDiv28: return 28;
4015 case GridTypeBeatDiv24: return 24;
4016 case GridTypeBeatDiv20: return 20;
4017 case GridTypeBeatDiv16: return 16;
4018 case GridTypeBeatDiv14: return 14;
4019 case GridTypeBeatDiv12: return 12;
4020 case GridTypeBeatDiv10: return 10;
4021 case GridTypeBeatDiv8: return 8;
4022 case GridTypeBeatDiv7: return 7;
4023 case GridTypeBeatDiv6: return 6;
4024 case GridTypeBeatDiv5: return 5;
4025 case GridTypeBeatDiv4: return 4;
4026 case GridTypeBeatDiv3: return 3;
4027 case GridTypeBeatDiv2: return 2;
4028 case GridTypeBeat: return 1;
4029 case GridTypeBar : return -1;
4031 case GridTypeNone: return 0;
4032 case GridTypeSmpte: return 0;
4033 case GridTypeMinSec: return 0;
4034 case GridTypeSamples: return 0;
4040 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4044 const unsigned divisions = get_grid_beat_divisions(position);
4046 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4049 switch (_grid_type) {
4051 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4054 const Meter& m = _session->tempo_map().meter_at_sample (position);
4055 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4063 return Temporal::Beats();
4067 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4071 ret = nudge_clock->current_duration (pos);
4072 next = ret + 1; /* XXXX fix me */
4078 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4080 ArdourDialog dialog (_("Playlist Deletion"));
4081 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4082 "If it is kept, its audio files will not be cleaned.\n"
4083 "If it is deleted, audio files used by it alone will be cleaned."),
4086 dialog.set_position (WIN_POS_CENTER);
4087 dialog.get_vbox()->pack_start (label);
4091 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4092 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4093 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4094 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4095 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4097 /* by default gtk uses the left most button */
4098 keep->grab_focus ();
4100 switch (dialog.run ()) {
4102 /* keep this and all remaining ones */
4107 /* delete this and all others */
4111 case RESPONSE_ACCEPT:
4112 /* delete the playlist */
4116 case RESPONSE_REJECT:
4117 /* keep the playlist */
4129 Editor::audio_region_selection_covers (samplepos_t where)
4131 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4132 if ((*a)->region()->covers (where)) {
4141 Editor::prepare_for_cleanup ()
4143 cut_buffer->clear_regions ();
4144 cut_buffer->clear_playlists ();
4146 selection->clear_regions ();
4147 selection->clear_playlists ();
4149 _regions->suspend_redisplay ();
4153 Editor::finish_cleanup ()
4155 _regions->resume_redisplay ();
4159 Editor::transport_loop_location()
4162 return _session->locations()->auto_loop_location();
4169 Editor::transport_punch_location()
4172 return _session->locations()->auto_punch_location();
4179 Editor::control_layout_scroll (GdkEventScroll* ev)
4181 /* Just forward to the normal canvas scroll method. The coordinate
4182 systems are different but since the canvas is always larger than the
4183 track headers, and aligned with the trackview area, this will work.
4185 In the not too distant future this layout is going away anyway and
4186 headers will be on the canvas.
4188 return canvas_scroll_event (ev, false);
4192 Editor::session_state_saved (string)
4195 _snapshots->redisplay ();
4199 Editor::maximise_editing_space ()
4205 Gtk::Window* toplevel = current_toplevel();
4208 toplevel->fullscreen ();
4214 Editor::restore_editing_space ()
4220 Gtk::Window* toplevel = current_toplevel();
4223 toplevel->unfullscreen();
4229 * Make new playlists for a given track and also any others that belong
4230 * to the same active route group with the `select' property.
4235 Editor::new_playlists (TimeAxisView* v)
4237 begin_reversible_command (_("new playlists"));
4238 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4239 _session->playlists->get (playlists);
4240 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4241 commit_reversible_command ();
4245 * Use a copy of the current playlist for a given track and also any others that belong
4246 * to the same active route group with the `select' property.
4251 Editor::copy_playlists (TimeAxisView* v)
4253 begin_reversible_command (_("copy playlists"));
4254 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4255 _session->playlists->get (playlists);
4256 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4257 commit_reversible_command ();
4260 /** Clear the current playlist for a given track and also any others that belong
4261 * to the same active route group with the `select' property.
4266 Editor::clear_playlists (TimeAxisView* v)
4268 begin_reversible_command (_("clear playlists"));
4269 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4270 _session->playlists->get (playlists);
4271 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4272 commit_reversible_command ();
4276 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4278 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4282 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4284 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4288 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4290 atv.clear_playlist ();
4294 Editor::get_y_origin () const
4296 return vertical_adjustment.get_value ();
4299 /** Queue up a change to the viewport x origin.
4300 * @param sample New x origin.
4303 Editor::reset_x_origin (samplepos_t sample)
4305 pending_visual_change.add (VisualChange::TimeOrigin);
4306 pending_visual_change.time_origin = sample;
4307 ensure_visual_change_idle_handler ();
4311 Editor::reset_y_origin (double y)
4313 pending_visual_change.add (VisualChange::YOrigin);
4314 pending_visual_change.y_origin = y;
4315 ensure_visual_change_idle_handler ();
4319 Editor::reset_zoom (samplecnt_t spp)
4321 if (spp == samples_per_pixel) {
4325 pending_visual_change.add (VisualChange::ZoomLevel);
4326 pending_visual_change.samples_per_pixel = spp;
4327 ensure_visual_change_idle_handler ();
4331 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4333 reset_x_origin (sample);
4336 if (!no_save_visual) {
4337 undo_visual_stack.push_back (current_visual_state(false));
4341 Editor::VisualState::VisualState (bool with_tracks)
4342 : gui_state (with_tracks ? new GUIObjectState : 0)
4346 Editor::VisualState::~VisualState ()
4351 Editor::VisualState*
4352 Editor::current_visual_state (bool with_tracks)
4354 VisualState* vs = new VisualState (with_tracks);
4355 vs->y_position = vertical_adjustment.get_value();
4356 vs->samples_per_pixel = samples_per_pixel;
4357 vs->_leftmost_sample = _leftmost_sample;
4358 vs->zoom_focus = zoom_focus;
4361 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4368 Editor::undo_visual_state ()
4370 if (undo_visual_stack.empty()) {
4374 VisualState* vs = undo_visual_stack.back();
4375 undo_visual_stack.pop_back();
4378 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4381 use_visual_state (*vs);
4386 Editor::redo_visual_state ()
4388 if (redo_visual_stack.empty()) {
4392 VisualState* vs = redo_visual_stack.back();
4393 redo_visual_stack.pop_back();
4395 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4396 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4399 use_visual_state (*vs);
4404 Editor::swap_visual_state ()
4406 if (undo_visual_stack.empty()) {
4407 redo_visual_state ();
4409 undo_visual_state ();
4414 Editor::use_visual_state (VisualState& vs)
4416 PBD::Unwinder<bool> nsv (no_save_visual, true);
4417 DisplaySuspender ds;
4419 vertical_adjustment.set_value (vs.y_position);
4421 set_zoom_focus (vs.zoom_focus);
4422 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4425 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4427 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4428 (*i)->clear_property_cache();
4429 (*i)->reset_visual_state ();
4433 _routes->update_visibility ();
4436 /** This is the core function that controls the zoom level of the canvas. It is called
4437 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4438 * @param spp new number of samples per pixel
4441 Editor::set_samples_per_pixel (samplecnt_t spp)
4447 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4448 const samplecnt_t lots_of_pixels = 4000;
4450 /* if the zoom level is greater than what you'd get trying to display 3
4451 * days of audio on a really big screen, then it's too big.
4454 if (spp * lots_of_pixels > three_days) {
4458 samples_per_pixel = spp;
4462 Editor::on_samples_per_pixel_changed ()
4464 bool const showing_time_selection = selection->time.length() > 0;
4466 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4467 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4468 (*i)->reshow_selection (selection->time);
4472 ZoomChanged (); /* EMIT_SIGNAL */
4474 ArdourCanvas::GtkCanvasViewport* c;
4476 c = get_track_canvas();
4478 c->canvas()->zoomed ();
4481 if (playhead_cursor) {
4482 playhead_cursor->set_position (playhead_cursor->current_sample ());
4485 refresh_location_display();
4486 _summary->set_overlays_dirty ();
4488 update_marker_labels ();
4494 Editor::playhead_cursor_sample () const
4496 return playhead_cursor->current_sample();
4500 Editor::queue_visual_videotimeline_update ()
4502 pending_visual_change.add (VisualChange::VideoTimeline);
4503 ensure_visual_change_idle_handler ();
4507 Editor::ensure_visual_change_idle_handler ()
4509 if (pending_visual_change.idle_handler_id < 0) {
4510 /* see comment in add_to_idle_resize above. */
4511 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4512 pending_visual_change.being_handled = false;
4517 Editor::_idle_visual_changer (void* arg)
4519 return static_cast<Editor*>(arg)->idle_visual_changer ();
4523 Editor::pre_render ()
4525 visual_change_queued = false;
4527 if (pending_visual_change.pending != 0) {
4528 ensure_visual_change_idle_handler();
4533 Editor::idle_visual_changer ()
4535 pending_visual_change.idle_handler_id = -1;
4537 if (pending_visual_change.pending == 0) {
4541 /* set_horizontal_position() below (and maybe other calls) call
4542 gtk_main_iteration(), so it's possible that a signal will be handled
4543 half-way through this method. If this signal wants an
4544 idle_visual_changer we must schedule another one after this one, so
4545 mark the idle_handler_id as -1 here to allow that. Also make a note
4546 that we are doing the visual change, so that changes in response to
4547 super-rapid-screen-update can be dropped if we are still processing
4551 if (visual_change_queued) {
4555 pending_visual_change.being_handled = true;
4557 VisualChange vc = pending_visual_change;
4559 pending_visual_change.pending = (VisualChange::Type) 0;
4561 visual_changer (vc);
4563 pending_visual_change.being_handled = false;
4565 visual_change_queued = true;
4567 return 0; /* this is always a one-shot call */
4571 Editor::visual_changer (const VisualChange& vc)
4574 * Changed first so the correct horizontal canvas position is calculated in
4575 * Editor::set_horizontal_position
4577 if (vc.pending & VisualChange::ZoomLevel) {
4578 set_samples_per_pixel (vc.samples_per_pixel);
4581 if (vc.pending & VisualChange::TimeOrigin) {
4582 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4583 set_horizontal_position (new_time_origin);
4586 if (vc.pending & VisualChange::YOrigin) {
4587 vertical_adjustment.set_value (vc.y_origin);
4591 * Now the canvas is in the final state before render the canvas items that
4592 * support the Item::prepare_for_render interface can calculate the correct
4593 * item to visible canvas intersection.
4595 if (vc.pending & VisualChange::ZoomLevel) {
4596 on_samples_per_pixel_changed ();
4598 compute_fixed_ruler_scale ();
4600 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4601 update_tempo_based_rulers ();
4604 if (!(vc.pending & VisualChange::ZoomLevel)) {
4605 /* If the canvas is not being zoomed then the canvas items will not change
4606 * and cause Item::prepare_for_render to be called so do it here manually.
4607 * Not ideal, but I can't think of a better solution atm.
4609 _track_canvas->prepare_for_render();
4612 /* If we are only scrolling vertically there is no need to update these */
4613 if (vc.pending != VisualChange::YOrigin) {
4614 update_fixed_rulers ();
4615 redisplay_grid (true);
4617 /* video frames & position need to be updated for zoom, horiz-scroll
4618 * and (explicitly) VisualChange::VideoTimeline.
4620 update_video_timeline();
4623 _summary->set_overlays_dirty ();
4626 struct EditorOrderTimeAxisSorter {
4627 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4628 return a->order () < b->order ();
4633 Editor::sort_track_selection (TrackViewList& sel)
4635 EditorOrderTimeAxisSorter cmp;
4640 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4643 samplepos_t where = 0;
4644 EditPoint ep = _edit_point;
4646 if (Profile->get_mixbus()) {
4647 if (ep == EditAtSelectedMarker) {
4648 ep = EditAtPlayhead;
4652 if (from_outside_canvas && (ep == EditAtMouse)) {
4653 ep = EditAtPlayhead;
4654 } else if (from_context_menu && (ep == EditAtMouse)) {
4655 return canvas_event_sample (&context_click_event, 0, 0);
4658 if (entered_marker) {
4659 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4660 return entered_marker->position();
4663 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4664 ep = EditAtSelectedMarker;
4667 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4668 ep = EditAtPlayhead;
4671 MusicSample snap_mf (0, 0);
4674 case EditAtPlayhead:
4675 if (_dragging_playhead && _control_scroll_target) {
4676 where = *_control_scroll_target;
4678 where = _session->audible_sample();
4680 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4683 case EditAtSelectedMarker:
4684 if (!selection->markers.empty()) {
4686 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4689 where = loc->start();
4693 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4701 if (!mouse_sample (where, ignored)) {
4702 /* XXX not right but what can we do ? */
4705 snap_mf.sample = where;
4707 where = snap_mf.sample;
4708 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4716 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4718 if (!_session) return;
4720 begin_reversible_command (cmd);
4724 if ((tll = transport_loop_location()) == 0) {
4725 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4726 XMLNode &before = _session->locations()->get_state();
4727 _session->locations()->add (loc, true);
4728 _session->set_auto_loop_location (loc);
4729 XMLNode &after = _session->locations()->get_state();
4730 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4732 XMLNode &before = tll->get_state();
4733 tll->set_hidden (false, this);
4734 tll->set (start, end);
4735 XMLNode &after = tll->get_state();
4736 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4739 commit_reversible_command ();
4743 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4745 if (!_session) return;
4747 begin_reversible_command (cmd);
4751 if ((tpl = transport_punch_location()) == 0) {
4752 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4753 XMLNode &before = _session->locations()->get_state();
4754 _session->locations()->add (loc, true);
4755 _session->set_auto_punch_location (loc);
4756 XMLNode &after = _session->locations()->get_state();
4757 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4759 XMLNode &before = tpl->get_state();
4760 tpl->set_hidden (false, this);
4761 tpl->set (start, end);
4762 XMLNode &after = tpl->get_state();
4763 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4766 commit_reversible_command ();
4769 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4770 * @param rs List to which found regions are added.
4771 * @param where Time to look at.
4772 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4775 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4777 const TrackViewList* tracks;
4780 tracks = &track_views;
4785 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4787 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4790 boost::shared_ptr<Track> tr;
4791 boost::shared_ptr<Playlist> pl;
4793 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4795 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4797 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4798 RegionView* rv = rtv->view()->find_view (*i);
4809 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4811 const TrackViewList* tracks;
4814 tracks = &track_views;
4819 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4820 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4822 boost::shared_ptr<Track> tr;
4823 boost::shared_ptr<Playlist> pl;
4825 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4827 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4829 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4831 RegionView* rv = rtv->view()->find_view (*i);
4842 /** Get regions using the following method:
4844 * Make a region list using:
4845 * (a) any selected regions
4846 * (b) the intersection of any selected tracks and the edit point(*)
4847 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4849 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4851 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4855 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4857 RegionSelection regions;
4859 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4860 regions.add (entered_regionview);
4862 regions = selection->regions;
4865 if (regions.empty()) {
4866 TrackViewList tracks = selection->tracks;
4868 if (!tracks.empty()) {
4869 /* no region selected or entered, but some selected tracks:
4870 * act on all regions on the selected tracks at the edit point
4872 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4873 get_regions_at(regions, where, tracks);
4880 /** Get regions using the following method:
4882 * Make a region list using:
4883 * (a) any selected regions
4884 * (b) the intersection of any selected tracks and the edit point(*)
4885 * (c) if neither exists, then whatever region is under the mouse
4887 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4889 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4892 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4894 RegionSelection regions;
4896 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4897 regions.add (entered_regionview);
4899 regions = selection->regions;
4902 if (regions.empty()) {
4903 TrackViewList tracks = selection->tracks;
4905 if (!tracks.empty()) {
4906 /* no region selected or entered, but some selected tracks:
4907 * act on all regions on the selected tracks at the edit point
4909 get_regions_at(regions, pos, tracks);
4916 /** Start with regions that are selected, or the entered regionview if none are selected.
4917 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4918 * of the regions that we started with.
4922 Editor::get_regions_from_selection_and_entered () const
4924 RegionSelection regions = selection->regions;
4926 if (regions.empty() && entered_regionview) {
4927 regions.add (entered_regionview);
4934 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4936 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4937 RouteTimeAxisView* rtav;
4939 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4940 boost::shared_ptr<Playlist> pl;
4941 std::vector<boost::shared_ptr<Region> > results;
4942 boost::shared_ptr<Track> tr;
4944 if ((tr = rtav->track()) == 0) {
4949 if ((pl = (tr->playlist())) != 0) {
4950 boost::shared_ptr<Region> r = pl->region_by_id (id);
4952 RegionView* rv = rtav->view()->find_view (r);
4954 regions.push_back (rv);
4963 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4966 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4967 MidiTimeAxisView* mtav;
4969 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4971 mtav->get_per_region_note_selection (selection);
4978 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4980 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4982 RouteTimeAxisView* tatv;
4984 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4986 boost::shared_ptr<Playlist> pl;
4987 vector<boost::shared_ptr<Region> > results;
4989 boost::shared_ptr<Track> tr;
4991 if ((tr = tatv->track()) == 0) {
4996 if ((pl = (tr->playlist())) != 0) {
4997 if (src_comparison) {
4998 pl->get_source_equivalent_regions (region, results);
5000 pl->get_region_list_equivalent_regions (region, results);
5004 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5005 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5006 regions.push_back (marv);
5015 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5017 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5018 RouteTimeAxisView* tatv;
5019 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5020 if (!tatv->track()) {
5023 RegionView* marv = tatv->view()->find_view (region);
5033 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5035 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5036 RouteTimeAxisView* rtav;
5037 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5038 if (rtav->route() == route) {
5047 Editor::show_rhythm_ferret ()
5049 if (rhythm_ferret == 0) {
5050 rhythm_ferret = new RhythmFerret(*this);
5053 rhythm_ferret->set_session (_session);
5054 rhythm_ferret->show ();
5055 rhythm_ferret->present ();
5059 Editor::first_idle ()
5061 MessageDialog* dialog = 0;
5063 if (track_views.size() > 1) {
5064 Timers::TimerSuspender t;
5065 dialog = new MessageDialog (
5066 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5070 ARDOUR_UI::instance()->flush_pending (60);
5073 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5077 /* now that all regionviews should exist, setup region selection */
5081 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5082 /* this is cumulative: rs is NOT cleared each time */
5083 get_regionviews_by_id (*pr, rs);
5086 selection->set (rs);
5088 /* first idle adds route children (automation tracks), so we need to redisplay here */
5089 _routes->redisplay ();
5093 if (_session->undo_depth() == 0) {
5094 undo_action->set_sensitive(false);
5096 redo_action->set_sensitive(false);
5097 begin_selection_op_history ();
5103 Editor::_idle_resize (gpointer arg)
5105 return ((Editor*)arg)->idle_resize ();
5109 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5111 if (resize_idle_id < 0) {
5112 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5113 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5114 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5116 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5117 _pending_resize_amount = 0;
5120 /* make a note of the smallest resulting height, so that we can clamp the
5121 lower limit at TimeAxisView::hSmall */
5123 int32_t min_resulting = INT32_MAX;
5125 _pending_resize_amount += h;
5126 _pending_resize_view = view;
5128 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5130 if (selection->tracks.contains (_pending_resize_view)) {
5131 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5132 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5136 if (min_resulting < 0) {
5141 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5142 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5146 /** Handle pending resizing of tracks */
5148 Editor::idle_resize ()
5150 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5152 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5153 selection->tracks.contains (_pending_resize_view)) {
5155 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5156 if (*i != _pending_resize_view) {
5157 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5162 _pending_resize_amount = 0;
5163 _group_tabs->set_dirty ();
5164 resize_idle_id = -1;
5172 ENSURE_GUI_THREAD (*this, &Editor::located);
5175 playhead_cursor->set_position (_session->audible_sample ());
5176 if (_follow_playhead && !_pending_initial_locate) {
5177 reset_x_origin_to_follow_playhead ();
5181 _pending_locate_request = false;
5182 _pending_initial_locate = false;
5183 _last_update_time = 0;
5187 Editor::region_view_added (RegionView * rv)
5189 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5191 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5192 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5193 if (rv->region()->id () == (*rnote).first) {
5194 mrv->select_notes ((*rnote).second);
5195 selection->pending_midi_note_selection.erase(rnote);
5201 _summary->set_background_dirty ();
5203 mark_region_boundary_cache_dirty ();
5207 Editor::region_view_removed ()
5209 _summary->set_background_dirty ();
5211 mark_region_boundary_cache_dirty ();
5215 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5217 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5218 if ((*j)->stripable() == s) {
5227 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5229 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5230 if ((*j)->control() == c) {
5234 TimeAxisView::Children kids = (*j)->get_child_list ();
5236 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5237 if ((*k)->control() == c) {
5247 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5251 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5252 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5262 Editor::suspend_route_redisplay ()
5265 _routes->suspend_redisplay();
5270 Editor::resume_route_redisplay ()
5273 _routes->redisplay(); // queue redisplay
5274 _routes->resume_redisplay();
5279 Editor::add_vcas (VCAList& vlist)
5283 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5284 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5287 add_stripables (sl);
5291 Editor::add_routes (RouteList& rlist)
5295 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5299 add_stripables (sl);
5303 Editor::add_stripables (StripableList& sl)
5305 list<TimeAxisView*> new_views;
5306 boost::shared_ptr<VCA> v;
5307 boost::shared_ptr<Route> r;
5308 TrackViewList new_selection;
5309 bool from_scratch = (track_views.size() == 0);
5311 sl.sort (Stripable::Sorter());
5313 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5315 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5317 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5319 new_views.push_back (vtv);
5321 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5323 if (r->is_auditioner() || r->is_monitor()) {
5327 RouteTimeAxisView* rtv;
5328 DataType dt = r->input()->default_type();
5330 if (dt == ARDOUR::DataType::AUDIO) {
5331 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5333 } else if (dt == ARDOUR::DataType::MIDI) {
5334 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5337 throw unknown_type();
5340 new_views.push_back (rtv);
5341 track_views.push_back (rtv);
5342 new_selection.push_back (rtv);
5344 rtv->effective_gain_display ();
5346 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5347 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5351 if (new_views.size() > 0) {
5352 _routes->time_axis_views_added (new_views);
5353 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5356 /* note: !new_selection.empty() means that we got some routes rather
5360 if (!from_scratch && !new_selection.empty()) {
5361 selection->set (new_selection);
5362 begin_selection_op_history();
5365 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5366 show_editor_mixer (true);
5369 editor_list_button.set_sensitive (true);
5373 Editor::timeaxisview_deleted (TimeAxisView *tv)
5375 if (tv == entered_track) {
5379 if (_session && _session->deletion_in_progress()) {
5380 /* the situation is under control */
5384 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5386 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5388 _routes->route_removed (tv);
5390 TimeAxisView::Children c = tv->get_child_list ();
5391 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5392 if (entered_track == i->get()) {
5397 /* remove it from the list of track views */
5399 TrackViewList::iterator i;
5401 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5402 i = track_views.erase (i);
5405 /* update whatever the current mixer strip is displaying, if revelant */
5407 boost::shared_ptr<Route> route;
5410 route = rtav->route ();
5413 if (current_mixer_strip && current_mixer_strip->route() == route) {
5415 TimeAxisView* next_tv;
5417 if (track_views.empty()) {
5419 } else if (i == track_views.end()) {
5420 next_tv = track_views.front();
5425 // skip VCAs (cannot be selected, n/a in editor-mixer)
5426 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5427 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5428 next_tv = track_views.front();
5430 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5431 /* just in case: no master, only a VCA remains */
5437 set_selected_mixer_strip (*next_tv);
5439 /* make the editor mixer strip go away setting the
5440 * button to inactive (which also unticks the menu option)
5443 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5449 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5455 DisplaySuspender ds;
5456 PresentationInfo::ChangeSuspender cs;
5458 if (apply_to_selection) {
5459 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5461 TrackSelection::iterator j = i;
5464 hide_track_in_display (*i, false);
5469 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5471 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5472 /* this will hide the mixer strip */
5473 set_selected_mixer_strip (*tv);
5476 _routes->hide_track_in_display (*tv);
5481 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5486 _routes->show_track_in_display (*tv);
5487 if (move_into_view) {
5488 ensure_time_axis_view_is_visible (*tv, false);
5493 Editor::sync_track_view_list_and_routes ()
5495 track_views = TrackViewList (_routes->views ());
5497 _summary->set_background_dirty();
5498 _group_tabs->set_dirty ();
5500 return false; // do not call again (until needed)
5504 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5506 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5511 /** Find a StripableTimeAxisView by the ID of its stripable */
5512 StripableTimeAxisView*
5513 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5515 StripableTimeAxisView* v;
5517 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5518 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5519 if(v->stripable()->id() == id) {
5529 Editor::fit_route_group (RouteGroup *g)
5531 TrackViewList ts = axis_views_from_routes (g->route_list ());
5536 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5538 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5541 _session->cancel_audition ();
5545 if (_session->is_auditioning()) {
5546 _session->cancel_audition ();
5547 if (r == last_audition_region) {
5552 _session->audition_region (r);
5553 last_audition_region = r;
5558 Editor::hide_a_region (boost::shared_ptr<Region> r)
5560 r->set_hidden (true);
5564 Editor::show_a_region (boost::shared_ptr<Region> r)
5566 r->set_hidden (false);
5570 Editor::audition_region_from_region_list ()
5572 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5576 Editor::hide_region_from_region_list ()
5578 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5582 Editor::show_region_in_region_list ()
5584 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5588 Editor::step_edit_status_change (bool yn)
5591 start_step_editing ();
5593 stop_step_editing ();
5598 Editor::start_step_editing ()
5600 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5604 Editor::stop_step_editing ()
5606 step_edit_connection.disconnect ();
5610 Editor::check_step_edit ()
5612 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5613 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5615 mtv->check_step_edit ();
5619 return true; // do it again, till we stop
5623 Editor::scroll_press (Direction dir)
5625 ++_scroll_callbacks;
5627 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5628 /* delay the first auto-repeat */
5634 scroll_backward (1);
5642 scroll_up_one_track ();
5646 scroll_down_one_track ();
5650 /* do hacky auto-repeat */
5651 if (!_scroll_connection.connected ()) {
5653 _scroll_connection = Glib::signal_timeout().connect (
5654 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5657 _scroll_callbacks = 0;
5664 Editor::scroll_release ()
5666 _scroll_connection.disconnect ();
5669 /** Queue a change for the Editor viewport x origin to follow the playhead */
5671 Editor::reset_x_origin_to_follow_playhead ()
5673 samplepos_t const sample = playhead_cursor->current_sample ();
5675 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5677 if (_session->transport_speed() < 0) {
5679 if (sample > (current_page_samples() / 2)) {
5680 center_screen (sample-(current_page_samples()/2));
5682 center_screen (current_page_samples()/2);
5689 if (sample < _leftmost_sample) {
5691 if (_session->transport_rolling()) {
5692 /* rolling; end up with the playhead at the right of the page */
5693 l = sample - current_page_samples ();
5695 /* not rolling: end up with the playhead 1/4 of the way along the page */
5696 l = sample - current_page_samples() / 4;
5700 if (_session->transport_rolling()) {
5701 /* rolling: end up with the playhead on the left of the page */
5704 /* not rolling: end up with the playhead 3/4 of the way along the page */
5705 l = sample - 3 * current_page_samples() / 4;
5713 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5719 Editor::super_rapid_screen_update ()
5721 if (!_session || !_session->engine().running()) {
5725 /* METERING / MIXER STRIPS */
5727 /* update track meters, if required */
5728 if (contents().is_mapped() && meters_running) {
5729 RouteTimeAxisView* rtv;
5730 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5731 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5732 rtv->fast_update ();
5737 /* and any current mixer strip */
5738 if (current_mixer_strip) {
5739 current_mixer_strip->fast_update ();
5742 bool latent_locate = false;
5743 samplepos_t sample = _session->audible_sample (&latent_locate);
5744 const int64_t now = g_get_monotonic_time ();
5747 if (_session->exporting ()) {
5748 /* freewheel/export may be faster or slower than transport_speed() / SR.
5749 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5751 _last_update_time = 0;
5754 if (!_session->transport_rolling ()) {
5755 /* Do not interpolate the playhead position; just set it */
5756 _last_update_time = 0;
5759 if (_last_update_time > 0) {
5760 /* interpolate and smoothen playhead position */
5761 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5762 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5763 err = sample - guess;
5765 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5766 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5769 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5771 err, _err_screen_engine);
5776 _err_screen_engine = 0;
5779 if (err > 8192 || latent_locate) {
5780 // in case of x-runs or freewheeling
5781 _last_update_time = 0;
5782 sample = _session->audible_sample ();
5784 _last_update_time = now;
5787 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5789 MusicSample where (sample, 0);
5790 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5791 snapped_cursor->hide ();
5792 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5793 snap_to (where); // can't use snap_to_with_modifier?
5794 snapped_cursor->set_position (where.sample);
5795 snapped_cursor->show ();
5796 } else if (_edit_point == EditAtSelectedMarker) {
5797 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5798 * however, the current editing code -does- snap so I'll draw it that way for now.
5800 if (!selection->markers.empty()) {
5801 MusicSample ms (selection->markers.front()->position(), 0);
5802 snap_to (ms); // should use snap_to_with_modifier?
5803 snapped_cursor->set_position (ms.sample);
5804 snapped_cursor->show ();
5806 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5807 snapped_cursor->show ();
5808 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5809 snapped_cursor->hide ();
5812 /* There are a few reasons why we might not update the playhead / viewport stuff:
5814 * 1. we don't update things when there's a pending locate request, otherwise
5815 * when the editor requests a locate there is a chance that this method
5816 * will move the playhead before the locate request is processed, causing
5818 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5819 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5821 if (_pending_locate_request) {
5822 _last_update_time = 0;
5826 if (_dragging_playhead) {
5827 _last_update_time = 0;
5831 if (playhead_cursor->current_sample () == sample) {
5835 playhead_cursor->set_position (sample);
5837 if (_session->requested_return_sample() >= 0) {
5838 _last_update_time = 0;
5842 if (!_follow_playhead || pending_visual_change.being_handled) {
5843 /* We only do this if we aren't already
5844 * handling a visual change (ie if
5845 * pending_visual_change.being_handled is
5846 * false) so that these requests don't stack
5847 * up there are too many of them to handle in
5853 if (!_stationary_playhead) {
5854 reset_x_origin_to_follow_playhead ();
5856 samplepos_t const sample = playhead_cursor->current_sample ();
5857 double target = ((double)sample - (double)current_page_samples() / 2.0);
5858 if (target <= 0.0) {
5861 /* compare to EditorCursor::set_position() */
5862 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5863 double const new_pos = sample_to_pixel_unrounded (target);
5864 if (rint (new_pos) != rint (old_pos)) {
5865 reset_x_origin (pixel_to_sample (new_pos));
5872 Editor::session_going_away ()
5874 _have_idled = false;
5876 _session_connections.drop_connections ();
5878 super_rapid_screen_update_connection.disconnect ();
5880 selection->clear ();
5881 cut_buffer->clear ();
5883 clicked_regionview = 0;
5884 clicked_axisview = 0;
5885 clicked_routeview = 0;
5886 entered_regionview = 0;
5888 _last_update_time = 0;
5891 playhead_cursor->hide ();
5893 /* rip everything out of the list displays */
5897 _route_groups->clear ();
5899 /* do this first so that deleting a track doesn't reset cms to null
5900 and thus cause a leak.
5903 if (current_mixer_strip) {
5904 if (current_mixer_strip->get_parent() != 0) {
5905 global_hpacker.remove (*current_mixer_strip);
5907 delete current_mixer_strip;
5908 current_mixer_strip = 0;
5911 /* delete all trackviews */
5913 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5916 track_views.clear ();
5918 nudge_clock->set_session (0);
5920 editor_list_button.set_active(false);
5921 editor_list_button.set_sensitive(false);
5923 /* clear tempo/meter rulers */
5924 remove_metric_marks ();
5925 clear_marker_display ();
5931 stop_step_editing ();
5935 /* get rid of any existing editor mixer strip */
5937 WindowTitle title(Glib::get_application_name());
5938 title += _("Editor");
5940 own_window()->set_title (title.get_string());
5943 SessionHandlePtr::session_going_away ();
5947 Editor::trigger_script (int i)
5949 LuaInstance::instance()-> call_action (i);
5953 Editor::show_editor_list (bool yn)
5956 _editor_list_vbox.show ();
5958 _editor_list_vbox.hide ();
5963 Editor::change_region_layering_order (bool from_context_menu)
5965 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5967 if (!clicked_routeview) {
5968 if (layering_order_editor) {
5969 layering_order_editor->hide ();
5974 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5980 boost::shared_ptr<Playlist> pl = track->playlist();
5986 if (layering_order_editor == 0) {
5987 layering_order_editor = new RegionLayeringOrderEditor (*this);
5990 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5991 layering_order_editor->maybe_present ();
5995 Editor::update_region_layering_order_editor ()
5997 if (layering_order_editor && layering_order_editor->is_visible ()) {
5998 change_region_layering_order (true);
6003 Editor::setup_fade_images ()
6005 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6006 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6007 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6008 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6009 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6011 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6012 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6013 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6014 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6015 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6019 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6021 Editor::action_menu_item (std::string const & name)
6023 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6026 return *manage (a->create_menu_item ());
6030 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6032 EventBox* b = manage (new EventBox);
6033 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6034 Label* l = manage (new Label (name));
6038 _the_notebook.append_page (widget, *b);
6042 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6044 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6045 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6048 if (ev->type == GDK_2BUTTON_PRESS) {
6050 /* double-click on a notebook tab shrinks or expands the notebook */
6052 if (_notebook_shrunk) {
6053 if (pre_notebook_shrink_pane_width) {
6054 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6056 _notebook_shrunk = false;
6058 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6060 /* this expands the LHS of the edit pane to cover the notebook
6061 PAGE but leaves the tabs visible.
6063 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6064 _notebook_shrunk = true;
6072 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6074 using namespace Menu_Helpers;
6076 MenuList& items = _control_point_context_menu.items ();
6079 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6080 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6081 if (!can_remove_control_point (item)) {
6082 items.back().set_sensitive (false);
6085 _control_point_context_menu.popup (event->button.button, event->button.time);
6089 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6091 using namespace Menu_Helpers;
6093 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6098 /* We need to get the selection here and pass it to the operations, since
6099 popping up the menu will cause a region leave event which clears
6100 entered_regionview. */
6102 MidiRegionView& mrv = note->region_view();
6103 const RegionSelection rs = get_regions_from_selection_and_entered ();
6104 const uint32_t sel_size = mrv.selection_size ();
6106 MenuList& items = _note_context_menu.items();
6110 items.push_back(MenuElem(_("Delete"),
6111 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6114 items.push_back(MenuElem(_("Edit..."),
6115 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6116 if (sel_size != 1) {
6117 items.back().set_sensitive (false);
6120 items.push_back(MenuElem(_("Transpose..."),
6121 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6124 items.push_back(MenuElem(_("Legatize"),
6125 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6127 items.back().set_sensitive (false);
6130 items.push_back(MenuElem(_("Quantize..."),
6131 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6133 items.push_back(MenuElem(_("Remove Overlap"),
6134 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6136 items.back().set_sensitive (false);
6139 items.push_back(MenuElem(_("Transform..."),
6140 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6142 _note_context_menu.popup (event->button.button, event->button.time);
6146 Editor::zoom_vertical_modifier_released()
6148 _stepping_axis_view = 0;
6152 Editor::ui_parameter_changed (string parameter)
6154 if (parameter == "icon-set") {
6155 while (!_cursor_stack.empty()) {
6156 _cursor_stack.pop_back();
6158 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6159 _cursor_stack.push_back(_cursors->grabber);
6160 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6161 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6163 } else if (parameter == "draggable-playhead") {
6164 if (_verbose_cursor) {
6165 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6171 Editor::use_own_window (bool and_fill_it)
6173 bool new_window = !own_window();
6175 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6177 if (win && new_window) {
6178 win->set_name ("EditorWindow");
6180 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6182 // win->signal_realize().connect (*this, &Editor::on_realize);
6183 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6184 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6185 win->set_data ("ardour-bindings", bindings);
6190 DisplaySuspender ds;
6191 contents().show_all ();
6193 /* XXX: this is a bit unfortunate; it would probably
6194 be nicer if we could just call show () above rather
6195 than needing the show_all ()
6198 /* re-hide stuff if necessary */
6199 editor_list_button_toggled ();
6200 parameter_changed ("show-summary");
6201 parameter_changed ("show-group-tabs");
6202 parameter_changed ("show-zoom-tools");
6204 /* now reset all audio_time_axis heights, because widgets might need
6210 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6211 tv = (static_cast<TimeAxisView*>(*i));
6212 tv->reset_height ();
6215 if (current_mixer_strip) {
6216 current_mixer_strip->hide_things ();
6217 current_mixer_strip->parameter_changed ("mixer-element-visibility");