2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/gtk_ui.h"
61 #include "gtkmm2ext/keyboard.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
66 #include "ardour/analysis_graph.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
78 #include "ardour/vca_manager.h"
79 #include "ardour/vca.h"
81 #include "canvas/debug.h"
82 #include "canvas/note.h"
83 #include "canvas/text.h"
85 #include "widgets/ardour_spacer.h"
86 #include "widgets/eventboxext.h"
87 #include "widgets/tooltips.h"
89 #include "control_protocol/control_protocol.h"
92 #include "analysis_window.h"
93 #include "audio_clock.h"
94 #include "audio_region_view.h"
95 #include "audio_streamview.h"
96 #include "audio_time_axis.h"
97 #include "automation_time_axis.h"
98 #include "bundle_manager.h"
99 #include "crossfade_edit.h"
102 #include "editing_convert.h"
104 #include "editor_cursors.h"
105 #include "editor_drag.h"
106 #include "editor_group_tabs.h"
107 #include "editor_locations.h"
108 #include "editor_regions.h"
109 #include "editor_route_groups.h"
110 #include "editor_routes.h"
111 #include "editor_snapshots.h"
112 #include "editor_summary.h"
113 #include "enums_convert.h"
114 #include "export_report.h"
115 #include "global_port_matrix.h"
116 #include "gui_object.h"
117 #include "gui_thread.h"
118 #include "keyboard.h"
119 #include "luainstance.h"
121 #include "midi_region_view.h"
122 #include "midi_time_axis.h"
123 #include "mixer_strip.h"
124 #include "mixer_ui.h"
125 #include "mouse_cursors.h"
126 #include "note_base.h"
127 #include "playlist_selector.h"
128 #include "public_editor.h"
129 #include "quantize_dialog.h"
130 #include "region_layering_order_editor.h"
131 #include "rgb_macros.h"
132 #include "rhythm_ferret.h"
133 #include "route_sorter.h"
134 #include "selection.h"
135 #include "simple_progress_dialog.h"
137 #include "grid_lines.h"
138 #include "time_axis_view.h"
139 #include "time_info_box.h"
141 #include "ui_config.h"
143 #include "vca_time_axis.h"
144 #include "verbose_cursor.h"
146 #include "pbd/i18n.h"
149 using namespace ARDOUR;
150 using namespace ArdourWidgets;
151 using namespace ARDOUR_UI_UTILS;
154 using namespace Glib;
155 using namespace Gtkmm2ext;
156 using namespace Editing;
158 using PBD::internationalize;
160 using Gtkmm2ext::Keyboard;
162 double Editor::timebar_height = 15.0;
164 static const gchar *_grid_type_strings[] = {
173 N_("1/3 (8th triplet)"), // or "1/12" ?
174 N_("1/6 (16th triplet)"),
175 N_("1/12 (32nd triplet)"),
176 N_("1/24 (64th triplet)"),
177 N_("1/5 (8th quintuplet)"),
178 N_("1/10 (16th quintuplet)"),
179 N_("1/20 (32nd quintuplet)"),
180 N_("1/7 (8th septuplet)"),
181 N_("1/14 (16th septuplet)"),
182 N_("1/28 (32nd septuplet)"),
189 static const gchar *_edit_point_strings[] = {
196 static const gchar *_edit_mode_strings[] = {
204 static const gchar *_zoom_focus_strings[] = {
214 #ifdef USE_RUBBERBAND
215 static const gchar *_rb_opt_strings[] = {
218 N_("Balanced multitimbral mixture"),
219 N_("Unpitched percussion with stable notes"),
220 N_("Crisp monophonic instrumental"),
221 N_("Unpitched solo percussion"),
222 N_("Resample without preserving pitch"),
227 /* Robin says: this should be odd to accomodate cairo drawing offset (width/2 rounds up to pixel boundary) */
229 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
231 #define COMBO_TRIANGLE_WIDTH 11 // as-measured for win/linux.
235 : PublicEditor (global_hpacker)
236 , editor_mixer_strip_width (Wide)
237 , constructed (false)
238 , _playlist_selector (0)
240 , no_save_visual (false)
241 , _leftmost_sample (0)
242 , samples_per_pixel (2048)
243 , zoom_focus (ZoomFocusPlayhead)
244 , mouse_mode (MouseObject)
245 , pre_internal_grid_type (GridTypeBeat)
246 , pre_internal_snap_mode (SnapOff)
247 , internal_grid_type (GridTypeBeat)
248 , internal_snap_mode (SnapOff)
249 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
250 , _notebook_shrunk (false)
251 , location_marker_color (0)
252 , location_range_color (0)
253 , location_loop_color (0)
254 , location_punch_color (0)
255 , location_cd_marker_color (0)
257 , _show_marker_lines (false)
258 , clicked_axisview (0)
259 , clicked_routeview (0)
260 , clicked_regionview (0)
261 , clicked_selection (0)
262 , clicked_control_point (0)
263 , button_release_can_deselect (true)
264 , _mouse_changed_selection (false)
265 , region_edit_menu_split_item (0)
266 , region_edit_menu_split_multichannel_item (0)
267 , track_region_edit_playlist_menu (0)
268 , track_edit_playlist_submenu (0)
269 , track_selection_edit_playlist_submenu (0)
270 , _popup_region_menu_item (0)
272 , _track_canvas_viewport (0)
273 , within_track_canvas (false)
274 , _verbose_cursor (0)
278 , range_marker_group (0)
279 , transport_marker_group (0)
280 , cd_marker_group (0)
281 , _time_markers_group (0)
282 , hv_scroll_group (0)
284 , cursor_scroll_group (0)
285 , no_scroll_group (0)
286 , _trackview_group (0)
287 , _drag_motion_group (0)
288 , _canvas_drop_zone (0)
289 , no_ruler_shown_update (false)
290 , ruler_grabbed_widget (0)
292 , minsec_mark_interval (0)
293 , minsec_mark_modulo (0)
295 , timecode_ruler_scale (timecode_show_many_hours)
296 , timecode_mark_modulo (0)
297 , timecode_nmarks (0)
298 , _samples_ruler_interval (0)
299 , bbt_ruler_scale (bbt_show_many)
302 , bbt_bar_helper_on (0)
303 , bbt_accent_modulo (0)
308 , visible_timebars (0)
309 , editor_ruler_menu (0)
313 , range_marker_bar (0)
314 , transport_marker_bar (0)
316 , minsec_label (_("Mins:Secs"))
317 , bbt_label (_("Bars:Beats"))
318 , timecode_label (_("Timecode"))
319 , samples_label (_("Samples"))
320 , tempo_label (_("Tempo"))
321 , meter_label (_("Meter"))
322 , mark_label (_("Location Markers"))
323 , range_mark_label (_("Range Markers"))
324 , transport_mark_label (_("Loop/Punch Ranges"))
325 , cd_mark_label (_("CD Markers"))
326 , videotl_label (_("Video Timeline"))
329 , playhead_cursor (0)
330 , _region_boundary_cache_dirty (true)
331 , edit_packer (4, 4, true)
332 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
333 , horizontal_adjustment (0.0, 0.0, 1e16)
334 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
335 , controls_layout (unused_adjustment, vertical_adjustment)
336 , _scroll_callbacks (0)
337 , _visible_canvas_width (0)
338 , _visible_canvas_height (0)
339 , _full_canvas_height (0)
340 , edit_controls_left_menu (0)
341 , edit_controls_right_menu (0)
342 , visual_change_queued(false)
343 , _last_update_time (0)
344 , _err_screen_engine (0)
345 , cut_buffer_start (0)
346 , cut_buffer_length (0)
347 , button_bindings (0)
348 , last_paste_pos (-1)
351 , current_interthread_info (0)
352 , analysis_window (0)
353 , select_new_marker (false)
355 , scrubbing_direction (0)
356 , scrub_reversals (0)
357 , scrub_reverse_distance (0)
358 , have_pending_keyboard_selection (false)
359 , pending_keyboard_selection_start (0)
360 , _grid_type (GridTypeBeat)
361 , _snap_mode (SnapOff)
362 , ignore_gui_changes (false)
363 , _drags (new DragManager (this))
365 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
366 , _dragging_playhead (false)
367 , _dragging_edit_point (false)
368 , _follow_playhead (true)
369 , _stationary_playhead (false)
372 , global_rect_group (0)
373 , time_line_group (0)
374 , tempo_marker_menu (0)
375 , meter_marker_menu (0)
377 , range_marker_menu (0)
378 , transport_marker_menu (0)
379 , new_transport_marker_menu (0)
381 , marker_menu_item (0)
382 , bbt_beat_subdivision (4)
383 , _visible_track_count (-1)
384 , toolbar_selection_clock_table (2,3)
385 , automation_mode_button (_("mode"))
386 , selection (new Selection (this, true))
387 , cut_buffer (new Selection (this, false))
388 , _selection_memento (new SelectionMemento())
389 , _all_region_actions_sensitized (false)
390 , _ignore_region_action (false)
391 , _last_region_menu_was_main (false)
392 , _track_selection_change_without_scroll (false)
393 , _editor_track_selection_change_without_scroll (false)
394 , cd_marker_bar_drag_rect (0)
395 , range_bar_drag_rect (0)
396 , transport_bar_drag_rect (0)
397 , transport_bar_range_rect (0)
398 , transport_bar_preroll_rect (0)
399 , transport_bar_postroll_rect (0)
400 , transport_loop_range_rect (0)
401 , transport_punch_range_rect (0)
402 , transport_punchin_line (0)
403 , transport_punchout_line (0)
404 , transport_preroll_rect (0)
405 , transport_postroll_rect (0)
407 , rubberband_rect (0)
413 , autoscroll_horizontal_allowed (false)
414 , autoscroll_vertical_allowed (false)
416 , autoscroll_widget (0)
417 , show_gain_after_trim (false)
418 , selection_op_cmd_depth (0)
419 , selection_op_history_it (0)
420 , no_save_instant (false)
422 , current_mixer_strip (0)
423 , show_editor_mixer_when_tracks_arrive (false)
424 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
425 , current_stepping_trackview (0)
426 , last_track_height_step_timestamp (0)
428 , entered_regionview (0)
429 , clear_entered_track (false)
430 , _edit_point (EditAtMouse)
431 , meters_running (false)
433 , _have_idled (false)
434 , resize_idle_id (-1)
435 , _pending_resize_amount (0)
436 , _pending_resize_view (0)
437 , _pending_locate_request (false)
438 , _pending_initial_locate (false)
442 , layering_order_editor (0)
443 , _last_cut_copy_source_track (0)
444 , _region_selection_change_updates_region_list (true)
446 , _following_mixer_selection (false)
447 , _control_point_toggled_on_press (false)
448 , _stepping_axis_view (0)
449 , quantize_dialog (0)
450 , _main_menu_disabler (0)
451 , myactions (X_("editor"))
453 /* we are a singleton */
455 PublicEditor::_instance = this;
459 last_event_time.tv_sec = 0;
460 last_event_time.tv_usec = 0;
462 selection_op_history.clear();
465 grid_type_strings = I18N (_grid_type_strings);
466 zoom_focus_strings = I18N (_zoom_focus_strings);
467 edit_mode_strings = I18N (_edit_mode_strings);
468 edit_point_strings = I18N (_edit_point_strings);
469 #ifdef USE_RUBBERBAND
470 rb_opt_strings = I18N (_rb_opt_strings);
474 build_edit_mode_menu();
475 build_zoom_focus_menu();
476 build_track_count_menu();
477 build_grid_type_menu();
478 build_edit_point_menu();
480 location_marker_color = UIConfiguration::instance().color ("location marker");
481 location_range_color = UIConfiguration::instance().color ("location range");
482 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
483 location_loop_color = UIConfiguration::instance().color ("location loop");
484 location_punch_color = UIConfiguration::instance().color ("location punch");
486 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
488 TimeAxisView::setup_sizes ();
489 ArdourMarker::setup_sizes (timebar_height);
490 TempoCurve::setup_sizes (timebar_height);
492 bbt_label.set_name ("EditorRulerLabel");
493 bbt_label.set_size_request (-1, (int)timebar_height);
494 bbt_label.set_alignment (1.0, 0.5);
495 bbt_label.set_padding (5,0);
497 bbt_label.set_no_show_all();
498 minsec_label.set_name ("EditorRulerLabel");
499 minsec_label.set_size_request (-1, (int)timebar_height);
500 minsec_label.set_alignment (1.0, 0.5);
501 minsec_label.set_padding (5,0);
502 minsec_label.hide ();
503 minsec_label.set_no_show_all();
504 timecode_label.set_name ("EditorRulerLabel");
505 timecode_label.set_size_request (-1, (int)timebar_height);
506 timecode_label.set_alignment (1.0, 0.5);
507 timecode_label.set_padding (5,0);
508 timecode_label.hide ();
509 timecode_label.set_no_show_all();
510 samples_label.set_name ("EditorRulerLabel");
511 samples_label.set_size_request (-1, (int)timebar_height);
512 samples_label.set_alignment (1.0, 0.5);
513 samples_label.set_padding (5,0);
514 samples_label.hide ();
515 samples_label.set_no_show_all();
517 tempo_label.set_name ("EditorRulerLabel");
518 tempo_label.set_size_request (-1, (int)timebar_height);
519 tempo_label.set_alignment (1.0, 0.5);
520 tempo_label.set_padding (5,0);
522 tempo_label.set_no_show_all();
524 meter_label.set_name ("EditorRulerLabel");
525 meter_label.set_size_request (-1, (int)timebar_height);
526 meter_label.set_alignment (1.0, 0.5);
527 meter_label.set_padding (5,0);
529 meter_label.set_no_show_all();
531 if (Profile->get_trx()) {
532 mark_label.set_text (_("Markers"));
534 mark_label.set_name ("EditorRulerLabel");
535 mark_label.set_size_request (-1, (int)timebar_height);
536 mark_label.set_alignment (1.0, 0.5);
537 mark_label.set_padding (5,0);
539 mark_label.set_no_show_all();
541 cd_mark_label.set_name ("EditorRulerLabel");
542 cd_mark_label.set_size_request (-1, (int)timebar_height);
543 cd_mark_label.set_alignment (1.0, 0.5);
544 cd_mark_label.set_padding (5,0);
545 cd_mark_label.hide();
546 cd_mark_label.set_no_show_all();
548 videotl_bar_height = 4;
549 videotl_label.set_name ("EditorRulerLabel");
550 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
551 videotl_label.set_alignment (1.0, 0.5);
552 videotl_label.set_padding (5,0);
553 videotl_label.hide();
554 videotl_label.set_no_show_all();
556 range_mark_label.set_name ("EditorRulerLabel");
557 range_mark_label.set_size_request (-1, (int)timebar_height);
558 range_mark_label.set_alignment (1.0, 0.5);
559 range_mark_label.set_padding (5,0);
560 range_mark_label.hide();
561 range_mark_label.set_no_show_all();
563 transport_mark_label.set_name ("EditorRulerLabel");
564 transport_mark_label.set_size_request (-1, (int)timebar_height);
565 transport_mark_label.set_alignment (1.0, 0.5);
566 transport_mark_label.set_padding (5,0);
567 transport_mark_label.hide();
568 transport_mark_label.set_no_show_all();
570 initialize_canvas ();
572 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
574 _summary = new EditorSummary (this);
576 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
577 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
579 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
581 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
582 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
584 edit_controls_vbox.set_spacing (0);
585 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
586 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
588 HBox* h = manage (new HBox);
589 _group_tabs = new EditorGroupTabs (this);
590 if (!ARDOUR::Profile->get_trx()) {
591 h->pack_start (*_group_tabs, PACK_SHRINK);
593 h->pack_start (edit_controls_vbox);
594 controls_layout.add (*h);
596 controls_layout.set_name ("EditControlsBase");
597 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
598 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
599 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
601 _cursors = new MouseCursors;
602 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
603 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
605 /* Push default cursor to ever-present bottom of cursor stack. */
606 push_canvas_cursor(_cursors->grabber);
608 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
610 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
611 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
612 pad_line_1->set_outline_color (0xFF0000FF);
618 edit_packer.set_col_spacings (0);
619 edit_packer.set_row_spacings (0);
620 edit_packer.set_homogeneous (false);
621 edit_packer.set_border_width (0);
622 edit_packer.set_name ("EditorWindow");
624 time_bars_event_box.add (time_bars_vbox);
625 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
626 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
628 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
629 axis_view_shadow->set_size_request (4, -1);
630 axis_view_shadow->set_name("EditorWindow");
631 axis_view_shadow->show();
633 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
635 /* labels for the time bars */
636 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
638 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
640 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
642 bottom_hbox.set_border_width (2);
643 bottom_hbox.set_spacing (3);
645 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
647 _route_groups = new EditorRouteGroups (this);
648 _routes = new EditorRoutes (this);
649 _regions = new EditorRegions (this);
650 _snapshots = new EditorSnapshots (this);
651 _locations = new EditorLocations (this);
652 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
654 /* these are static location signals */
656 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
657 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
658 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
660 add_notebook_page (_("Regions"), _regions->widget ());
661 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
662 add_notebook_page (_("Snapshots"), _snapshots->widget ());
663 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
664 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
666 _the_notebook.set_show_tabs (true);
667 _the_notebook.set_scrollable (true);
668 _the_notebook.popup_disable ();
669 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
670 _the_notebook.show_all ();
672 _notebook_shrunk = false;
675 /* Pick up some settings we need to cache, early */
677 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
680 settings->get_property ("notebook-shrunk", _notebook_shrunk);
683 editor_summary_pane.set_check_divider_position (true);
684 editor_summary_pane.add (edit_packer);
686 Button* summary_arrow_left = manage (new Button);
687 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
688 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
689 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 Button* summary_arrow_right = manage (new Button);
692 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
693 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
694 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
696 VBox* summary_arrows_left = manage (new VBox);
697 summary_arrows_left->pack_start (*summary_arrow_left);
699 VBox* summary_arrows_right = manage (new VBox);
700 summary_arrows_right->pack_start (*summary_arrow_right);
702 Frame* summary_frame = manage (new Frame);
703 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
705 summary_frame->add (*_summary);
706 summary_frame->show ();
708 _summary_hbox.pack_start (*summary_arrows_left, false, false);
709 _summary_hbox.pack_start (*summary_frame, true, true);
710 _summary_hbox.pack_start (*summary_arrows_right, false, false);
712 if (!ARDOUR::Profile->get_trx()) {
713 editor_summary_pane.add (_summary_hbox);
716 edit_pane.set_check_divider_position (true);
717 edit_pane.add (editor_summary_pane);
718 if (!ARDOUR::Profile->get_trx()) {
719 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
720 _editor_list_vbox.pack_start (_the_notebook);
721 edit_pane.add (_editor_list_vbox);
722 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
725 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
726 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
729 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
730 /* initial allocation is 90% to canvas, 10% to notebook */
733 edit_pane.set_divider (0, fract);
735 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
736 /* initial allocation is 90% to canvas, 10% to summary */
739 editor_summary_pane.set_divider (0, fract);
741 global_vpacker.set_spacing (0);
742 global_vpacker.set_border_width (0);
744 /* the next three EventBoxes provide the ability for their child widgets to have a background color. That is all. */
746 Gtk::EventBox* ebox = manage (new Gtk::EventBox); // a themeable box
747 ebox->set_name("EditorWindow");
748 ebox->add (ebox_hpacker);
750 Gtk::EventBox* epane_box = manage (new EventBoxExt); // a themeable box
751 epane_box->set_name("EditorWindow");
752 epane_box->add (edit_pane);
754 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); // a themeable box
755 epane_box2->set_name("EditorWindow");
756 epane_box2->add (global_vpacker);
758 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
759 toolbar_shadow->set_size_request (-1, 4);
760 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
761 toolbar_shadow->set_name("EditorWindow");
762 toolbar_shadow->show();
764 global_vpacker.pack_start (*toolbar_shadow, false, false);
765 global_vpacker.pack_start (*ebox, false, false);
766 global_vpacker.pack_start (*epane_box, true, true);
767 global_hpacker.pack_start (*epane_box2, true, true);
769 /* need to show the "contents" widget so that notebook will show if tab is switched to
772 global_hpacker.show ();
776 /* register actions now so that set_state() can find them and set toggles/checks etc */
783 _playlist_selector = new PlaylistSelector();
784 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
786 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
790 nudge_forward_button.set_name ("nudge button");
791 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
793 nudge_backward_button.set_name ("nudge button");
794 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
796 fade_context_menu.set_name ("ArdourContextMenu");
798 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
800 /* allow external control surfaces/protocols to do various things */
802 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
803 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
804 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
805 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
806 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
807 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
808 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
809 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
810 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
811 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
812 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
813 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
814 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
815 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
817 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
818 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
819 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
820 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
821 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
823 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
827 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
829 /* problematic: has to return a value and thus cannot be x-thread */
831 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
833 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
834 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
836 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
838 _ignore_region_action = false;
839 _last_region_menu_was_main = false;
840 _popup_region_menu_item = 0;
842 _show_marker_lines = false;
844 /* Button bindings */
846 button_bindings = new Bindings ("editor-mouse");
848 XMLNode* node = button_settings();
850 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
851 button_bindings->load_operation (**i);
857 /* grab current parameter state */
858 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
859 UIConfiguration::instance().map_parameters (pc);
861 setup_fade_images ();
863 set_grid_to (GridTypeNone);
870 delete button_bindings;
872 delete _route_groups;
873 delete _track_canvas_viewport;
876 delete _verbose_cursor;
877 delete quantize_dialog;
883 delete _playlist_selector;
884 delete _time_info_box;
889 LuaInstance::destroy_instance ();
891 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
894 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
897 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
903 Editor::button_settings () const
905 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
906 XMLNode* node = find_named_node (*settings, X_("Buttons"));
909 node = new XMLNode (X_("Buttons"));
916 Editor::get_smart_mode () const
918 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
922 Editor::catch_vanishing_regionview (RegionView *rv)
924 /* note: the selection will take care of the vanishing
925 audioregionview by itself.
928 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
932 if (clicked_regionview == rv) {
933 clicked_regionview = 0;
936 if (entered_regionview == rv) {
937 set_entered_regionview (0);
940 if (!_all_region_actions_sensitized) {
941 sensitize_all_region_actions (true);
946 Editor::set_entered_regionview (RegionView* rv)
948 if (rv == entered_regionview) {
952 if (entered_regionview) {
953 entered_regionview->exited ();
956 entered_regionview = rv;
958 if (entered_regionview != 0) {
959 entered_regionview->entered ();
962 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
963 /* This RegionView entry might have changed what region actions
964 are allowed, so sensitize them all in case a key is pressed.
966 sensitize_all_region_actions (true);
971 Editor::set_entered_track (TimeAxisView* tav)
974 entered_track->exited ();
980 entered_track->entered ();
985 Editor::instant_save ()
987 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
992 _session->add_instant_xml(get_state());
994 Config->add_instant_xml(get_state());
999 Editor::control_vertical_zoom_in_all ()
1001 tav_zoom_smooth (false, true);
1005 Editor::control_vertical_zoom_out_all ()
1007 tav_zoom_smooth (true, true);
1011 Editor::control_vertical_zoom_in_selected ()
1013 tav_zoom_smooth (false, false);
1017 Editor::control_vertical_zoom_out_selected ()
1019 tav_zoom_smooth (true, false);
1023 Editor::control_view (uint32_t view)
1025 goto_visual_state (view);
1029 Editor::control_unselect ()
1031 selection->clear_tracks ();
1035 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1037 TimeAxisView* tav = time_axis_view_from_stripable (s);
1041 case Selection::Add:
1042 selection->add (tav);
1044 case Selection::Toggle:
1045 selection->toggle (tav);
1047 case Selection::Extend:
1049 case Selection::Set:
1050 selection->set (tav);
1054 selection->clear_tracks ();
1059 Editor::control_step_tracks_up ()
1061 scroll_tracks_up_line ();
1065 Editor::control_step_tracks_down ()
1067 scroll_tracks_down_line ();
1071 Editor::control_scroll (float fraction)
1073 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1079 double step = fraction * current_page_samples();
1082 _control_scroll_target is an optional<T>
1084 it acts like a pointer to an samplepos_t, with
1085 a operator conversion to boolean to check
1086 that it has a value could possibly use
1087 playhead_cursor->current_sample to store the
1088 value and a boolean in the class to know
1089 when it's out of date
1092 if (!_control_scroll_target) {
1093 _control_scroll_target = _session->transport_sample();
1094 _dragging_playhead = true;
1097 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1098 *_control_scroll_target = 0;
1099 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1100 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1102 *_control_scroll_target += (samplepos_t) trunc (step);
1105 /* move visuals, we'll catch up with it later */
1107 playhead_cursor->set_position (*_control_scroll_target);
1108 UpdateAllTransportClocks (*_control_scroll_target);
1110 if (*_control_scroll_target > (current_page_samples() / 2)) {
1111 /* try to center PH in window */
1112 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1118 Now we do a timeout to actually bring the session to the right place
1119 according to the playhead. This is to avoid reading disk buffers on every
1120 call to control_scroll, which is driven by ScrollTimeline and therefore
1121 probably by a control surface wheel which can generate lots of events.
1123 /* cancel the existing timeout */
1125 control_scroll_connection.disconnect ();
1127 /* add the next timeout */
1129 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1133 Editor::deferred_control_scroll (samplepos_t /*target*/)
1135 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1136 /* reset for next stream */
1137 _control_scroll_target = boost::none;
1138 _dragging_playhead = false;
1143 Editor::access_action (const std::string& action_group, const std::string& action_item)
1149 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1152 act = ActionManager::get_action (action_group.c_str(), action_item.c_str());
1160 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1162 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1166 Editor::on_realize ()
1170 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1171 start_lock_event_timing ();
1176 Editor::start_lock_event_timing ()
1178 /* check if we should lock the GUI every 30 seconds */
1180 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1184 Editor::generic_event_handler (GdkEvent* ev)
1187 case GDK_BUTTON_PRESS:
1188 case GDK_BUTTON_RELEASE:
1189 case GDK_MOTION_NOTIFY:
1191 case GDK_KEY_RELEASE:
1192 if (contents().is_mapped()) {
1193 gettimeofday (&last_event_time, 0);
1197 case GDK_LEAVE_NOTIFY:
1198 switch (ev->crossing.detail) {
1199 case GDK_NOTIFY_UNKNOWN:
1200 case GDK_NOTIFY_INFERIOR:
1201 case GDK_NOTIFY_ANCESTOR:
1203 case GDK_NOTIFY_VIRTUAL:
1204 case GDK_NOTIFY_NONLINEAR:
1205 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1206 /* leaving window, so reset focus, thus ending any and
1207 all text entry operations.
1209 ARDOUR_UI::instance()->reset_focus (&contents());
1222 Editor::lock_timeout_callback ()
1224 struct timeval now, delta;
1226 gettimeofday (&now, 0);
1228 timersub (&now, &last_event_time, &delta);
1230 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1232 /* don't call again. Returning false will effectively
1233 disconnect us from the timer callback.
1235 unlock() will call start_lock_event_timing() to get things
1245 Editor::map_position_change (samplepos_t sample)
1247 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1249 if (_session == 0) {
1253 if (_follow_playhead) {
1254 center_screen (sample);
1257 playhead_cursor->set_position (sample);
1261 Editor::center_screen (samplepos_t sample)
1263 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1265 /* if we're off the page, then scroll.
1268 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1269 center_screen_internal (sample, page);
1274 Editor::center_screen_internal (samplepos_t sample, float page)
1278 if (sample > page) {
1279 sample -= (samplepos_t) page;
1284 reset_x_origin (sample);
1289 Editor::update_title ()
1291 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1293 if (!own_window()) {
1298 bool dirty = _session->dirty();
1300 string session_name;
1302 if (_session->snap_name() != _session->name()) {
1303 session_name = _session->snap_name();
1305 session_name = _session->name();
1309 session_name = "*" + session_name;
1312 WindowTitle title(session_name);
1313 title += S_("Window|Editor");
1314 title += Glib::get_application_name();
1315 own_window()->set_title (title.get_string());
1317 /* ::session_going_away() will have taken care of it */
1322 Editor::set_session (Session *t)
1324 SessionHandlePtr::set_session (t);
1330 /* initialize _leftmost_sample to the extents of the session
1331 * this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample
1332 * before the visible state has been loaded from instant.xml */
1333 _leftmost_sample = session_gui_extents().first;
1335 _playlist_selector->set_session (_session);
1336 nudge_clock->set_session (_session);
1337 _summary->set_session (_session);
1338 _group_tabs->set_session (_session);
1339 _route_groups->set_session (_session);
1340 _regions->set_session (_session);
1341 _snapshots->set_session (_session);
1342 _routes->set_session (_session);
1343 _locations->set_session (_session);
1344 _time_info_box->set_session (_session);
1346 if (rhythm_ferret) {
1347 rhythm_ferret->set_session (_session);
1350 if (analysis_window) {
1351 analysis_window->set_session (_session);
1355 sfbrowser->set_session (_session);
1358 compute_fixed_ruler_scale ();
1360 /* Make sure we have auto loop and auto punch ranges */
1362 Location* loc = _session->locations()->auto_loop_location();
1364 loc->set_name (_("Loop"));
1367 loc = _session->locations()->auto_punch_location();
1370 loc->set_name (_("Punch"));
1373 refresh_location_display ();
1375 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1376 * the selected Marker; this needs the LocationMarker list to be available.
1378 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1379 set_state (*node, Stateful::loading_state_version);
1381 /* catch up on selection state, etc. */
1384 sc.add (Properties::selected);
1385 presentation_info_changed (sc);
1387 /* catch up with the playhead */
1389 _session->request_locate (playhead_cursor->current_sample ());
1390 _pending_initial_locate = true;
1394 /* These signals can all be emitted by a non-GUI thread. Therefore the
1395 handlers for them must not attempt to directly interact with the GUI,
1396 but use PBD::Signal<T>::connect() which accepts an event loop
1397 ("context") where the handler will be asked to run.
1400 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1401 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1402 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1403 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1404 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1405 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1406 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1407 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1408 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1409 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1410 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1411 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1412 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1413 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1414 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1415 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1417 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1418 playhead_cursor->show ();
1420 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1421 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1422 snapped_cursor->show ();
1424 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1425 Config->map_parameters (pc);
1426 _session->config.map_parameters (pc);
1428 restore_ruler_visibility ();
1429 //tempo_map_changed (PropertyChange (0));
1430 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1432 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1433 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1436 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1437 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1440 /* register for undo history */
1441 _session->register_with_memento_command_factory(id(), this);
1442 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1444 LuaInstance::instance()->set_session(_session);
1446 start_updating_meters ();
1450 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1452 using namespace Menu_Helpers;
1454 void (Editor::*emf)(FadeShape);
1455 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1458 images = &_xfade_in_images;
1459 emf = &Editor::set_fade_in_shape;
1461 images = &_xfade_out_images;
1462 emf = &Editor::set_fade_out_shape;
1467 _("Linear (for highly correlated material)"),
1468 *(*images)[FadeLinear],
1469 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 _("Constant power"),
1478 *(*images)[FadeConstantPower],
1479 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *(*images)[FadeSymmetric],
1488 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *(*images)[FadeSlow],
1498 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1501 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1506 *(*images)[FadeFast],
1507 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1510 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 /** Pop up a context menu for when the user clicks on a start crossfade */
1515 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1517 using namespace Menu_Helpers;
1518 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1523 MenuList& items (xfade_in_context_menu.items());
1526 if (arv->audio_region()->fade_in_active()) {
1527 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1529 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1532 items.push_back (SeparatorElem());
1533 fill_xfade_menu (items, true);
1535 xfade_in_context_menu.popup (button, time);
1538 /** Pop up a context menu for when the user clicks on an end crossfade */
1540 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1542 using namespace Menu_Helpers;
1543 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1548 MenuList& items (xfade_out_context_menu.items());
1551 if (arv->audio_region()->fade_out_active()) {
1552 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1554 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1557 items.push_back (SeparatorElem());
1558 fill_xfade_menu (items, false);
1560 xfade_out_context_menu.popup (button, time);
1564 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1566 using namespace Menu_Helpers;
1567 Menu* (Editor::*build_menu_function)();
1570 switch (item_type) {
1572 case RegionViewName:
1573 case RegionViewNameHighlight:
1574 case LeftFrameHandle:
1575 case RightFrameHandle:
1576 if (with_selection) {
1577 build_menu_function = &Editor::build_track_selection_context_menu;
1579 build_menu_function = &Editor::build_track_region_context_menu;
1584 if (with_selection) {
1585 build_menu_function = &Editor::build_track_selection_context_menu;
1587 build_menu_function = &Editor::build_track_context_menu;
1592 if (clicked_routeview->track()) {
1593 build_menu_function = &Editor::build_track_context_menu;
1595 build_menu_function = &Editor::build_track_bus_context_menu;
1600 /* probably shouldn't happen but if it does, we don't care */
1604 menu = (this->*build_menu_function)();
1605 menu->set_name ("ArdourContextMenu");
1607 /* now handle specific situations */
1609 switch (item_type) {
1611 case RegionViewName:
1612 case RegionViewNameHighlight:
1613 case LeftFrameHandle:
1614 case RightFrameHandle:
1615 if (!with_selection) {
1616 if (region_edit_menu_split_item) {
1617 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1618 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1620 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1623 if (region_edit_menu_split_multichannel_item) {
1624 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1625 region_edit_menu_split_multichannel_item->set_sensitive (true);
1627 region_edit_menu_split_multichannel_item->set_sensitive (false);
1640 /* probably shouldn't happen but if it does, we don't care */
1644 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1646 /* Bounce to disk */
1648 using namespace Menu_Helpers;
1649 MenuList& edit_items = menu->items();
1651 edit_items.push_back (SeparatorElem());
1653 switch (clicked_routeview->audio_track()->freeze_state()) {
1654 case AudioTrack::NoFreeze:
1655 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1658 case AudioTrack::Frozen:
1659 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1662 case AudioTrack::UnFrozen:
1663 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1669 if (item_type == StreamItem && clicked_routeview) {
1670 clicked_routeview->build_underlay_menu(menu);
1673 /* When the region menu is opened, we setup the actions so that they look right
1676 sensitize_the_right_region_actions (false);
1677 _last_region_menu_was_main = false;
1679 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1680 menu->popup (button, time);
1684 Editor::build_track_context_menu ()
1686 using namespace Menu_Helpers;
1688 MenuList& edit_items = track_context_menu.items();
1691 add_dstream_context_items (edit_items);
1692 return &track_context_menu;
1696 Editor::build_track_bus_context_menu ()
1698 using namespace Menu_Helpers;
1700 MenuList& edit_items = track_context_menu.items();
1703 add_bus_context_items (edit_items);
1704 return &track_context_menu;
1708 Editor::build_track_region_context_menu ()
1710 using namespace Menu_Helpers;
1711 MenuList& edit_items = track_region_context_menu.items();
1714 /* we've just cleared the track region context menu, so the menu that these
1715 two items were on will have disappeared; stop them dangling.
1717 region_edit_menu_split_item = 0;
1718 region_edit_menu_split_multichannel_item = 0;
1720 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1723 boost::shared_ptr<Track> tr;
1724 boost::shared_ptr<Playlist> pl;
1726 if ((tr = rtv->track())) {
1727 add_region_context_items (edit_items, tr);
1731 add_dstream_context_items (edit_items);
1733 return &track_region_context_menu;
1737 Editor::loudness_analyze_region_selection ()
1742 Selection& s (PublicEditor::instance ().get_selection ());
1743 RegionSelection ars = s.regions;
1744 ARDOUR::AnalysisGraph ag (_session);
1745 samplecnt_t total_work = 0;
1747 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1748 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1752 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1755 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1756 total_work += arv->region ()->length ();
1759 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1761 ag.set_total_samples (total_work);
1762 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1765 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1766 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1770 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1774 ag.analyze_region (ar);
1777 if (!ag.canceled ()) {
1778 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1784 Editor::loudness_analyze_range_selection ()
1789 Selection& s (PublicEditor::instance ().get_selection ());
1790 TimeSelection ts = s.time;
1791 ARDOUR::AnalysisGraph ag (_session);
1792 samplecnt_t total_work = 0;
1794 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1795 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1799 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1803 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1804 total_work += j->length ();
1808 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1810 ag.set_total_samples (total_work);
1811 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1814 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1815 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1819 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1823 ag.analyze_range (rui->route (), pl, ts);
1826 if (!ag.canceled ()) {
1827 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1833 Editor::spectral_analyze_region_selection ()
1835 if (analysis_window == 0) {
1836 analysis_window = new AnalysisWindow();
1839 analysis_window->set_session(_session);
1841 analysis_window->show_all();
1844 analysis_window->set_regionmode();
1845 analysis_window->analyze();
1847 analysis_window->present();
1851 Editor::spectral_analyze_range_selection()
1853 if (analysis_window == 0) {
1854 analysis_window = new AnalysisWindow();
1857 analysis_window->set_session(_session);
1859 analysis_window->show_all();
1862 analysis_window->set_rangemode();
1863 analysis_window->analyze();
1865 analysis_window->present();
1869 Editor::build_track_selection_context_menu ()
1871 using namespace Menu_Helpers;
1872 MenuList& edit_items = track_selection_context_menu.items();
1873 edit_items.clear ();
1875 add_selection_context_items (edit_items);
1876 // edit_items.push_back (SeparatorElem());
1877 // add_dstream_context_items (edit_items);
1879 return &track_selection_context_menu;
1883 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1885 using namespace Menu_Helpers;
1887 /* OK, stick the region submenu at the top of the list, and then add
1891 RegionSelection rs = get_regions_from_selection_and_entered ();
1893 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1895 if (_popup_region_menu_item == 0) {
1896 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1897 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1898 _popup_region_menu_item->show ();
1900 _popup_region_menu_item->set_label (menu_item_name);
1903 /* No layering allowed in later is higher layering model */
1904 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1905 if (act && Config->get_layer_model() == LaterHigher) {
1906 act->set_sensitive (false);
1908 act->set_sensitive (true);
1911 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1913 edit_items.push_back (*_popup_region_menu_item);
1914 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1915 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1917 edit_items.push_back (SeparatorElem());
1920 /** Add context menu items relevant to selection ranges.
1921 * @param edit_items List to add the items to.
1924 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1926 using namespace Menu_Helpers;
1928 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1929 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1931 edit_items.push_back (SeparatorElem());
1932 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1934 edit_items.push_back (SeparatorElem());
1935 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1936 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1938 edit_items.push_back (SeparatorElem());
1940 edit_items.push_back (
1942 _("Move Range Start to Previous Region Boundary"),
1943 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1947 edit_items.push_back (
1949 _("Move Range Start to Next Region Boundary"),
1950 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1954 edit_items.push_back (
1956 _("Move Range End to Previous Region Boundary"),
1957 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1961 edit_items.push_back (
1963 _("Move Range End to Next Region Boundary"),
1964 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1968 edit_items.push_back (SeparatorElem());
1969 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1970 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1972 edit_items.push_back (SeparatorElem());
1973 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1977 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1978 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1983 edit_items.push_back (SeparatorElem());
1984 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1985 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1987 edit_items.push_back (SeparatorElem());
1988 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1989 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1990 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1991 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1992 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1993 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1994 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
2000 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2002 using namespace Menu_Helpers;
2006 Menu *play_menu = manage (new Menu);
2007 MenuList& play_items = play_menu->items();
2008 play_menu->set_name ("ArdourContextMenu");
2010 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2011 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2012 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2013 play_items.push_back (SeparatorElem());
2014 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2016 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2020 Menu *select_menu = manage (new Menu);
2021 MenuList& select_items = select_menu->items();
2022 select_menu->set_name ("ArdourContextMenu");
2024 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2025 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2026 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2027 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2028 select_items.push_back (SeparatorElem());
2029 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2030 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2031 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2032 select_items.push_back (SeparatorElem());
2033 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2034 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2035 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2036 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2037 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2038 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2039 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2041 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2045 Menu *cutnpaste_menu = manage (new Menu);
2046 MenuList& cutnpaste_items = cutnpaste_menu->items();
2047 cutnpaste_menu->set_name ("ArdourContextMenu");
2049 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2050 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2051 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2053 cutnpaste_items.push_back (SeparatorElem());
2055 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2056 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2058 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2060 /* Adding new material */
2062 edit_items.push_back (SeparatorElem());
2063 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2064 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2068 Menu *nudge_menu = manage (new Menu());
2069 MenuList& nudge_items = nudge_menu->items();
2070 nudge_menu->set_name ("ArdourContextMenu");
2072 edit_items.push_back (SeparatorElem());
2073 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2074 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2075 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2076 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2078 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2082 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2084 using namespace Menu_Helpers;
2088 Menu *play_menu = manage (new Menu);
2089 MenuList& play_items = play_menu->items();
2090 play_menu->set_name ("ArdourContextMenu");
2092 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2093 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2094 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2098 Menu *select_menu = manage (new Menu);
2099 MenuList& select_items = select_menu->items();
2100 select_menu->set_name ("ArdourContextMenu");
2102 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2103 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2104 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2105 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2106 select_items.push_back (SeparatorElem());
2107 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2108 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2109 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2110 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2112 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2116 Menu *cutnpaste_menu = manage (new Menu);
2117 MenuList& cutnpaste_items = cutnpaste_menu->items();
2118 cutnpaste_menu->set_name ("ArdourContextMenu");
2120 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2121 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2122 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2124 Menu *nudge_menu = manage (new Menu());
2125 MenuList& nudge_items = nudge_menu->items();
2126 nudge_menu->set_name ("ArdourContextMenu");
2128 edit_items.push_back (SeparatorElem());
2129 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2130 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2131 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2132 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2134 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2138 Editor::grid_type() const
2144 Editor::grid_musical() const
2146 switch (_grid_type) {
2147 case GridTypeBeatDiv32:
2148 case GridTypeBeatDiv28:
2149 case GridTypeBeatDiv24:
2150 case GridTypeBeatDiv20:
2151 case GridTypeBeatDiv16:
2152 case GridTypeBeatDiv14:
2153 case GridTypeBeatDiv12:
2154 case GridTypeBeatDiv10:
2155 case GridTypeBeatDiv8:
2156 case GridTypeBeatDiv7:
2157 case GridTypeBeatDiv6:
2158 case GridTypeBeatDiv5:
2159 case GridTypeBeatDiv4:
2160 case GridTypeBeatDiv3:
2161 case GridTypeBeatDiv2:
2166 case GridTypeTimecode:
2167 case GridTypeMinSec:
2168 case GridTypeCDFrame:
2175 Editor::grid_nonmusical() const
2177 switch (_grid_type) {
2178 case GridTypeTimecode:
2179 case GridTypeMinSec:
2180 case GridTypeCDFrame:
2182 case GridTypeBeatDiv32:
2183 case GridTypeBeatDiv28:
2184 case GridTypeBeatDiv24:
2185 case GridTypeBeatDiv20:
2186 case GridTypeBeatDiv16:
2187 case GridTypeBeatDiv14:
2188 case GridTypeBeatDiv12:
2189 case GridTypeBeatDiv10:
2190 case GridTypeBeatDiv8:
2191 case GridTypeBeatDiv7:
2192 case GridTypeBeatDiv6:
2193 case GridTypeBeatDiv5:
2194 case GridTypeBeatDiv4:
2195 case GridTypeBeatDiv3:
2196 case GridTypeBeatDiv2:
2205 Editor::snap_mode() const
2211 Editor::set_grid_to (GridType gt)
2213 if (_grid_type == gt) { // already set
2217 unsigned int grid_ind = (unsigned int)gt;
2219 if (internal_editing()) {
2220 internal_grid_type = gt;
2222 pre_internal_grid_type = gt;
2227 if (grid_ind > grid_type_strings.size() - 1) {
2229 _grid_type = (GridType)grid_ind;
2232 string str = grid_type_strings[grid_ind];
2234 if (str != grid_type_selector.get_text()) {
2235 grid_type_selector.set_text (str);
2238 /* show appropriate rulers for this grid setting.
2239 * TODO: perhaps make this optional.
2240 * Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines
2242 if (grid_musical()) {
2243 ruler_tempo_action->set_active(true);
2244 ruler_meter_action->set_active(true);
2246 ruler_bbt_action->set_active(true);
2247 ruler_timecode_action->set_active(false);
2248 ruler_minsec_action->set_active(false);
2249 ruler_samples_action->set_active(false);
2250 } else if (_grid_type == GridTypeTimecode) {
2251 ruler_tempo_action->set_active(false);
2252 ruler_meter_action->set_active(false);
2254 ruler_bbt_action->set_active(false);
2255 ruler_timecode_action->set_active(true);
2256 ruler_minsec_action->set_active(false);
2257 ruler_samples_action->set_active(false);
2258 } else if (_grid_type == GridTypeMinSec) {
2259 ruler_tempo_action->set_active(false);
2260 ruler_meter_action->set_active(false);
2262 ruler_bbt_action->set_active(false);
2263 ruler_timecode_action->set_active(false);
2264 ruler_minsec_action->set_active(true);
2265 ruler_samples_action->set_active(false);
2266 } else if (_grid_type == GridTypeCDFrame) {
2267 ruler_tempo_action->set_active(false);
2268 ruler_meter_action->set_active(false);
2270 ruler_bbt_action->set_active(false);
2271 ruler_timecode_action->set_active(false);
2272 ruler_minsec_action->set_active(true);
2274 ruler_cd_marker_action->set_active(true);
2275 ruler_samples_action->set_active(false);
2280 if (grid_musical()) {
2281 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2282 update_tempo_based_rulers ();
2285 mark_region_boundary_cache_dirty ();
2287 redisplay_grid (false);
2289 SnapChanged (); /* EMIT SIGNAL */
2293 Editor::set_snap_mode (SnapMode mode)
2295 if (internal_editing()) {
2296 internal_snap_mode = mode;
2298 pre_internal_snap_mode = mode;
2303 if (_snap_mode == SnapOff) {
2304 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2306 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2313 Editor::set_edit_point_preference (EditPoint ep, bool force)
2315 bool changed = (_edit_point != ep);
2318 if (Profile->get_mixbus())
2319 if (ep == EditAtSelectedMarker)
2320 ep = EditAtPlayhead;
2322 string str = edit_point_strings[(int)ep];
2323 if (str != edit_point_selector.get_text ()) {
2324 edit_point_selector.set_text (str);
2327 update_all_enter_cursors();
2329 if (!force && !changed) {
2333 const char* action=NULL;
2335 switch (_edit_point) {
2336 case EditAtPlayhead:
2337 action = "edit-at-playhead";
2339 case EditAtSelectedMarker:
2340 action = "edit-at-marker";
2343 action = "edit-at-mouse";
2347 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2349 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2353 bool in_track_canvas;
2355 if (!mouse_sample (foo, in_track_canvas)) {
2356 in_track_canvas = false;
2359 reset_canvas_action_sensitivity (in_track_canvas);
2360 sensitize_the_right_region_actions (false);
2366 Editor::set_state (const XMLNode& node, int version)
2369 PBD::Unwinder<bool> nsi (no_save_instant, true);
2372 Tabbable::set_state (node, version);
2375 if (_session && node.get_property ("playhead", ph_pos)) {
2377 playhead_cursor->set_position (ph_pos);
2379 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2380 playhead_cursor->set_position (0);
2383 playhead_cursor->set_position (0);
2386 node.get_property ("mixer-width", editor_mixer_strip_width);
2388 node.get_property ("zoom-focus", zoom_focus);
2389 zoom_focus_selection_done (zoom_focus);
2392 if (node.get_property ("zoom", z)) {
2393 /* older versions of ardour used floating point samples_per_pixel */
2394 reset_zoom (llrintf (z));
2396 reset_zoom (samples_per_pixel);
2400 if (node.get_property ("visible-track-count", cnt)) {
2401 set_visible_track_count (cnt);
2405 if (!node.get_property ("grid-type", grid_type)) {
2406 grid_type = _grid_type;
2408 set_grid_to (grid_type);
2411 if (node.get_property ("snap-mode", sm)) {
2412 snap_mode_selection_done(sm);
2413 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2414 * snap_mode_selection_done() will only mark an already active item as active
2415 * which does not trigger set_text().
2419 set_snap_mode (_snap_mode);
2422 node.get_property ("internal-grid-type", internal_grid_type);
2423 node.get_property ("internal-snap-mode", internal_snap_mode);
2424 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2425 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2428 if (node.get_property ("mouse-mode", mm_str)) {
2429 MouseMode m = str2mousemode(mm_str);
2430 set_mouse_mode (m, true);
2432 set_mouse_mode (MouseObject, true);
2436 if (node.get_property ("left-frame", lf_pos)) {
2440 reset_x_origin (lf_pos);
2444 if (node.get_property ("y-origin", y_origin)) {
2445 reset_y_origin (y_origin);
2448 if (node.get_property ("join-object-range", yn)) {
2449 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2451 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2452 tact->set_active (!yn);
2453 tact->set_active (yn);
2455 set_mouse_mode(mouse_mode, true);
2459 if (node.get_property ("edit-point", ep)) {
2460 set_edit_point_preference (ep, true);
2462 set_edit_point_preference (_edit_point);
2465 if (node.get_property ("follow-playhead", yn)) {
2466 set_follow_playhead (yn);
2469 if (node.get_property ("stationary-playhead", yn)) {
2470 set_stationary_playhead (yn);
2473 RegionListSortType sort_type;
2474 if (node.get_property ("region-list-sort-type", sort_type)) {
2475 _regions->reset_sort_type (sort_type, true);
2478 if (node.get_property ("show-editor-mixer", yn)) {
2480 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2483 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2485 /* do it twice to force the change */
2487 tact->set_active (!yn);
2488 tact->set_active (yn);
2491 if (node.get_property ("show-editor-list", yn)) {
2493 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2498 /* do it twice to force the change */
2500 tact->set_active (!yn);
2501 tact->set_active (yn);
2505 if (node.get_property (X_("editor-list-page"), el_page)) {
2506 _the_notebook.set_current_page (el_page);
2509 if (node.get_property (X_("show-marker-lines"), yn)) {
2510 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2512 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2514 tact->set_active (!yn);
2515 tact->set_active (yn);
2518 XMLNodeList children = node.children ();
2519 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2520 selection->set_state (**i, Stateful::current_state_version);
2521 _regions->set_state (**i);
2522 _locations->set_state (**i);
2525 if (node.get_property ("maximised", yn)) {
2526 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2528 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2529 bool fs = tact && tact->get_active();
2531 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2535 samplepos_t nudge_clock_value;
2536 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2537 nudge_clock->set (nudge_clock_value);
2539 nudge_clock->set_mode (AudioClock::Timecode);
2540 nudge_clock->set (_session->sample_rate() * 5, true);
2545 * Not all properties may have been in XML, but
2546 * those that are linked to a private variable may need changing
2550 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2551 yn = _follow_playhead;
2553 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2554 if (tact->get_active() != yn) {
2555 tact->set_active (yn);
2559 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2560 yn = _stationary_playhead;
2562 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2563 if (tact->get_active() != yn) {
2564 tact->set_active (yn);
2569 return LuaInstance::instance()->set_state(node);
2573 Editor::get_state ()
2575 XMLNode* node = new XMLNode (X_("Editor"));
2577 node->set_property ("id", id().to_s ());
2579 node->add_child_nocopy (Tabbable::get_state());
2581 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2582 node->set_property("notebook-shrunk", _notebook_shrunk);
2583 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2585 maybe_add_mixer_strip_width (*node);
2587 node->set_property ("zoom-focus", zoom_focus);
2589 node->set_property ("zoom", samples_per_pixel);
2590 node->set_property ("grid-type", _grid_type);
2591 node->set_property ("snap-mode", _snap_mode);
2592 node->set_property ("internal-grid-type", internal_grid_type);
2593 node->set_property ("internal-snap-mode", internal_snap_mode);
2594 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2595 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2596 node->set_property ("edit-point", _edit_point);
2597 node->set_property ("visible-track-count", _visible_track_count);
2599 node->set_property ("playhead", playhead_cursor->current_sample ());
2600 node->set_property ("left-frame", _leftmost_sample);
2601 node->set_property ("y-origin", vertical_adjustment.get_value ());
2603 node->set_property ("maximised", _maximised);
2604 node->set_property ("follow-playhead", _follow_playhead);
2605 node->set_property ("stationary-playhead", _stationary_playhead);
2606 node->set_property ("region-list-sort-type", _regions->sort_type ());
2607 node->set_property ("mouse-mode", mouse_mode);
2608 node->set_property ("join-object-range", smart_mode_action->get_active ());
2610 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2612 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2613 node->set_property (X_("show-editor-mixer"), tact->get_active());
2616 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2618 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2619 node->set_property (X_("show-editor-list"), tact->get_active());
2622 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2624 if (button_bindings) {
2625 XMLNode* bb = new XMLNode (X_("Buttons"));
2626 button_bindings->save (*bb);
2627 node->add_child_nocopy (*bb);
2630 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2632 node->add_child_nocopy (selection->get_state ());
2633 node->add_child_nocopy (_regions->get_state ());
2635 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2637 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2638 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2639 node->add_child_nocopy (_locations->get_state ());
2644 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2645 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2647 * @return pair: TimeAxisView that y is over, layer index.
2649 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2650 * in stacked or expanded region display mode, otherwise 0.
2652 std::pair<TimeAxisView *, double>
2653 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2655 if (!trackview_relative_offset) {
2656 y -= _trackview_group->canvas_origin().y;
2660 return std::make_pair ((TimeAxisView *) 0, 0);
2663 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2665 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2672 return std::make_pair ((TimeAxisView *) 0, 0);
2676 Editor::set_snapped_cursor_position (samplepos_t pos)
2678 if (_edit_point == EditAtMouse) {
2679 snapped_cursor->set_position(pos);
2684 /** Snap a position to the grid, if appropriate, taking into account current
2685 * grid settings and also the state of any snap modifier keys that may be pressed.
2686 * @param start Position to snap.
2687 * @param event Event to get current key modifier information from, or 0.
2690 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
2692 if (!_session || !event) {
2696 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2697 if (_snap_mode == SnapOff) {
2698 snap_to_internal (start, direction, pref, for_mark);
2700 start.set (start.sample, 0);
2703 if (_snap_mode != SnapOff) {
2704 snap_to_internal (start, direction, pref, for_mark);
2705 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2706 /* SnapOff, but we pressed the snap_delta modifier */
2707 snap_to_internal (start, direction, pref, for_mark);
2709 start.set (start.sample, 0);
2715 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2717 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2718 start.set (start.sample, 0);
2722 snap_to_internal (start, direction, pref, for_mark, ensure_snap);
2726 check_best_snap (samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best)
2728 samplepos_t diff = abs (test - presnap);
2734 test = max_samplepos; // reset this so it doesn't get accidentally reused
2738 Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
2740 if (marks.empty()) return presnap;
2744 samplepos_t test = presnap;
2746 before = after = max_samplepos;
2748 /* get marks to either side of presnap */
2749 vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
2750 while (m != marks.end() && (m->position < presnap)) {
2754 if (m == marks.end ()) {
2755 /* ran out of marks */
2756 before = marks.back().position;
2759 after = m->position;
2761 if (m != marks.begin ()) {
2763 before = m->position;
2766 if (before == max_samplepos && after == max_samplepos) {
2767 /* No grid to snap to, so just don't snap */
2769 } else if (before == max_samplepos) {
2771 } else if (after == max_samplepos) {
2774 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2776 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2778 else if (direction == 0) {
2779 if ((presnap - before) < (after - presnap)) {
2791 Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
2797 _session->locations()->marks_either_side (presnap, before, after);
2799 if (before == max_samplepos && after == max_samplepos) {
2800 /* No marks to snap to, so just don't snap */
2802 } else if (before == max_samplepos) {
2804 } else if (after == max_samplepos) {
2807 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2809 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2811 } else if (direction == 0) {
2812 if ((presnap - before) < (after - presnap)) {
2824 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2826 const samplepos_t presnap = start.sample;
2828 samplepos_t test = max_samplepos; // for each snap, we'll use this value
2829 samplepos_t dist = max_samplepos; // this records the distance of the best snap result we've found so far
2830 samplepos_t best = max_samplepos; // this records the best snap-result we've found so far
2832 /* check snap-to-marker */
2833 if ( (pref == SnapToAny) && UIConfiguration::instance().get_snap_to_marks()) {
2838 test = marker_snap_to_internal (presnap, direction);
2839 check_best_snap(presnap, test, dist, best);
2842 /* check snap-to-region-{start/end/sync} */
2844 (pref == SnapToAny) &&
2845 (UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync())
2847 if (!region_boundary_cache.empty()) {
2849 vector<samplepos_t>::iterator prev = region_boundary_cache.begin();
2850 vector<samplepos_t>::iterator next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2851 if (next != region_boundary_cache.begin ()) {
2856 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2858 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2860 else if (direction == 0) {
2861 if ((presnap - *prev) < (*next - presnap)) {
2870 check_best_snap(presnap, test, dist, best);
2874 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone)) {
2875 test = snap_to_grid (grid_marks, presnap, direction);
2876 check_best_snap(presnap, test, dist, best);
2879 /* now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
2880 * this also helps to avoid snapping to somewhere the user can't see. (i.e.: I clicked on a region and it disappeared!!)
2881 * ToDo: Perhaps this should only occur if EditPointMouse?
2883 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2885 start.set (best, 0);
2887 } else if (presnap > best) {
2888 if (presnap > (best+ snap_threshold_s)) {
2891 } else if (presnap < best) {
2892 if (presnap < (best - snap_threshold_s)) {
2897 start.set (best, 0);
2902 Editor::setup_toolbar ()
2904 HBox* mode_box = manage(new HBox);
2905 mode_box->set_border_width (2);
2906 mode_box->set_spacing(2);
2908 HBox* mouse_mode_box = manage (new HBox);
2909 HBox* mouse_mode_hbox = manage (new HBox);
2910 VBox* mouse_mode_vbox = manage (new VBox);
2911 Alignment* mouse_mode_align = manage (new Alignment);
2913 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2914 mouse_mode_size_group->add_widget (smart_mode_button);
2915 mouse_mode_size_group->add_widget (mouse_move_button);
2916 mouse_mode_size_group->add_widget (mouse_cut_button);
2917 mouse_mode_size_group->add_widget (mouse_select_button);
2918 mouse_mode_size_group->add_widget (mouse_timefx_button);
2919 mouse_mode_size_group->add_widget (mouse_audition_button);
2920 mouse_mode_size_group->add_widget (mouse_draw_button);
2921 mouse_mode_size_group->add_widget (mouse_content_button);
2923 if (!Profile->get_mixbus()) {
2924 mouse_mode_size_group->add_widget (zoom_in_button);
2925 mouse_mode_size_group->add_widget (zoom_out_button);
2926 mouse_mode_size_group->add_widget (zoom_out_full_button);
2927 mouse_mode_size_group->add_widget (zoom_focus_selector);
2928 mouse_mode_size_group->add_widget (tav_shrink_button);
2929 mouse_mode_size_group->add_widget (tav_expand_button);
2931 mouse_mode_size_group->add_widget (zoom_preset_selector);
2932 mouse_mode_size_group->add_widget (visible_tracks_selector);
2935 mouse_mode_size_group->add_widget (grid_type_selector);
2936 mouse_mode_size_group->add_widget (snap_mode_button);
2938 mouse_mode_size_group->add_widget (edit_point_selector);
2939 mouse_mode_size_group->add_widget (edit_mode_selector);
2941 mouse_mode_size_group->add_widget (*nudge_clock);
2942 mouse_mode_size_group->add_widget (nudge_forward_button);
2943 mouse_mode_size_group->add_widget (nudge_backward_button);
2945 mouse_mode_hbox->set_spacing (2);
2947 if (!ARDOUR::Profile->get_trx()) {
2948 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2951 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2952 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2954 if (!ARDOUR::Profile->get_mixbus()) {
2955 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2956 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2959 if (!ARDOUR::Profile->get_trx()) {
2960 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2961 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2962 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2965 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2967 mouse_mode_align->add (*mouse_mode_vbox);
2968 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2970 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2972 edit_mode_selector.set_name ("mouse mode button");
2974 if (!ARDOUR::Profile->get_trx()) {
2975 mode_box->pack_start (edit_mode_selector, false, false);
2976 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2977 mode_box->pack_start (edit_point_selector, false, false);
2978 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2981 mode_box->pack_start (*mouse_mode_box, false, false);
2985 _zoom_box.set_spacing (2);
2986 _zoom_box.set_border_width (2);
2990 zoom_preset_selector.set_name ("zoom button");
2991 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
2993 zoom_in_button.set_name ("zoom button");
2994 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2995 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2996 zoom_in_button.set_related_action (act);
2998 zoom_out_button.set_name ("zoom button");
2999 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3000 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3001 zoom_out_button.set_related_action (act);
3003 zoom_out_full_button.set_name ("zoom button");
3004 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3005 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3006 zoom_out_full_button.set_related_action (act);
3008 zoom_focus_selector.set_name ("zoom button");
3010 if (ARDOUR::Profile->get_mixbus()) {
3011 _zoom_box.pack_start (zoom_preset_selector, false, false);
3012 } else if (ARDOUR::Profile->get_trx()) {
3013 mode_box->pack_start (zoom_out_button, false, false);
3014 mode_box->pack_start (zoom_in_button, false, false);
3016 _zoom_box.pack_start (zoom_out_button, false, false);
3017 _zoom_box.pack_start (zoom_in_button, false, false);
3018 _zoom_box.pack_start (zoom_out_full_button, false, false);
3019 _zoom_box.pack_start (zoom_focus_selector, false, false);
3022 /* Track zoom buttons */
3023 _track_box.set_spacing (2);
3024 _track_box.set_border_width (2);
3026 visible_tracks_selector.set_name ("zoom button");
3027 if (Profile->get_mixbus()) {
3028 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3030 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3033 tav_expand_button.set_name ("zoom button");
3034 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3035 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3036 tav_expand_button.set_related_action (act);
3038 tav_shrink_button.set_name ("zoom button");
3039 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3040 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3041 tav_shrink_button.set_related_action (act);
3043 if (ARDOUR::Profile->get_mixbus()) {
3044 _track_box.pack_start (visible_tracks_selector);
3045 } else if (ARDOUR::Profile->get_trx()) {
3046 _track_box.pack_start (tav_shrink_button);
3047 _track_box.pack_start (tav_expand_button);
3049 _track_box.pack_start (visible_tracks_selector);
3050 _track_box.pack_start (tav_shrink_button);
3051 _track_box.pack_start (tav_expand_button);
3054 snap_box.set_spacing (2);
3055 snap_box.set_border_width (2);
3057 grid_type_selector.set_name ("mouse mode button");
3059 snap_mode_button.set_name ("mouse mode button");
3061 edit_point_selector.set_name ("mouse mode button");
3063 snap_box.pack_start (snap_mode_button, false, false);
3064 snap_box.pack_start (grid_type_selector, false, false);
3068 HBox *nudge_box = manage (new HBox);
3069 nudge_box->set_spacing (2);
3070 nudge_box->set_border_width (2);
3072 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3073 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3075 nudge_box->pack_start (nudge_backward_button, false, false);
3076 nudge_box->pack_start (nudge_forward_button, false, false);
3077 nudge_box->pack_start (*nudge_clock, false, false);
3080 /* Pack everything in... */
3082 toolbar_hbox.set_spacing (2);
3083 toolbar_hbox.set_border_width (2);
3085 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3086 tool_shadow->set_size_request (4, -1);
3087 tool_shadow->show();
3089 ebox_hpacker.pack_start (*tool_shadow, false, false);
3090 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3092 Gtk::EventBox* spacer = manage (new Gtk::EventBox); // extra space under the mouse toolbar, for aesthetics
3093 spacer->set_name("EditorWindow");
3094 spacer->set_size_request(-1,4);
3097 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3098 ebox_vpacker.pack_start(*spacer, false, false);
3099 ebox_vpacker.show();
3101 toolbar_hbox.pack_start (*mode_box, false, false);
3103 if (!ARDOUR::Profile->get_trx()) {
3105 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3107 toolbar_hbox.pack_start (snap_box, false, false);
3109 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3111 toolbar_hbox.pack_start (*nudge_box, false, false);
3113 toolbar_hbox.pack_end (_zoom_box, false, false, 2);
3115 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3117 toolbar_hbox.pack_end (_track_box, false, false);
3121 toolbar_hbox.show_all ();
3125 Editor::build_edit_point_menu ()
3127 using namespace Menu_Helpers;
3129 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3130 if(!Profile->get_mixbus())
3131 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3132 edit_point_selector.AddMenuElem (MenuElem (edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3134 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3138 Editor::build_edit_mode_menu ()
3140 using namespace Menu_Helpers;
3142 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3143 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3144 edit_mode_selector.AddMenuElem (MenuElem (edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3145 /* Note: Splice was removed */
3147 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3151 Editor::build_grid_type_menu ()
3153 using namespace Menu_Helpers;
3155 /* main grid: bars, quarter-notes, etc */
3156 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3157 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3158 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3159 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3160 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3161 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3162 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3163 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3166 grid_type_selector.AddMenuElem(SeparatorElem());
3167 Gtk::Menu *_triplet_menu = manage (new Menu);
3168 MenuList& triplet_items (_triplet_menu->items());
3170 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3)));
3171 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6)));
3172 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12)));
3173 triplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24)));
3175 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3177 /* quintuplet grid */
3178 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3179 MenuList& quintuplet_items (_quintuplet_menu->items());
3181 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5)));
3182 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10)));
3183 quintuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20)));
3185 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3187 /* septuplet grid */
3188 Gtk::Menu *_septuplet_menu = manage (new Menu);
3189 MenuList& septuplet_items (_septuplet_menu->items());
3191 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7)));
3192 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14)));
3193 septuplet_items.push_back (MenuElem (grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28)));
3195 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3197 grid_type_selector.AddMenuElem(SeparatorElem());
3198 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeTimecode], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeTimecode)));
3199 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3200 grid_type_selector.AddMenuElem (MenuElem (grid_type_strings[(int)GridTypeCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeCDFrame)));
3202 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
3206 Editor::setup_tooltips ()
3208 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3209 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3210 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3211 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3212 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3213 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3214 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3215 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3216 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3217 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3218 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3219 set_tooltip (zoom_in_button, _("Zoom In"));
3220 set_tooltip (zoom_out_button, _("Zoom Out"));
3221 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3222 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3223 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3224 set_tooltip (tav_expand_button, _("Expand Tracks"));
3225 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3226 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3227 set_tooltip (grid_type_selector, _("Grid Mode"));
3228 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3229 set_tooltip (edit_point_selector, _("Edit Point"));
3230 set_tooltip (edit_mode_selector, _("Edit Mode"));
3231 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3235 Editor::convert_drop_to_paths (
3236 vector<string>& paths,
3237 const RefPtr<Gdk::DragContext>& /*context*/,
3240 const SelectionData& data,
3244 if (_session == 0) {
3248 vector<string> uris = data.get_uris();
3252 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3253 are actually URI lists. So do it by hand.
3256 if (data.get_target() != "text/plain") {
3260 /* Parse the "uri-list" format that Nautilus provides,
3261 where each pathname is delimited by \r\n.
3263 THERE MAY BE NO NULL TERMINATING CHAR!!!
3266 string txt = data.get_text();
3270 p = (char *) malloc (txt.length() + 1);
3271 txt.copy (p, txt.length(), 0);
3272 p[txt.length()] = '\0';
3278 while (g_ascii_isspace (*p))
3282 while (*q && (*q != '\n') && (*q != '\r')) {
3289 while (q > p && g_ascii_isspace (*q))
3294 uris.push_back (string (p, q - p + 1));
3298 p = strchr (p, '\n');
3310 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3311 if ((*i).substr (0,7) == "file://") {
3312 paths.push_back (Glib::filename_from_uri (*i));
3320 Editor::new_tempo_section ()
3325 Editor::map_transport_state ()
3327 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3329 if (_session && _session->transport_stopped()) {
3330 have_pending_keyboard_selection = false;
3333 update_loop_range_view ();
3337 Editor::transport_looped ()
3339 /* reset Playhead position interpolation.
3340 * see Editor::super_rapid_screen_update
3342 _last_update_time = 0;
3348 Editor::begin_selection_op_history ()
3350 selection_op_cmd_depth = 0;
3351 selection_op_history_it = 0;
3353 while(!selection_op_history.empty()) {
3354 delete selection_op_history.front();
3355 selection_op_history.pop_front();
3358 selection_undo_action->set_sensitive (false);
3359 selection_redo_action->set_sensitive (false);
3360 selection_op_history.push_front (&_selection_memento->get_state ());
3364 Editor::begin_reversible_selection_op (string name)
3367 //cerr << name << endl;
3368 /* begin/commit pairs can be nested */
3369 selection_op_cmd_depth++;
3374 Editor::commit_reversible_selection_op ()
3377 if (selection_op_cmd_depth == 1) {
3379 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3380 /* The user has undone some selection ops and then made a new one,
3381 * making anything earlier in the list invalid.
3384 list<XMLNode *>::iterator it = selection_op_history.begin();
3385 list<XMLNode *>::iterator e_it = it;
3386 advance (e_it, selection_op_history_it);
3388 for (; it != e_it; ++it) {
3391 selection_op_history.erase (selection_op_history.begin(), e_it);
3394 selection_op_history.push_front (&_selection_memento->get_state ());
3395 selection_op_history_it = 0;
3397 selection_undo_action->set_sensitive (true);
3398 selection_redo_action->set_sensitive (false);
3401 if (selection_op_cmd_depth > 0) {
3402 selection_op_cmd_depth--;
3408 Editor::undo_selection_op ()
3411 selection_op_history_it++;
3413 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3414 if (n == selection_op_history_it) {
3415 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3416 selection_redo_action->set_sensitive (true);
3420 /* is there an earlier entry? */
3421 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3422 selection_undo_action->set_sensitive (false);
3428 Editor::redo_selection_op ()
3431 if (selection_op_history_it > 0) {
3432 selection_op_history_it--;
3435 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3436 if (n == selection_op_history_it) {
3437 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3438 selection_undo_action->set_sensitive (true);
3443 if (selection_op_history_it == 0) {
3444 selection_redo_action->set_sensitive (false);
3450 Editor::begin_reversible_command (string name)
3453 before.push_back (&_selection_memento->get_state ());
3454 _session->begin_reversible_command (name);
3459 Editor::begin_reversible_command (GQuark q)
3462 before.push_back (&_selection_memento->get_state ());
3463 _session->begin_reversible_command (q);
3468 Editor::abort_reversible_command ()
3471 while(!before.empty()) {
3472 delete before.front();
3475 _session->abort_reversible_command ();
3480 Editor::commit_reversible_command ()
3483 if (before.size() == 1) {
3484 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3485 redo_action->set_sensitive(false);
3486 undo_action->set_sensitive(true);
3487 begin_selection_op_history ();
3490 if (before.empty()) {
3491 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3496 _session->commit_reversible_command ();
3501 Editor::history_changed ()
3505 if (undo_action && _session) {
3506 if (_session->undo_depth() == 0) {
3507 label = S_("Command|Undo");
3509 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3511 undo_action->property_label() = label;
3514 if (redo_action && _session) {
3515 if (_session->redo_depth() == 0) {
3517 redo_action->set_sensitive (false);
3519 label = string_compose(_("Redo (%1)"), _session->next_redo());
3520 redo_action->set_sensitive (true);
3522 redo_action->property_label() = label;
3527 Editor::duplicate_range (bool with_dialog)
3531 RegionSelection rs = get_regions_from_selection_and_entered ();
3533 if (selection->time.length() == 0 && rs.empty()) {
3539 ArdourDialog win (_("Duplicate"));
3540 Label label (_("Number of duplications:"));
3541 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3542 SpinButton spinner (adjustment, 0.0, 1);
3545 win.get_vbox()->set_spacing (12);
3546 win.get_vbox()->pack_start (hbox);
3547 hbox.set_border_width (6);
3548 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3550 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3551 place, visually. so do this by hand.
3554 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3555 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3556 spinner.grab_focus();
3562 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3563 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3564 win.set_default_response (RESPONSE_ACCEPT);
3566 spinner.grab_focus ();
3568 switch (win.run ()) {
3569 case RESPONSE_ACCEPT:
3575 times = adjustment.get_value();
3578 if ((current_mouse_mode() == MouseRange)) {
3579 if (selection->time.length()) {
3580 duplicate_selection (times);
3582 } else if (get_smart_mode()) {
3583 if (selection->time.length()) {
3584 duplicate_selection (times);
3586 duplicate_some_regions (rs, times);
3588 duplicate_some_regions (rs, times);
3593 Editor::set_edit_mode (EditMode m)
3595 Config->set_edit_mode (m);
3599 Editor::cycle_edit_mode ()
3601 switch (Config->get_edit_mode()) {
3603 Config->set_edit_mode (Ripple);
3607 Config->set_edit_mode (Lock);
3610 Config->set_edit_mode (Slide);
3616 Editor::edit_mode_selection_done (EditMode m)
3618 Config->set_edit_mode (m);
3622 Editor::grid_type_selection_done (GridType gridtype)
3624 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3626 ract->set_active ();
3631 Editor::snap_mode_selection_done (SnapMode mode)
3633 RefPtr<RadioAction> ract = snap_mode_action (mode);
3636 ract->set_active (true);
3641 Editor::cycle_edit_point (bool with_marker)
3643 if(Profile->get_mixbus())
3644 with_marker = false;
3646 switch (_edit_point) {
3648 set_edit_point_preference (EditAtPlayhead);
3650 case EditAtPlayhead:
3652 set_edit_point_preference (EditAtSelectedMarker);
3654 set_edit_point_preference (EditAtMouse);
3657 case EditAtSelectedMarker:
3658 set_edit_point_preference (EditAtMouse);
3664 Editor::edit_point_selection_done (EditPoint ep)
3666 set_edit_point_preference (ep);
3670 Editor::build_zoom_focus_menu ()
3672 using namespace Menu_Helpers;
3674 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3675 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3676 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3677 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3678 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3679 zoom_focus_selector.AddMenuElem (MenuElem (zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3681 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3685 Editor::zoom_focus_selection_done (ZoomFocus f)
3687 RefPtr<RadioAction> ract = zoom_focus_action (f);
3689 ract->set_active ();
3694 Editor::build_track_count_menu ()
3696 using namespace Menu_Helpers;
3698 if (!Profile->get_mixbus()) {
3699 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3700 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3709 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3713 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3724 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3725 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3731 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3732 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3733 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3734 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3735 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3740 Editor::set_zoom_preset (int64_t ms)
3743 temporal_zoom_session();
3747 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3748 temporal_zoom ((sample_rate * ms / 1000) / _visible_canvas_width);
3752 Editor::set_visible_track_count (int32_t n)
3754 _visible_track_count = n;
3756 /* if the canvas hasn't really been allocated any size yet, just
3757 record the desired number of visible tracks and return. when canvas
3758 allocation happens, we will get called again and then we can do the
3762 if (_visible_canvas_height <= 1) {
3768 DisplaySuspender ds;
3770 if (_visible_track_count > 0) {
3771 h = trackviews_height() / _visible_track_count;
3772 std::ostringstream s;
3773 s << _visible_track_count;
3775 } else if (_visible_track_count == 0) {
3777 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3778 if ((*i)->marked_for_display()) {
3780 TimeAxisView::Children cl ((*i)->get_child_list ());
3781 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3782 if ((*j)->marked_for_display()) {
3789 visible_tracks_selector.set_text (X_("*"));
3792 h = trackviews_height() / n;
3795 /* negative value means that the visible track count has
3796 been overridden by explicit track height changes.
3798 visible_tracks_selector.set_text (X_("*"));
3802 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3803 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3806 if (str != visible_tracks_selector.get_text()) {
3807 visible_tracks_selector.set_text (str);
3812 Editor::override_visible_track_count ()
3814 _visible_track_count = -1;
3815 visible_tracks_selector.set_text (_("*"));
3819 Editor::edit_controls_button_release (GdkEventButton* ev)
3821 if (Keyboard::is_context_menu_event (ev)) {
3822 ARDOUR_UI::instance()->add_route ();
3823 } else if (ev->button == 1) {
3824 selection->clear_tracks ();
3831 Editor::mouse_select_button_release (GdkEventButton* ev)
3833 /* this handles just right-clicks */
3835 if (ev->button != 3) {
3843 Editor::set_zoom_focus (ZoomFocus f)
3845 string str = zoom_focus_strings[(int)f];
3847 if (str != zoom_focus_selector.get_text()) {
3848 zoom_focus_selector.set_text (str);
3851 if (zoom_focus != f) {
3858 Editor::cycle_zoom_focus ()
3860 switch (zoom_focus) {
3862 set_zoom_focus (ZoomFocusRight);
3864 case ZoomFocusRight:
3865 set_zoom_focus (ZoomFocusCenter);
3867 case ZoomFocusCenter:
3868 set_zoom_focus (ZoomFocusPlayhead);
3870 case ZoomFocusPlayhead:
3871 set_zoom_focus (ZoomFocusMouse);
3873 case ZoomFocusMouse:
3874 set_zoom_focus (ZoomFocusEdit);
3877 set_zoom_focus (ZoomFocusLeft);
3883 Editor::update_grid ()
3885 if (grid_musical()) {
3886 std::vector<TempoMap::BBTPoint> grid;
3887 if (bbt_ruler_scale != bbt_show_many) {
3888 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3890 maybe_draw_grid_lines ();
3891 } else if (grid_nonmusical()) {
3892 maybe_draw_grid_lines ();
3899 Editor::toggle_follow_playhead ()
3901 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3903 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3904 set_follow_playhead (tact->get_active());
3908 /** @param yn true to follow playhead, otherwise false.
3909 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3912 Editor::set_follow_playhead (bool yn, bool catch_up)
3914 if (_follow_playhead != yn) {
3915 if ((_follow_playhead = yn) == true && catch_up) {
3917 reset_x_origin_to_follow_playhead ();
3924 Editor::toggle_stationary_playhead ()
3926 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3928 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3929 set_stationary_playhead (tact->get_active());
3934 Editor::set_stationary_playhead (bool yn)
3936 if (_stationary_playhead != yn) {
3937 if ((_stationary_playhead = yn) == true) {
3938 /* catch up -- FIXME need a 3.0 equivalent of this 2.X call */
3939 // update_current_screen ();
3946 Editor::playlist_selector () const
3948 return *_playlist_selector;
3952 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
3954 if (paste_count == 0) {
3955 /* don't bother calculating an offset that will be zero anyway */
3959 /* calculate basic unsnapped multi-paste offset */
3960 samplecnt_t offset = paste_count * duration;
3962 /* snap offset so pos + offset is aligned to the grid */
3963 MusicSample offset_pos (pos + offset, 0);
3964 snap_to(offset_pos, RoundUpMaybe);
3965 offset = offset_pos.sample - pos;
3971 Editor::get_grid_beat_divisions(samplepos_t position)
3973 switch (_grid_type) {
3974 case GridTypeBeatDiv32: return 32;
3975 case GridTypeBeatDiv28: return 28;
3976 case GridTypeBeatDiv24: return 24;
3977 case GridTypeBeatDiv20: return 20;
3978 case GridTypeBeatDiv16: return 16;
3979 case GridTypeBeatDiv14: return 14;
3980 case GridTypeBeatDiv12: return 12;
3981 case GridTypeBeatDiv10: return 10;
3982 case GridTypeBeatDiv8: return 8;
3983 case GridTypeBeatDiv7: return 7;
3984 case GridTypeBeatDiv6: return 6;
3985 case GridTypeBeatDiv5: return 5;
3986 case GridTypeBeatDiv4: return 4;
3987 case GridTypeBeatDiv3: return 3;
3988 case GridTypeBeatDiv2: return 2;
3990 case GridTypeNone: return 0;
3991 case GridTypeTimecode: return 0;
3992 case GridTypeMinSec: return 0;
3993 case GridTypeCDFrame: return 0;
3999 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4000 if the grid is non-musical, returns 0.
4001 if the grid is snapped to bars, returns -1.
4002 @param event_state the current keyboard modifier mask.
4005 Editor::get_grid_music_divisions (uint32_t event_state)
4007 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4011 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4015 switch (_grid_type) {
4016 case GridTypeBeatDiv32: return 32;
4017 case GridTypeBeatDiv28: return 28;
4018 case GridTypeBeatDiv24: return 24;
4019 case GridTypeBeatDiv20: return 20;
4020 case GridTypeBeatDiv16: return 16;
4021 case GridTypeBeatDiv14: return 14;
4022 case GridTypeBeatDiv12: return 12;
4023 case GridTypeBeatDiv10: return 10;
4024 case GridTypeBeatDiv8: return 8;
4025 case GridTypeBeatDiv7: return 7;
4026 case GridTypeBeatDiv6: return 6;
4027 case GridTypeBeatDiv5: return 5;
4028 case GridTypeBeatDiv4: return 4;
4029 case GridTypeBeatDiv3: return 3;
4030 case GridTypeBeatDiv2: return 2;
4031 case GridTypeBeat: return 1;
4032 case GridTypeBar : return -1;
4034 case GridTypeNone: return 0;
4035 case GridTypeTimecode: return 0;
4036 case GridTypeMinSec: return 0;
4037 case GridTypeCDFrame: return 0;
4043 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4047 const unsigned divisions = get_grid_beat_divisions(position);
4049 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4052 switch (_grid_type) {
4054 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4057 const Meter& m = _session->tempo_map().meter_at_sample (position);
4058 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4066 return Temporal::Beats();
4070 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4074 ret = nudge_clock->current_duration (pos);
4075 next = ret + 1; /* XXXX fix me */
4081 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4083 ArdourDialog dialog (_("Playlist Deletion"));
4084 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4085 "If it is kept, its audio files will not be cleaned.\n"
4086 "If it is deleted, audio files used by it alone will be cleaned."),
4089 dialog.set_position (WIN_POS_CENTER);
4090 dialog.get_vbox()->pack_start (label);
4094 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4095 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4096 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4097 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4098 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4100 /* by default gtk uses the left most button */
4101 keep->grab_focus ();
4103 switch (dialog.run ()) {
4105 /* keep this and all remaining ones */
4110 /* delete this and all others */
4114 case RESPONSE_ACCEPT:
4115 /* delete the playlist */
4119 case RESPONSE_REJECT:
4120 /* keep the playlist */
4132 Editor::audio_region_selection_covers (samplepos_t where)
4134 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4135 if ((*a)->region()->covers (where)) {
4144 Editor::prepare_for_cleanup ()
4146 cut_buffer->clear_regions ();
4147 cut_buffer->clear_playlists ();
4149 selection->clear_regions ();
4150 selection->clear_playlists ();
4152 _regions->suspend_redisplay ();
4156 Editor::finish_cleanup ()
4158 _regions->resume_redisplay ();
4162 Editor::transport_loop_location()
4165 return _session->locations()->auto_loop_location();
4172 Editor::transport_punch_location()
4175 return _session->locations()->auto_punch_location();
4182 Editor::control_layout_scroll (GdkEventScroll* ev)
4184 /* Just forward to the normal canvas scroll method. The coordinate
4185 systems are different but since the canvas is always larger than the
4186 track headers, and aligned with the trackview area, this will work.
4188 In the not too distant future this layout is going away anyway and
4189 headers will be on the canvas.
4191 return canvas_scroll_event (ev, false);
4195 Editor::session_state_saved (string)
4198 _snapshots->redisplay ();
4202 Editor::maximise_editing_space ()
4208 Gtk::Window* toplevel = current_toplevel();
4211 toplevel->fullscreen ();
4217 Editor::restore_editing_space ()
4223 Gtk::Window* toplevel = current_toplevel();
4226 toplevel->unfullscreen();
4232 * Make new playlists for a given track and also any others that belong
4233 * to the same active route group with the `select' property.
4238 Editor::new_playlists (TimeAxisView* v)
4240 begin_reversible_command (_("new playlists"));
4241 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4242 _session->playlists->get (playlists);
4243 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4244 commit_reversible_command ();
4248 * Use a copy of the current playlist for a given track and also any others that belong
4249 * to the same active route group with the `select' property.
4254 Editor::copy_playlists (TimeAxisView* v)
4256 begin_reversible_command (_("copy playlists"));
4257 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4258 _session->playlists->get (playlists);
4259 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4260 commit_reversible_command ();
4263 /** Clear the current playlist for a given track and also any others that belong
4264 * to the same active route group with the `select' property.
4269 Editor::clear_playlists (TimeAxisView* v)
4271 begin_reversible_command (_("clear playlists"));
4272 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4273 _session->playlists->get (playlists);
4274 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4275 commit_reversible_command ();
4279 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4281 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4285 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4287 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4291 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4293 atv.clear_playlist ();
4297 Editor::get_y_origin () const
4299 return vertical_adjustment.get_value ();
4302 /** Queue up a change to the viewport x origin.
4303 * @param sample New x origin.
4306 Editor::reset_x_origin (samplepos_t sample)
4308 pending_visual_change.add (VisualChange::TimeOrigin);
4309 pending_visual_change.time_origin = sample;
4310 ensure_visual_change_idle_handler ();
4314 Editor::reset_y_origin (double y)
4316 pending_visual_change.add (VisualChange::YOrigin);
4317 pending_visual_change.y_origin = y;
4318 ensure_visual_change_idle_handler ();
4322 Editor::reset_zoom (samplecnt_t spp)
4324 if (spp == samples_per_pixel) {
4328 pending_visual_change.add (VisualChange::ZoomLevel);
4329 pending_visual_change.samples_per_pixel = spp;
4330 ensure_visual_change_idle_handler ();
4334 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4336 reset_x_origin (sample);
4339 if (!no_save_visual) {
4340 undo_visual_stack.push_back (current_visual_state(false));
4344 Editor::VisualState::VisualState (bool with_tracks)
4345 : gui_state (with_tracks ? new GUIObjectState : 0)
4349 Editor::VisualState::~VisualState ()
4354 Editor::VisualState*
4355 Editor::current_visual_state (bool with_tracks)
4357 VisualState* vs = new VisualState (with_tracks);
4358 vs->y_position = vertical_adjustment.get_value();
4359 vs->samples_per_pixel = samples_per_pixel;
4360 vs->_leftmost_sample = _leftmost_sample;
4361 vs->zoom_focus = zoom_focus;
4364 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4371 Editor::undo_visual_state ()
4373 if (undo_visual_stack.empty()) {
4377 VisualState* vs = undo_visual_stack.back();
4378 undo_visual_stack.pop_back();
4381 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4384 use_visual_state (*vs);
4389 Editor::redo_visual_state ()
4391 if (redo_visual_stack.empty()) {
4395 VisualState* vs = redo_visual_stack.back();
4396 redo_visual_stack.pop_back();
4398 /* XXX: can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack? */
4399 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4402 use_visual_state (*vs);
4407 Editor::swap_visual_state ()
4409 if (undo_visual_stack.empty()) {
4410 redo_visual_state ();
4412 undo_visual_state ();
4417 Editor::use_visual_state (VisualState& vs)
4419 PBD::Unwinder<bool> nsv (no_save_visual, true);
4420 DisplaySuspender ds;
4422 vertical_adjustment.set_value (vs.y_position);
4424 set_zoom_focus (vs.zoom_focus);
4425 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4428 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4430 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4431 (*i)->clear_property_cache();
4432 (*i)->reset_visual_state ();
4436 _routes->update_visibility ();
4439 /** This is the core function that controls the zoom level of the canvas. It is called
4440 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4441 * @param spp new number of samples per pixel
4444 Editor::set_samples_per_pixel (samplecnt_t spp)
4450 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4451 const samplecnt_t lots_of_pixels = 4000;
4453 /* if the zoom level is greater than what you'd get trying to display 3
4454 * days of audio on a really big screen, then it's too big.
4457 if (spp * lots_of_pixels > three_days) {
4461 samples_per_pixel = spp;
4465 Editor::on_samples_per_pixel_changed ()
4467 bool const showing_time_selection = selection->time.length() > 0;
4469 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4470 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4471 (*i)->reshow_selection (selection->time);
4475 ZoomChanged (); /* EMIT_SIGNAL */
4477 ArdourCanvas::GtkCanvasViewport* c;
4479 c = get_track_canvas();
4481 c->canvas()->zoomed ();
4484 if (playhead_cursor) {
4485 playhead_cursor->set_position (playhead_cursor->current_sample ());
4488 refresh_location_display();
4489 _summary->set_overlays_dirty ();
4491 update_marker_labels ();
4497 Editor::playhead_cursor_sample () const
4499 return playhead_cursor->current_sample();
4503 Editor::queue_visual_videotimeline_update ()
4505 pending_visual_change.add (VisualChange::VideoTimeline);
4506 ensure_visual_change_idle_handler ();
4510 Editor::ensure_visual_change_idle_handler ()
4512 if (pending_visual_change.idle_handler_id < 0) {
4513 /* see comment in add_to_idle_resize above. */
4514 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4515 pending_visual_change.being_handled = false;
4520 Editor::_idle_visual_changer (void* arg)
4522 return static_cast<Editor*>(arg)->idle_visual_changer ();
4526 Editor::pre_render ()
4528 visual_change_queued = false;
4530 if (pending_visual_change.pending != 0) {
4531 ensure_visual_change_idle_handler();
4536 Editor::idle_visual_changer ()
4538 pending_visual_change.idle_handler_id = -1;
4540 if (pending_visual_change.pending == 0) {
4544 /* set_horizontal_position() below (and maybe other calls) call
4545 gtk_main_iteration(), so it's possible that a signal will be handled
4546 half-way through this method. If this signal wants an
4547 idle_visual_changer we must schedule another one after this one, so
4548 mark the idle_handler_id as -1 here to allow that. Also make a note
4549 that we are doing the visual change, so that changes in response to
4550 super-rapid-screen-update can be dropped if we are still processing
4554 if (visual_change_queued) {
4558 pending_visual_change.being_handled = true;
4560 VisualChange vc = pending_visual_change;
4562 pending_visual_change.pending = (VisualChange::Type) 0;
4564 visual_changer (vc);
4566 pending_visual_change.being_handled = false;
4568 visual_change_queued = true;
4570 return 0; /* this is always a one-shot call */
4574 Editor::visual_changer (const VisualChange& vc)
4577 * Changed first so the correct horizontal canvas position is calculated in
4578 * Editor::set_horizontal_position
4580 if (vc.pending & VisualChange::ZoomLevel) {
4581 set_samples_per_pixel (vc.samples_per_pixel);
4584 if (vc.pending & VisualChange::TimeOrigin) {
4585 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4586 set_horizontal_position (new_time_origin);
4589 if (vc.pending & VisualChange::YOrigin) {
4590 vertical_adjustment.set_value (vc.y_origin);
4594 * Now the canvas is in the final state before render the canvas items that
4595 * support the Item::prepare_for_render interface can calculate the correct
4596 * item to visible canvas intersection.
4598 if (vc.pending & VisualChange::ZoomLevel) {
4599 on_samples_per_pixel_changed ();
4601 compute_fixed_ruler_scale ();
4603 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4604 update_tempo_based_rulers ();
4607 if (!(vc.pending & VisualChange::ZoomLevel)) {
4608 /* If the canvas is not being zoomed then the canvas items will not change
4609 * and cause Item::prepare_for_render to be called so do it here manually.
4610 * Not ideal, but I can't think of a better solution atm.
4612 _track_canvas->prepare_for_render();
4615 /* If we are only scrolling vertically there is no need to update these */
4616 if (vc.pending != VisualChange::YOrigin) {
4617 update_fixed_rulers ();
4618 redisplay_grid (true);
4620 /* video frames & position need to be updated for zoom, horiz-scroll
4621 * and (explicitly) VisualChange::VideoTimeline.
4623 update_video_timeline();
4626 _summary->set_overlays_dirty ();
4629 struct EditorOrderTimeAxisSorter {
4630 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4631 return a->order () < b->order ();
4636 Editor::sort_track_selection (TrackViewList& sel)
4638 EditorOrderTimeAxisSorter cmp;
4643 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4646 samplepos_t where = 0;
4647 EditPoint ep = _edit_point;
4649 if (Profile->get_mixbus()) {
4650 if (ep == EditAtSelectedMarker) {
4651 ep = EditAtPlayhead;
4655 if (from_outside_canvas && (ep == EditAtMouse)) {
4656 ep = EditAtPlayhead;
4657 } else if (from_context_menu && (ep == EditAtMouse)) {
4658 return canvas_event_sample (&context_click_event, 0, 0);
4661 if (entered_marker) {
4662 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4663 return entered_marker->position();
4666 if ((ignore == EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4667 ep = EditAtSelectedMarker;
4670 if ((ignore == EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4671 ep = EditAtPlayhead;
4674 MusicSample snap_mf (0, 0);
4677 case EditAtPlayhead:
4678 if (_dragging_playhead) {
4679 /* NOTE: since the user is dragging with the mouse, this operation will implicitly be Snapped */
4680 where = playhead_cursor->current_sample();
4682 where = _session->audible_sample();
4684 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4687 case EditAtSelectedMarker:
4688 if (!selection->markers.empty()) {
4690 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4693 where = loc->start();
4697 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4705 if (!mouse_sample (where, ignored)) {
4706 /* XXX not right but what can we do ? */
4709 snap_mf.sample = where;
4711 where = snap_mf.sample;
4712 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4720 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4722 if (!_session) return;
4724 begin_reversible_command (cmd);
4728 if ((tll = transport_loop_location()) == 0) {
4729 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4730 XMLNode &before = _session->locations()->get_state();
4731 _session->locations()->add (loc, true);
4732 _session->set_auto_loop_location (loc);
4733 XMLNode &after = _session->locations()->get_state();
4734 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4736 XMLNode &before = tll->get_state();
4737 tll->set_hidden (false, this);
4738 tll->set (start, end);
4739 XMLNode &after = tll->get_state();
4740 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4743 commit_reversible_command ();
4747 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4749 if (!_session) return;
4751 begin_reversible_command (cmd);
4755 if ((tpl = transport_punch_location()) == 0) {
4756 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4757 XMLNode &before = _session->locations()->get_state();
4758 _session->locations()->add (loc, true);
4759 _session->set_auto_punch_location (loc);
4760 XMLNode &after = _session->locations()->get_state();
4761 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4763 XMLNode &before = tpl->get_state();
4764 tpl->set_hidden (false, this);
4765 tpl->set (start, end);
4766 XMLNode &after = tpl->get_state();
4767 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4770 commit_reversible_command ();
4773 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4774 * @param rs List to which found regions are added.
4775 * @param where Time to look at.
4776 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4779 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4781 const TrackViewList* tracks;
4784 tracks = &track_views;
4789 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4791 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4794 boost::shared_ptr<Track> tr;
4795 boost::shared_ptr<Playlist> pl;
4797 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4799 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4801 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4802 RegionView* rv = rtv->view()->find_view (*i);
4813 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4815 const TrackViewList* tracks;
4818 tracks = &track_views;
4823 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4824 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4826 boost::shared_ptr<Track> tr;
4827 boost::shared_ptr<Playlist> pl;
4829 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4831 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4833 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4835 RegionView* rv = rtv->view()->find_view (*i);
4846 /** Get regions using the following method:
4848 * Make a region list using:
4849 * (a) any selected regions
4850 * (b) the intersection of any selected tracks and the edit point(*)
4851 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4853 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4855 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4859 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4861 RegionSelection regions;
4863 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4864 regions.add (entered_regionview);
4866 regions = selection->regions;
4869 if (regions.empty()) {
4870 TrackViewList tracks = selection->tracks;
4872 if (!tracks.empty()) {
4873 /* no region selected or entered, but some selected tracks:
4874 * act on all regions on the selected tracks at the edit point
4876 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4877 get_regions_at(regions, where, tracks);
4884 /** Get regions using the following method:
4886 * Make a region list using:
4887 * (a) any selected regions
4888 * (b) the intersection of any selected tracks and the edit point(*)
4889 * (c) if neither exists, then whatever region is under the mouse
4891 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4893 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4896 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4898 RegionSelection regions;
4900 if (entered_regionview && selection->tracks.empty() && selection->regions.empty()) {
4901 regions.add (entered_regionview);
4903 regions = selection->regions;
4906 if (regions.empty()) {
4907 TrackViewList tracks = selection->tracks;
4909 if (!tracks.empty()) {
4910 /* no region selected or entered, but some selected tracks:
4911 * act on all regions on the selected tracks at the edit point
4913 get_regions_at(regions, pos, tracks);
4920 /** Start with regions that are selected, or the entered regionview if none are selected.
4921 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4922 * of the regions that we started with.
4926 Editor::get_regions_from_selection_and_entered () const
4928 RegionSelection regions = selection->regions;
4930 if (regions.empty() && entered_regionview) {
4931 regions.add (entered_regionview);
4938 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4940 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4941 RouteTimeAxisView* rtav;
4943 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4944 boost::shared_ptr<Playlist> pl;
4945 std::vector<boost::shared_ptr<Region> > results;
4946 boost::shared_ptr<Track> tr;
4948 if ((tr = rtav->track()) == 0) {
4953 if ((pl = (tr->playlist())) != 0) {
4954 boost::shared_ptr<Region> r = pl->region_by_id (id);
4956 RegionView* rv = rtav->view()->find_view (r);
4958 regions.push_back (rv);
4967 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4970 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4971 MidiTimeAxisView* mtav;
4973 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4975 mtav->get_per_region_note_selection (selection);
4982 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4984 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4986 RouteTimeAxisView* tatv;
4988 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4990 boost::shared_ptr<Playlist> pl;
4991 vector<boost::shared_ptr<Region> > results;
4993 boost::shared_ptr<Track> tr;
4995 if ((tr = tatv->track()) == 0) {
5000 if ((pl = (tr->playlist())) != 0) {
5001 if (src_comparison) {
5002 pl->get_source_equivalent_regions (region, results);
5004 pl->get_region_list_equivalent_regions (region, results);
5008 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5009 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5010 regions.push_back (marv);
5019 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5021 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5022 RouteTimeAxisView* tatv;
5023 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5024 if (!tatv->track()) {
5027 RegionView* marv = tatv->view()->find_view (region);
5037 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5039 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5040 RouteTimeAxisView* rtav;
5041 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5042 if (rtav->route() == route) {
5051 Editor::show_rhythm_ferret ()
5053 if (rhythm_ferret == 0) {
5054 rhythm_ferret = new RhythmFerret(*this);
5057 rhythm_ferret->set_session (_session);
5058 rhythm_ferret->show ();
5059 rhythm_ferret->present ();
5063 Editor::first_idle ()
5065 MessageDialog* dialog = 0;
5067 if (track_views.size() > 1) {
5068 Timers::TimerSuspender t;
5069 dialog = new MessageDialog (
5070 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5074 ARDOUR_UI::instance()->flush_pending (60);
5077 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5081 /* now that all regionviews should exist, setup region selection */
5085 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5086 /* this is cumulative: rs is NOT cleared each time */
5087 get_regionviews_by_id (*pr, rs);
5090 selection->set (rs);
5092 /* first idle adds route children (automation tracks), so we need to redisplay here */
5093 _routes->redisplay ();
5097 if (_session->undo_depth() == 0) {
5098 undo_action->set_sensitive(false);
5100 redo_action->set_sensitive(false);
5101 begin_selection_op_history ();
5107 Editor::_idle_resize (gpointer arg)
5109 return ((Editor*)arg)->idle_resize ();
5113 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5115 if (resize_idle_id < 0) {
5116 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5117 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5118 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5120 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5121 _pending_resize_amount = 0;
5124 /* make a note of the smallest resulting height, so that we can clamp the
5125 lower limit at TimeAxisView::hSmall */
5127 int32_t min_resulting = INT32_MAX;
5129 _pending_resize_amount += h;
5130 _pending_resize_view = view;
5132 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5134 if (selection->tracks.contains (_pending_resize_view)) {
5135 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5136 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5140 if (min_resulting < 0) {
5145 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5146 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5150 /** Handle pending resizing of tracks */
5152 Editor::idle_resize ()
5154 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5156 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5157 selection->tracks.contains (_pending_resize_view)) {
5159 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5160 if (*i != _pending_resize_view) {
5161 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5166 _pending_resize_amount = 0;
5167 _group_tabs->set_dirty ();
5168 resize_idle_id = -1;
5176 ENSURE_GUI_THREAD (*this, &Editor::located);
5179 playhead_cursor->set_position (_session->audible_sample ());
5180 if (_follow_playhead && !_pending_initial_locate) {
5181 reset_x_origin_to_follow_playhead ();
5185 _pending_locate_request = false;
5186 _pending_initial_locate = false;
5187 _last_update_time = 0;
5191 Editor::region_view_added (RegionView * rv)
5193 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5195 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5196 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5197 if (rv->region()->id () == (*rnote).first) {
5198 mrv->select_notes ((*rnote).second);
5199 selection->pending_midi_note_selection.erase(rnote);
5205 _summary->set_background_dirty ();
5207 mark_region_boundary_cache_dirty ();
5211 Editor::region_view_removed ()
5213 _summary->set_background_dirty ();
5215 mark_region_boundary_cache_dirty ();
5219 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5221 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5222 if ((*j)->stripable() == s) {
5231 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5233 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5234 if ((*j)->control() == c) {
5238 TimeAxisView::Children kids = (*j)->get_child_list ();
5240 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5241 if ((*k)->control() == c) {
5251 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5255 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5256 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5266 Editor::suspend_route_redisplay ()
5269 _routes->suspend_redisplay();
5274 Editor::resume_route_redisplay ()
5277 _routes->redisplay(); // queue redisplay
5278 _routes->resume_redisplay();
5283 Editor::add_vcas (VCAList& vlist)
5287 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5288 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5291 add_stripables (sl);
5295 Editor::add_routes (RouteList& rlist)
5299 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5303 add_stripables (sl);
5307 Editor::add_stripables (StripableList& sl)
5309 list<TimeAxisView*> new_views;
5310 boost::shared_ptr<VCA> v;
5311 boost::shared_ptr<Route> r;
5312 TrackViewList new_selection;
5313 bool from_scratch = (track_views.size() == 0);
5315 sl.sort (Stripable::Sorter());
5317 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5319 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5321 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5323 new_views.push_back (vtv);
5325 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5327 if (r->is_auditioner() || r->is_monitor()) {
5331 RouteTimeAxisView* rtv;
5332 DataType dt = r->input()->default_type();
5334 if (dt == ARDOUR::DataType::AUDIO) {
5335 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5337 } else if (dt == ARDOUR::DataType::MIDI) {
5338 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5341 throw unknown_type();
5344 new_views.push_back (rtv);
5345 track_views.push_back (rtv);
5346 new_selection.push_back (rtv);
5348 rtv->effective_gain_display ();
5350 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5351 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5355 if (new_views.size() > 0) {
5356 _routes->time_axis_views_added (new_views);
5357 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5360 /* note: !new_selection.empty() means that we got some routes rather
5364 if (!from_scratch && !new_selection.empty()) {
5365 selection->set (new_selection);
5366 begin_selection_op_history();
5369 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5370 show_editor_mixer (true);
5373 editor_list_button.set_sensitive (true);
5377 Editor::timeaxisview_deleted (TimeAxisView *tv)
5379 if (tv == entered_track) {
5383 if (_session && _session->deletion_in_progress()) {
5384 /* the situation is under control */
5388 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5390 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5392 _routes->route_removed (tv);
5394 TimeAxisView::Children c = tv->get_child_list ();
5395 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5396 if (entered_track == i->get()) {
5401 /* remove it from the list of track views */
5403 TrackViewList::iterator i;
5405 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5406 i = track_views.erase (i);
5409 /* update whatever the current mixer strip is displaying, if revelant */
5411 boost::shared_ptr<Route> route;
5414 route = rtav->route ();
5417 if (current_mixer_strip && current_mixer_strip->route() == route) {
5419 TimeAxisView* next_tv;
5421 if (track_views.empty()) {
5423 } else if (i == track_views.end()) {
5424 next_tv = track_views.front();
5429 // skip VCAs (cannot be selected, n/a in editor-mixer)
5430 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5431 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5432 next_tv = track_views.front();
5434 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5435 /* just in case: no master, only a VCA remains */
5441 set_selected_mixer_strip (*next_tv);
5443 /* make the editor mixer strip go away setting the
5444 * button to inactive (which also unticks the menu option)
5447 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5453 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5459 DisplaySuspender ds;
5460 PresentationInfo::ChangeSuspender cs;
5462 if (apply_to_selection) {
5463 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end();) {
5465 TrackSelection::iterator j = i;
5468 hide_track_in_display (*i, false);
5473 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5475 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5476 /* this will hide the mixer strip */
5477 set_selected_mixer_strip (*tv);
5480 _routes->hide_track_in_display (*tv);
5485 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5490 _routes->show_track_in_display (*tv);
5491 if (move_into_view) {
5492 ensure_time_axis_view_is_visible (*tv, false);
5497 Editor::sync_track_view_list_and_routes ()
5499 track_views = TrackViewList (_routes->views ());
5501 _summary->set_background_dirty();
5502 _group_tabs->set_dirty ();
5504 return false; // do not call again (until needed)
5508 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5510 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5515 /** Find a StripableTimeAxisView by the ID of its stripable */
5516 StripableTimeAxisView*
5517 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5519 StripableTimeAxisView* v;
5521 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5522 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5523 if(v->stripable()->id() == id) {
5533 Editor::fit_route_group (RouteGroup *g)
5535 TrackViewList ts = axis_views_from_routes (g->route_list ());
5540 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5542 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5545 _session->cancel_audition ();
5549 if (_session->is_auditioning()) {
5550 _session->cancel_audition ();
5551 if (r == last_audition_region) {
5556 _session->audition_region (r);
5557 last_audition_region = r;
5562 Editor::hide_a_region (boost::shared_ptr<Region> r)
5564 r->set_hidden (true);
5568 Editor::show_a_region (boost::shared_ptr<Region> r)
5570 r->set_hidden (false);
5574 Editor::audition_region_from_region_list ()
5576 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5580 Editor::hide_region_from_region_list ()
5582 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5586 Editor::show_region_in_region_list ()
5588 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5592 Editor::step_edit_status_change (bool yn)
5595 start_step_editing ();
5597 stop_step_editing ();
5602 Editor::start_step_editing ()
5604 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5608 Editor::stop_step_editing ()
5610 step_edit_connection.disconnect ();
5614 Editor::check_step_edit ()
5616 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5617 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5619 mtv->check_step_edit ();
5623 return true; // do it again, till we stop
5627 Editor::scroll_press (Direction dir)
5629 ++_scroll_callbacks;
5631 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5632 /* delay the first auto-repeat */
5638 scroll_backward (1);
5646 scroll_up_one_track ();
5650 scroll_down_one_track ();
5654 /* do hacky auto-repeat */
5655 if (!_scroll_connection.connected ()) {
5657 _scroll_connection = Glib::signal_timeout().connect (
5658 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5661 _scroll_callbacks = 0;
5668 Editor::scroll_release ()
5670 _scroll_connection.disconnect ();
5673 /** Queue a change for the Editor viewport x origin to follow the playhead */
5675 Editor::reset_x_origin_to_follow_playhead ()
5677 samplepos_t const sample = playhead_cursor->current_sample ();
5679 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5681 if (_session->transport_speed() < 0) {
5683 if (sample > (current_page_samples() / 2)) {
5684 center_screen (sample-(current_page_samples()/2));
5686 center_screen (current_page_samples()/2);
5693 if (sample < _leftmost_sample) {
5695 if (_session->transport_rolling()) {
5696 /* rolling; end up with the playhead at the right of the page */
5697 l = sample - current_page_samples ();
5699 /* not rolling: end up with the playhead 1/4 of the way along the page */
5700 l = sample - current_page_samples() / 4;
5704 if (_session->transport_rolling()) {
5705 /* rolling: end up with the playhead on the left of the page */
5708 /* not rolling: end up with the playhead 3/4 of the way along the page */
5709 l = sample - 3 * current_page_samples() / 4;
5717 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5723 Editor::super_rapid_screen_update ()
5725 if (!_session || !_session->engine().running()) {
5729 /* METERING / MIXER STRIPS */
5731 /* update track meters, if required */
5732 if (contents().is_mapped() && meters_running) {
5733 RouteTimeAxisView* rtv;
5734 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5735 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5736 rtv->fast_update ();
5741 /* and any current mixer strip */
5742 if (current_mixer_strip) {
5743 current_mixer_strip->fast_update ();
5746 bool latent_locate = false;
5747 samplepos_t sample = _session->audible_sample (&latent_locate);
5748 const int64_t now = g_get_monotonic_time ();
5751 if (_session->exporting ()) {
5752 /* freewheel/export may be faster or slower than transport_speed() / SR.
5753 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5755 _last_update_time = 0;
5758 if (!_session->transport_rolling ()) {
5759 /* Do not interpolate the playhead position; just set it */
5760 _last_update_time = 0;
5763 if (_last_update_time > 0) {
5764 /* interpolate and smoothen playhead position */
5765 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5766 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5767 err = sample - guess;
5769 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5770 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5773 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5775 err, _err_screen_engine);
5780 _err_screen_engine = 0;
5783 if (err > 8192 || latent_locate) {
5784 // in case of x-runs or freewheeling
5785 _last_update_time = 0;
5786 sample = _session->audible_sample ();
5788 _last_update_time = now;
5791 /* snapped cursor stuff (the snapped_cursor shows where an operation is going to occur) */
5793 MusicSample where (sample, 0);
5794 if (!UIConfiguration::instance().get_show_snapped_cursor()) {
5795 snapped_cursor->hide ();
5796 } else if (_edit_point == EditAtPlayhead && !_dragging_playhead) {
5797 /* EditAtPlayhead does not snap */
5798 } else if (_edit_point == EditAtSelectedMarker) {
5799 /* NOTE: I don't think EditAtSelectedMarker should snap. They are what they are.
5800 * however, the current editing code -does- snap so I'll draw it that way for now.
5802 if (!selection->markers.empty()) {
5803 MusicSample ms (selection->markers.front()->position(), 0);
5804 snap_to (ms); // should use snap_to_with_modifier?
5805 snapped_cursor->set_position (ms.sample);
5806 snapped_cursor->show ();
5808 } else if (mouse_sample (where.sample, ignored)) { // cursor is in the editing canvas. show it.
5809 snapped_cursor->show ();
5810 } else { // mouse is out of the editing canvas. hide the snapped_cursor
5811 snapped_cursor->hide ();
5814 /* There are a few reasons why we might not update the playhead / viewport stuff:
5816 * 1. we don't update things when there's a pending locate request, otherwise
5817 * when the editor requests a locate there is a chance that this method
5818 * will move the playhead before the locate request is processed, causing
5820 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5821 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5823 if (_pending_locate_request) {
5824 _last_update_time = 0;
5828 if (_dragging_playhead) {
5829 _last_update_time = 0;
5833 if (playhead_cursor->current_sample () == sample) {
5837 playhead_cursor->set_position (sample);
5839 if (_session->requested_return_sample() >= 0) {
5840 _last_update_time = 0;
5844 if (!_follow_playhead || pending_visual_change.being_handled) {
5845 /* We only do this if we aren't already
5846 * handling a visual change (ie if
5847 * pending_visual_change.being_handled is
5848 * false) so that these requests don't stack
5849 * up there are too many of them to handle in
5855 if (!_stationary_playhead) {
5856 reset_x_origin_to_follow_playhead ();
5858 samplepos_t const sample = playhead_cursor->current_sample ();
5859 double target = ((double)sample - (double)current_page_samples() / 2.0);
5860 if (target <= 0.0) {
5863 /* compare to EditorCursor::set_position() */
5864 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5865 double const new_pos = sample_to_pixel_unrounded (target);
5866 if (rint (new_pos) != rint (old_pos)) {
5867 reset_x_origin (pixel_to_sample (new_pos));
5874 Editor::session_going_away ()
5876 _have_idled = false;
5878 _session_connections.drop_connections ();
5880 super_rapid_screen_update_connection.disconnect ();
5882 selection->clear ();
5883 cut_buffer->clear ();
5885 clicked_regionview = 0;
5886 clicked_axisview = 0;
5887 clicked_routeview = 0;
5888 entered_regionview = 0;
5890 _last_update_time = 0;
5893 playhead_cursor->hide ();
5895 /* rip everything out of the list displays */
5899 _route_groups->clear ();
5901 /* do this first so that deleting a track doesn't reset cms to null
5902 and thus cause a leak.
5905 if (current_mixer_strip) {
5906 if (current_mixer_strip->get_parent() != 0) {
5907 global_hpacker.remove (*current_mixer_strip);
5909 delete current_mixer_strip;
5910 current_mixer_strip = 0;
5913 /* delete all trackviews */
5915 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5918 track_views.clear ();
5920 nudge_clock->set_session (0);
5922 editor_list_button.set_active(false);
5923 editor_list_button.set_sensitive(false);
5925 /* clear tempo/meter rulers */
5926 remove_metric_marks ();
5927 clear_marker_display ();
5933 stop_step_editing ();
5937 /* get rid of any existing editor mixer strip */
5939 WindowTitle title(Glib::get_application_name());
5940 title += _("Editor");
5942 own_window()->set_title (title.get_string());
5945 SessionHandlePtr::session_going_away ();
5949 Editor::trigger_script (int i)
5951 LuaInstance::instance()-> call_action (i);
5955 Editor::show_editor_list (bool yn)
5958 _editor_list_vbox.show ();
5960 _editor_list_vbox.hide ();
5965 Editor::change_region_layering_order (bool from_context_menu)
5967 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5969 if (!clicked_routeview) {
5970 if (layering_order_editor) {
5971 layering_order_editor->hide ();
5976 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5982 boost::shared_ptr<Playlist> pl = track->playlist();
5988 if (layering_order_editor == 0) {
5989 layering_order_editor = new RegionLayeringOrderEditor (*this);
5992 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5993 layering_order_editor->maybe_present ();
5997 Editor::update_region_layering_order_editor ()
5999 if (layering_order_editor && layering_order_editor->is_visible ()) {
6000 change_region_layering_order (true);
6005 Editor::setup_fade_images ()
6007 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6008 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6009 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6010 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6011 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6013 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6014 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6015 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6016 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6017 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6021 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6023 Editor::action_menu_item (std::string const & name)
6025 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6028 return *manage (a->create_menu_item ());
6032 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6034 EventBox* b = manage (new EventBox);
6035 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6036 Label* l = manage (new Label (name));
6040 _the_notebook.append_page (widget, *b);
6044 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6046 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6047 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6050 if (ev->type == GDK_2BUTTON_PRESS) {
6052 /* double-click on a notebook tab shrinks or expands the notebook */
6054 if (_notebook_shrunk) {
6055 if (pre_notebook_shrink_pane_width) {
6056 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6058 _notebook_shrunk = false;
6060 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6062 /* this expands the LHS of the edit pane to cover the notebook
6063 PAGE but leaves the tabs visible.
6065 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6066 _notebook_shrunk = true;
6074 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6076 using namespace Menu_Helpers;
6078 MenuList& items = _control_point_context_menu.items ();
6081 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6082 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6083 if (!can_remove_control_point (item)) {
6084 items.back().set_sensitive (false);
6087 _control_point_context_menu.popup (event->button.button, event->button.time);
6091 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6093 using namespace Menu_Helpers;
6095 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6100 /* We need to get the selection here and pass it to the operations, since
6101 popping up the menu will cause a region leave event which clears
6102 entered_regionview. */
6104 MidiRegionView& mrv = note->region_view();
6105 const RegionSelection rs = get_regions_from_selection_and_entered ();
6106 const uint32_t sel_size = mrv.selection_size ();
6108 MenuList& items = _note_context_menu.items();
6112 items.push_back(MenuElem(_("Delete"),
6113 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6116 items.push_back(MenuElem(_("Edit..."),
6117 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6118 if (sel_size != 1) {
6119 items.back().set_sensitive (false);
6122 items.push_back(MenuElem(_("Transpose..."),
6123 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6126 items.push_back(MenuElem(_("Legatize"),
6127 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6129 items.back().set_sensitive (false);
6132 items.push_back(MenuElem(_("Quantize..."),
6133 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6135 items.push_back(MenuElem(_("Remove Overlap"),
6136 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6138 items.back().set_sensitive (false);
6141 items.push_back(MenuElem(_("Transform..."),
6142 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6144 _note_context_menu.popup (event->button.button, event->button.time);
6148 Editor::zoom_vertical_modifier_released()
6150 _stepping_axis_view = 0;
6154 Editor::ui_parameter_changed (string parameter)
6156 if (parameter == "icon-set") {
6157 while (!_cursor_stack.empty()) {
6158 _cursor_stack.pop_back();
6160 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6161 _cursor_stack.push_back(_cursors->grabber);
6162 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6163 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6165 } else if (parameter == "draggable-playhead") {
6166 if (_verbose_cursor) {
6167 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6169 } else if (parameter == "use-note-bars-for-velocity") {
6170 ArdourCanvas::Note::set_show_velocity_bars (UIConfiguration::instance().get_use_note_bars_for_velocity());
6171 _track_canvas->request_redraw (_track_canvas->visible_area());
6176 Editor::use_own_window (bool and_fill_it)
6178 bool new_window = !own_window();
6180 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6182 if (win && new_window) {
6183 win->set_name ("EditorWindow");
6185 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6187 // win->signal_realize().connect (*this, &Editor::on_realize);
6188 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6189 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6190 win->set_data ("ardour-bindings", bindings);
6195 DisplaySuspender ds;
6196 contents().show_all ();
6198 /* XXX: this is a bit unfortunate; it would probably
6199 be nicer if we could just call show () above rather
6200 than needing the show_all ()
6203 /* re-hide stuff if necessary */
6204 editor_list_button_toggled ();
6205 parameter_changed ("show-summary");
6206 parameter_changed ("show-group-tabs");
6207 parameter_changed ("show-zoom-tools");
6209 /* now reset all audio_time_axis heights, because widgets might need
6215 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6216 tv = (static_cast<TimeAxisView*>(*i));
6217 tv->reset_height ();
6220 if (current_mixer_strip) {
6221 current_mixer_strip->hide_things ();
6222 current_mixer_strip->parameter_changed ("mixer-element-visibility");