2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/gtk_ui.h"
61 #include "gtkmm2ext/keyboard.h"
62 #include "gtkmm2ext/utils.h"
63 #include "gtkmm2ext/window_title.h"
64 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
66 #include "ardour/analysis_graph.h"
67 #include "ardour/audio_track.h"
68 #include "ardour/audioengine.h"
69 #include "ardour/audioregion.h"
70 #include "ardour/lmath.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route.h"
74 #include "ardour/route_group.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/tempo.h"
77 #include "ardour/utils.h"
78 #include "ardour/vca_manager.h"
79 #include "ardour/vca.h"
81 #include "canvas/debug.h"
82 #include "canvas/text.h"
84 #include "widgets/ardour_spacer.h"
85 #include "widgets/eventboxext.h"
86 #include "widgets/tooltips.h"
88 #include "control_protocol/control_protocol.h"
91 #include "analysis_window.h"
92 #include "audio_clock.h"
93 #include "audio_region_view.h"
94 #include "audio_streamview.h"
95 #include "audio_time_axis.h"
96 #include "automation_time_axis.h"
97 #include "bundle_manager.h"
98 #include "crossfade_edit.h"
101 #include "editing_convert.h"
103 #include "editor_cursors.h"
104 #include "editor_drag.h"
105 #include "editor_group_tabs.h"
106 #include "editor_locations.h"
107 #include "editor_regions.h"
108 #include "editor_route_groups.h"
109 #include "editor_routes.h"
110 #include "editor_snapshots.h"
111 #include "editor_summary.h"
112 #include "enums_convert.h"
113 #include "export_report.h"
114 #include "global_port_matrix.h"
115 #include "gui_object.h"
116 #include "gui_thread.h"
117 #include "keyboard.h"
118 #include "luainstance.h"
120 #include "midi_region_view.h"
121 #include "midi_time_axis.h"
122 #include "mixer_strip.h"
123 #include "mixer_ui.h"
124 #include "mouse_cursors.h"
125 #include "note_base.h"
126 #include "playlist_selector.h"
127 #include "public_editor.h"
128 #include "quantize_dialog.h"
129 #include "region_layering_order_editor.h"
130 #include "rgb_macros.h"
131 #include "rhythm_ferret.h"
132 #include "route_sorter.h"
133 #include "selection.h"
134 #include "simple_progress_dialog.h"
136 #include "grid_lines.h"
137 #include "time_axis_view.h"
138 #include "time_info_box.h"
140 #include "ui_config.h"
142 #include "vca_time_axis.h"
143 #include "verbose_cursor.h"
145 #include "pbd/i18n.h"
148 using namespace ARDOUR;
149 using namespace ArdourWidgets;
150 using namespace ARDOUR_UI_UTILS;
153 using namespace Glib;
154 using namespace Gtkmm2ext;
155 using namespace Editing;
157 using PBD::internationalize;
159 using Gtkmm2ext::Keyboard;
161 double Editor::timebar_height = 15.0;
163 static const gchar *_grid_type_strings[] = {
172 N_("1/3 (8th triplet)"), // or "1/12" ?
173 N_("1/6 (16th triplet)"),
174 N_("1/12 (32nd triplet)"),
175 N_("1/24 (64th triplet)"),
176 N_("1/5 (8th quintuplet)"),
177 N_("1/10 (16th quintuplet)"),
178 N_("1/20 (32nd quintuplet)"),
179 N_("1/7 (8th septuplet)"),
180 N_("1/14 (16th septuplet)"),
181 N_("1/28 (32nd septuplet)"),
188 static const gchar *_edit_point_strings[] = {
195 static const gchar *_edit_mode_strings[] = {
203 static const gchar *_zoom_focus_strings[] = {
213 #ifdef USE_RUBBERBAND
214 static const gchar *_rb_opt_strings[] = {
217 N_("Balanced multitimbral mixture"),
218 N_("Unpitched percussion with stable notes"),
219 N_("Crisp monophonic instrumental"),
220 N_("Unpitched solo percussion"),
221 N_("Resample without preserving pitch"),
226 //Robin says: this should be odd to accomodate cairo drawing offset ( width/2 rounds up to pixel boundary )
228 #define COMBO_TRIANGLE_WIDTH 19 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
230 #define COMBO_TRIANGLE_WIDTH 11 // as-measured for win/linux.
234 : PublicEditor (global_hpacker)
235 , editor_mixer_strip_width (Wide)
236 , constructed (false)
237 , _playlist_selector (0)
239 , no_save_visual (false)
240 , _leftmost_sample (0)
241 , samples_per_pixel (2048)
242 , zoom_focus (ZoomFocusPlayhead)
243 , mouse_mode (MouseObject)
244 , pre_internal_grid_type (GridTypeBeat)
245 , pre_internal_snap_mode (SnapOff)
246 , internal_grid_type (GridTypeBeat)
247 , internal_snap_mode (SnapOff)
248 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
249 , _notebook_shrunk (false)
250 , location_marker_color (0)
251 , location_range_color (0)
252 , location_loop_color (0)
253 , location_punch_color (0)
254 , location_cd_marker_color (0)
256 , _show_marker_lines (false)
257 , clicked_axisview (0)
258 , clicked_routeview (0)
259 , clicked_regionview (0)
260 , clicked_selection (0)
261 , clicked_control_point (0)
262 , button_release_can_deselect (true)
263 , _mouse_changed_selection (false)
264 , region_edit_menu_split_item (0)
265 , region_edit_menu_split_multichannel_item (0)
266 , track_region_edit_playlist_menu (0)
267 , track_edit_playlist_submenu (0)
268 , track_selection_edit_playlist_submenu (0)
269 , _popup_region_menu_item (0)
271 , _track_canvas_viewport (0)
272 , within_track_canvas (false)
273 , _verbose_cursor (0)
277 , range_marker_group (0)
278 , transport_marker_group (0)
279 , cd_marker_group (0)
280 , _time_markers_group (0)
281 , hv_scroll_group (0)
283 , cursor_scroll_group (0)
284 , no_scroll_group (0)
285 , _trackview_group (0)
286 , _drag_motion_group (0)
287 , _canvas_drop_zone (0)
288 , no_ruler_shown_update (false)
289 , ruler_grabbed_widget (0)
291 , minsec_mark_interval (0)
292 , minsec_mark_modulo (0)
294 , timecode_ruler_scale (timecode_show_many_hours)
295 , timecode_mark_modulo (0)
296 , timecode_nmarks (0)
297 , _samples_ruler_interval (0)
298 , bbt_ruler_scale (bbt_show_many)
301 , bbt_bar_helper_on (0)
302 , bbt_accent_modulo (0)
307 , visible_timebars (0)
308 , editor_ruler_menu (0)
312 , range_marker_bar (0)
313 , transport_marker_bar (0)
315 , minsec_label (_("Mins:Secs"))
316 , bbt_label (_("Bars:Beats"))
317 , timecode_label (_("Timecode"))
318 , samples_label (_("Samples"))
319 , tempo_label (_("Tempo"))
320 , meter_label (_("Meter"))
321 , mark_label (_("Location Markers"))
322 , range_mark_label (_("Range Markers"))
323 , transport_mark_label (_("Loop/Punch Ranges"))
324 , cd_mark_label (_("CD Markers"))
325 , videotl_label (_("Video Timeline"))
328 , playhead_cursor (0)
329 , _region_boundary_cache_dirty (true)
330 , edit_packer (4, 4, true)
331 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
332 , horizontal_adjustment (0.0, 0.0, 1e16)
333 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
334 , controls_layout (unused_adjustment, vertical_adjustment)
335 , _scroll_callbacks (0)
336 , _visible_canvas_width (0)
337 , _visible_canvas_height (0)
338 , _full_canvas_height (0)
339 , edit_controls_left_menu (0)
340 , edit_controls_right_menu (0)
341 , visual_change_queued(false)
342 , _last_update_time (0)
343 , _err_screen_engine (0)
344 , cut_buffer_start (0)
345 , cut_buffer_length (0)
346 , button_bindings (0)
347 , last_paste_pos (-1)
350 , current_interthread_info (0)
351 , analysis_window (0)
352 , select_new_marker (false)
354 , scrubbing_direction (0)
355 , scrub_reversals (0)
356 , scrub_reverse_distance (0)
357 , have_pending_keyboard_selection (false)
358 , pending_keyboard_selection_start (0)
359 , _grid_type (GridTypeBeat)
360 , _snap_mode (SnapOff)
361 , ignore_gui_changes (false)
362 , _drags (new DragManager (this))
364 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
365 , _dragging_playhead (false)
366 , _dragging_edit_point (false)
367 , _follow_playhead (true)
368 , _stationary_playhead (false)
371 , global_rect_group (0)
372 , time_line_group (0)
373 , tempo_marker_menu (0)
374 , meter_marker_menu (0)
376 , range_marker_menu (0)
377 , transport_marker_menu (0)
378 , new_transport_marker_menu (0)
380 , marker_menu_item (0)
381 , bbt_beat_subdivision (4)
382 , _visible_track_count (-1)
383 , toolbar_selection_clock_table (2,3)
384 , automation_mode_button (_("mode"))
385 , selection (new Selection (this, true))
386 , cut_buffer (new Selection (this, false))
387 , _selection_memento (new SelectionMemento())
388 , _all_region_actions_sensitized (false)
389 , _ignore_region_action (false)
390 , _last_region_menu_was_main (false)
391 , _track_selection_change_without_scroll (false)
392 , _editor_track_selection_change_without_scroll (false)
393 , cd_marker_bar_drag_rect (0)
394 , range_bar_drag_rect (0)
395 , transport_bar_drag_rect (0)
396 , transport_bar_range_rect (0)
397 , transport_bar_preroll_rect (0)
398 , transport_bar_postroll_rect (0)
399 , transport_loop_range_rect (0)
400 , transport_punch_range_rect (0)
401 , transport_punchin_line (0)
402 , transport_punchout_line (0)
403 , transport_preroll_rect (0)
404 , transport_postroll_rect (0)
406 , rubberband_rect (0)
412 , autoscroll_horizontal_allowed (false)
413 , autoscroll_vertical_allowed (false)
415 , autoscroll_widget (0)
416 , show_gain_after_trim (false)
417 , selection_op_cmd_depth (0)
418 , selection_op_history_it (0)
419 , no_save_instant (false)
421 , current_mixer_strip (0)
422 , show_editor_mixer_when_tracks_arrive (false)
423 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
424 , current_stepping_trackview (0)
425 , last_track_height_step_timestamp (0)
427 , entered_regionview (0)
428 , clear_entered_track (false)
429 , _edit_point (EditAtMouse)
430 , meters_running (false)
432 , _have_idled (false)
433 , resize_idle_id (-1)
434 , _pending_resize_amount (0)
435 , _pending_resize_view (0)
436 , _pending_locate_request (false)
437 , _pending_initial_locate (false)
441 , layering_order_editor (0)
442 , _last_cut_copy_source_track (0)
443 , _region_selection_change_updates_region_list (true)
445 , _following_mixer_selection (false)
446 , _control_point_toggled_on_press (false)
447 , _stepping_axis_view (0)
448 , quantize_dialog (0)
449 , _main_menu_disabler (0)
450 , myactions (X_("editor"))
452 /* we are a singleton */
454 PublicEditor::_instance = this;
458 last_event_time.tv_sec = 0;
459 last_event_time.tv_usec = 0;
461 selection_op_history.clear();
464 grid_type_strings = I18N (_grid_type_strings);
465 zoom_focus_strings = I18N (_zoom_focus_strings);
466 edit_mode_strings = I18N (_edit_mode_strings);
467 edit_point_strings = I18N (_edit_point_strings);
468 #ifdef USE_RUBBERBAND
469 rb_opt_strings = I18N (_rb_opt_strings);
473 build_edit_mode_menu();
474 build_zoom_focus_menu();
475 build_track_count_menu();
476 build_grid_type_menu();
477 build_edit_point_menu();
479 location_marker_color = UIConfiguration::instance().color ("location marker");
480 location_range_color = UIConfiguration::instance().color ("location range");
481 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
482 location_loop_color = UIConfiguration::instance().color ("location loop");
483 location_punch_color = UIConfiguration::instance().color ("location punch");
485 timebar_height = std::max (12., ceil (15. * UIConfiguration::instance().get_ui_scale()));
487 TimeAxisView::setup_sizes ();
488 ArdourMarker::setup_sizes (timebar_height);
489 TempoCurve::setup_sizes (timebar_height);
491 bbt_label.set_name ("EditorRulerLabel");
492 bbt_label.set_size_request (-1, (int)timebar_height);
493 bbt_label.set_alignment (1.0, 0.5);
494 bbt_label.set_padding (5,0);
496 bbt_label.set_no_show_all();
497 minsec_label.set_name ("EditorRulerLabel");
498 minsec_label.set_size_request (-1, (int)timebar_height);
499 minsec_label.set_alignment (1.0, 0.5);
500 minsec_label.set_padding (5,0);
501 minsec_label.hide ();
502 minsec_label.set_no_show_all();
503 timecode_label.set_name ("EditorRulerLabel");
504 timecode_label.set_size_request (-1, (int)timebar_height);
505 timecode_label.set_alignment (1.0, 0.5);
506 timecode_label.set_padding (5,0);
507 timecode_label.hide ();
508 timecode_label.set_no_show_all();
509 samples_label.set_name ("EditorRulerLabel");
510 samples_label.set_size_request (-1, (int)timebar_height);
511 samples_label.set_alignment (1.0, 0.5);
512 samples_label.set_padding (5,0);
513 samples_label.hide ();
514 samples_label.set_no_show_all();
516 tempo_label.set_name ("EditorRulerLabel");
517 tempo_label.set_size_request (-1, (int)timebar_height);
518 tempo_label.set_alignment (1.0, 0.5);
519 tempo_label.set_padding (5,0);
521 tempo_label.set_no_show_all();
523 meter_label.set_name ("EditorRulerLabel");
524 meter_label.set_size_request (-1, (int)timebar_height);
525 meter_label.set_alignment (1.0, 0.5);
526 meter_label.set_padding (5,0);
528 meter_label.set_no_show_all();
530 if (Profile->get_trx()) {
531 mark_label.set_text (_("Markers"));
533 mark_label.set_name ("EditorRulerLabel");
534 mark_label.set_size_request (-1, (int)timebar_height);
535 mark_label.set_alignment (1.0, 0.5);
536 mark_label.set_padding (5,0);
538 mark_label.set_no_show_all();
540 cd_mark_label.set_name ("EditorRulerLabel");
541 cd_mark_label.set_size_request (-1, (int)timebar_height);
542 cd_mark_label.set_alignment (1.0, 0.5);
543 cd_mark_label.set_padding (5,0);
544 cd_mark_label.hide();
545 cd_mark_label.set_no_show_all();
547 videotl_bar_height = 4;
548 videotl_label.set_name ("EditorRulerLabel");
549 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
550 videotl_label.set_alignment (1.0, 0.5);
551 videotl_label.set_padding (5,0);
552 videotl_label.hide();
553 videotl_label.set_no_show_all();
555 range_mark_label.set_name ("EditorRulerLabel");
556 range_mark_label.set_size_request (-1, (int)timebar_height);
557 range_mark_label.set_alignment (1.0, 0.5);
558 range_mark_label.set_padding (5,0);
559 range_mark_label.hide();
560 range_mark_label.set_no_show_all();
562 transport_mark_label.set_name ("EditorRulerLabel");
563 transport_mark_label.set_size_request (-1, (int)timebar_height);
564 transport_mark_label.set_alignment (1.0, 0.5);
565 transport_mark_label.set_padding (5,0);
566 transport_mark_label.hide();
567 transport_mark_label.set_no_show_all();
569 initialize_canvas ();
571 CairoWidget::set_focus_handler (sigc::mem_fun (ARDOUR_UI::instance(), &ARDOUR_UI::reset_focus));
573 _summary = new EditorSummary (this);
575 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
576 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
578 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
580 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
581 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
583 edit_controls_vbox.set_spacing (0);
584 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
585 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
587 HBox* h = manage (new HBox);
588 _group_tabs = new EditorGroupTabs (this);
589 if (!ARDOUR::Profile->get_trx()) {
590 h->pack_start (*_group_tabs, PACK_SHRINK);
592 h->pack_start (edit_controls_vbox);
593 controls_layout.add (*h);
595 controls_layout.set_name ("EditControlsBase");
596 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
597 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
598 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
600 _cursors = new MouseCursors;
601 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
602 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
604 /* Push default cursor to ever-present bottom of cursor stack. */
605 push_canvas_cursor(_cursors->grabber);
607 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
609 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
610 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
611 pad_line_1->set_outline_color (0xFF0000FF);
617 edit_packer.set_col_spacings (0);
618 edit_packer.set_row_spacings (0);
619 edit_packer.set_homogeneous (false);
620 edit_packer.set_border_width (0);
621 edit_packer.set_name ("EditorWindow");
623 time_bars_event_box.add (time_bars_vbox);
624 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
625 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
627 ArdourWidgets::ArdourDropShadow *axis_view_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
628 axis_view_shadow->set_size_request( 4, -1 );
629 axis_view_shadow->set_name("EditorWindow");
630 axis_view_shadow->show();
632 edit_packer.attach (*axis_view_shadow, 0, 1, 0, 2, FILL, FILL|EXPAND, 0, 0);
634 /* labels for the time bars */
635 edit_packer.attach (time_bars_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
637 edit_packer.attach (controls_layout, 1, 2, 1, 2, FILL, FILL|EXPAND, 0, 0);
639 edit_packer.attach (*_track_canvas_viewport, 2, 3, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
641 bottom_hbox.set_border_width (2);
642 bottom_hbox.set_spacing (3);
644 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
646 _route_groups = new EditorRouteGroups (this);
647 _routes = new EditorRoutes (this);
648 _regions = new EditorRegions (this);
649 _snapshots = new EditorSnapshots (this);
650 _locations = new EditorLocations (this);
651 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
653 /* these are static location signals */
655 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
656 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
657 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
659 add_notebook_page (_("Regions"), _regions->widget ());
660 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
661 add_notebook_page (_("Snapshots"), _snapshots->widget ());
662 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
663 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
665 _the_notebook.set_show_tabs (true);
666 _the_notebook.set_scrollable (true);
667 _the_notebook.popup_disable ();
668 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
669 _the_notebook.show_all ();
671 _notebook_shrunk = false;
674 /* Pick up some settings we need to cache, early */
676 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
679 settings->get_property ("notebook-shrunk", _notebook_shrunk);
682 editor_summary_pane.set_check_divider_position (true);
683 editor_summary_pane.add (edit_packer);
685 Button* summary_arrow_left = manage (new Button);
686 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
687 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
688 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
690 Button* summary_arrow_right = manage (new Button);
691 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
692 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
693 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
695 VBox* summary_arrows_left = manage (new VBox);
696 summary_arrows_left->pack_start (*summary_arrow_left);
698 VBox* summary_arrows_right = manage (new VBox);
699 summary_arrows_right->pack_start (*summary_arrow_right);
701 Frame* summary_sample = manage (new Frame);
702 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
704 summary_sample->add (*_summary);
705 summary_sample->show ();
707 _summary_hbox.pack_start (*summary_arrows_left, false, false);
708 _summary_hbox.pack_start (*summary_sample, true, true);
709 _summary_hbox.pack_start (*summary_arrows_right, false, false);
711 if (!ARDOUR::Profile->get_trx()) {
712 editor_summary_pane.add (_summary_hbox);
715 edit_pane.set_check_divider_position (true);
716 edit_pane.add (editor_summary_pane);
717 if (!ARDOUR::Profile->get_trx()) {
718 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
719 _editor_list_vbox.pack_start (_the_notebook);
720 edit_pane.add (_editor_list_vbox);
721 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
724 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
725 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
728 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
729 /* initial allocation is 90% to canvas, 10% to notebook */
732 edit_pane.set_divider (0, fract);
734 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
735 /* initial allocation is 90% to canvas, 10% to summary */
738 editor_summary_pane.set_divider (0, fract);
740 global_vpacker.set_spacing (0);
741 global_vpacker.set_border_width (0);
743 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
745 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
746 ebox->set_name("EditorWindow");
747 ebox->add (ebox_hpacker);
749 Gtk::EventBox* epane_box = manage (new EventBoxExt); //a themeable box
750 epane_box->set_name("EditorWindow");
751 epane_box->add (edit_pane);
753 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box
754 epane_box2->set_name("EditorWindow");
755 epane_box2->add (global_vpacker);
757 ArdourWidgets::ArdourDropShadow *toolbar_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
758 toolbar_shadow->set_size_request( -1, 4 );
759 toolbar_shadow->set_mode(ArdourWidgets::ArdourDropShadow::DropShadowBoth);
760 toolbar_shadow->set_name("EditorWindow");
761 toolbar_shadow->show();
763 global_vpacker.pack_start (*toolbar_shadow, false, false);
764 global_vpacker.pack_start (*ebox, false, false);
765 global_vpacker.pack_start (*epane_box, true, true);
766 global_hpacker.pack_start (*epane_box2, true, true);
768 /* need to show the "contents" widget so that notebook will show if tab is switched to
771 global_hpacker.show ();
775 /* register actions now so that set_state() can find them and set toggles/checks etc */
782 _playlist_selector = new PlaylistSelector();
783 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
785 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
789 nudge_forward_button.set_name ("nudge button");
790 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
792 nudge_backward_button.set_name ("nudge button");
793 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
795 fade_context_menu.set_name ("ArdourContextMenu");
797 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
799 /* allow external control surfaces/protocols to do various things */
801 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
802 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
803 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
804 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
805 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
806 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
807 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
808 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
809 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
810 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
811 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
812 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
813 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
814 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
816 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
817 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
818 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
819 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
820 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
822 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
826 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
828 /* problematic: has to return a value and thus cannot be x-thread */
830 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
832 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
833 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
835 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
837 _ignore_region_action = false;
838 _last_region_menu_was_main = false;
839 _popup_region_menu_item = 0;
841 _show_marker_lines = false;
843 /* Button bindings */
845 button_bindings = new Bindings ("editor-mouse");
847 XMLNode* node = button_settings();
849 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
850 button_bindings->load_operation (**i);
856 /* grab current parameter state */
857 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
858 UIConfiguration::instance().map_parameters (pc);
860 setup_fade_images ();
862 set_grid_to (GridTypeNone);
869 delete button_bindings;
871 delete _route_groups;
872 delete _track_canvas_viewport;
875 delete _verbose_cursor;
876 delete quantize_dialog;
882 delete _playlist_selector;
883 delete _time_info_box;
888 LuaInstance::destroy_instance ();
890 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
893 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
896 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
902 Editor::button_settings () const
904 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
905 XMLNode* node = find_named_node (*settings, X_("Buttons"));
908 node = new XMLNode (X_("Buttons"));
915 Editor::get_smart_mode () const
917 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
921 Editor::catch_vanishing_regionview (RegionView *rv)
923 /* note: the selection will take care of the vanishing
924 audioregionview by itself.
927 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
931 if (clicked_regionview == rv) {
932 clicked_regionview = 0;
935 if (entered_regionview == rv) {
936 set_entered_regionview (0);
939 if (!_all_region_actions_sensitized) {
940 sensitize_all_region_actions (true);
945 Editor::set_entered_regionview (RegionView* rv)
947 if (rv == entered_regionview) {
951 if (entered_regionview) {
952 entered_regionview->exited ();
955 entered_regionview = rv;
957 if (entered_regionview != 0) {
958 entered_regionview->entered ();
961 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
962 /* This RegionView entry might have changed what region actions
963 are allowed, so sensitize them all in case a key is pressed.
965 sensitize_all_region_actions (true);
970 Editor::set_entered_track (TimeAxisView* tav)
973 entered_track->exited ();
979 entered_track->entered ();
984 Editor::instant_save ()
986 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
991 _session->add_instant_xml(get_state());
993 Config->add_instant_xml(get_state());
998 Editor::control_vertical_zoom_in_all ()
1000 tav_zoom_smooth (false, true);
1004 Editor::control_vertical_zoom_out_all ()
1006 tav_zoom_smooth (true, true);
1010 Editor::control_vertical_zoom_in_selected ()
1012 tav_zoom_smooth (false, false);
1016 Editor::control_vertical_zoom_out_selected ()
1018 tav_zoom_smooth (true, false);
1022 Editor::control_view (uint32_t view)
1024 goto_visual_state (view);
1028 Editor::control_unselect ()
1030 selection->clear_tracks ();
1034 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1036 TimeAxisView* tav = time_axis_view_from_stripable (s);
1040 case Selection::Add:
1041 selection->add (tav);
1043 case Selection::Toggle:
1044 selection->toggle (tav);
1046 case Selection::Extend:
1048 case Selection::Set:
1049 selection->set (tav);
1053 selection->clear_tracks ();
1058 Editor::control_step_tracks_up ()
1060 scroll_tracks_up_line ();
1064 Editor::control_step_tracks_down ()
1066 scroll_tracks_down_line ();
1070 Editor::control_scroll (float fraction)
1072 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1078 double step = fraction * current_page_samples();
1081 _control_scroll_target is an optional<T>
1083 it acts like a pointer to an samplepos_t, with
1084 a operator conversion to boolean to check
1085 that it has a value could possibly use
1086 playhead_cursor->current_sample to store the
1087 value and a boolean in the class to know
1088 when it's out of date
1091 if (!_control_scroll_target) {
1092 _control_scroll_target = _session->transport_sample();
1093 _dragging_playhead = true;
1096 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1097 *_control_scroll_target = 0;
1098 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1099 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1101 *_control_scroll_target += (samplepos_t) trunc (step);
1104 /* move visuals, we'll catch up with it later */
1106 playhead_cursor->set_position (*_control_scroll_target);
1107 UpdateAllTransportClocks (*_control_scroll_target);
1109 if (*_control_scroll_target > (current_page_samples() / 2)) {
1110 /* try to center PH in window */
1111 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1117 Now we do a timeout to actually bring the session to the right place
1118 according to the playhead. This is to avoid reading disk buffers on every
1119 call to control_scroll, which is driven by ScrollTimeline and therefore
1120 probably by a control surface wheel which can generate lots of events.
1122 /* cancel the existing timeout */
1124 control_scroll_connection.disconnect ();
1126 /* add the next timeout */
1128 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1132 Editor::deferred_control_scroll (samplepos_t /*target*/)
1134 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1135 // reset for next stream
1136 _control_scroll_target = boost::none;
1137 _dragging_playhead = false;
1142 Editor::access_action (const std::string& action_group, const std::string& action_item)
1148 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1151 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1159 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1161 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1165 Editor::on_realize ()
1169 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1170 start_lock_event_timing ();
1175 Editor::start_lock_event_timing ()
1177 /* check if we should lock the GUI every 30 seconds */
1179 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1183 Editor::generic_event_handler (GdkEvent* ev)
1186 case GDK_BUTTON_PRESS:
1187 case GDK_BUTTON_RELEASE:
1188 case GDK_MOTION_NOTIFY:
1190 case GDK_KEY_RELEASE:
1191 if (contents().is_mapped()) {
1192 gettimeofday (&last_event_time, 0);
1196 case GDK_LEAVE_NOTIFY:
1197 switch (ev->crossing.detail) {
1198 case GDK_NOTIFY_UNKNOWN:
1199 case GDK_NOTIFY_INFERIOR:
1200 case GDK_NOTIFY_ANCESTOR:
1202 case GDK_NOTIFY_VIRTUAL:
1203 case GDK_NOTIFY_NONLINEAR:
1204 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1205 /* leaving window, so reset focus, thus ending any and
1206 all text entry operations.
1208 ARDOUR_UI::instance()->reset_focus (&contents());
1221 Editor::lock_timeout_callback ()
1223 struct timeval now, delta;
1225 gettimeofday (&now, 0);
1227 timersub (&now, &last_event_time, &delta);
1229 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1231 /* don't call again. Returning false will effectively
1232 disconnect us from the timer callback.
1234 unlock() will call start_lock_event_timing() to get things
1244 Editor::map_position_change (samplepos_t sample)
1246 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1248 if (_session == 0) {
1252 if (_follow_playhead) {
1253 center_screen (sample);
1256 playhead_cursor->set_position (sample);
1260 Editor::center_screen (samplepos_t sample)
1262 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1264 /* if we're off the page, then scroll.
1267 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1268 center_screen_internal (sample, page);
1273 Editor::center_screen_internal (samplepos_t sample, float page)
1277 if (sample > page) {
1278 sample -= (samplepos_t) page;
1283 reset_x_origin (sample);
1288 Editor::update_title ()
1290 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1292 if (!own_window()) {
1297 bool dirty = _session->dirty();
1299 string session_name;
1301 if (_session->snap_name() != _session->name()) {
1302 session_name = _session->snap_name();
1304 session_name = _session->name();
1308 session_name = "*" + session_name;
1311 WindowTitle title(session_name);
1312 title += S_("Window|Editor");
1313 title += Glib::get_application_name();
1314 own_window()->set_title (title.get_string());
1316 /* ::session_going_away() will have taken care of it */
1321 Editor::set_session (Session *t)
1323 SessionHandlePtr::set_session (t);
1329 //initialize _leftmost_sample to the extents of the session
1330 //this prevents a bogus setting of leftmost = "0" if the summary view asks for the leftmost sample before the visible state has been loaded from instant.xml
1331 _leftmost_sample = session_gui_extents().first;
1333 _playlist_selector->set_session (_session);
1334 nudge_clock->set_session (_session);
1335 _summary->set_session (_session);
1336 _group_tabs->set_session (_session);
1337 _route_groups->set_session (_session);
1338 _regions->set_session (_session);
1339 _snapshots->set_session (_session);
1340 _routes->set_session (_session);
1341 _locations->set_session (_session);
1342 _time_info_box->set_session (_session);
1344 if (rhythm_ferret) {
1345 rhythm_ferret->set_session (_session);
1348 if (analysis_window) {
1349 analysis_window->set_session (_session);
1353 sfbrowser->set_session (_session);
1356 compute_fixed_ruler_scale ();
1358 /* Make sure we have auto loop and auto punch ranges */
1360 Location* loc = _session->locations()->auto_loop_location();
1362 loc->set_name (_("Loop"));
1365 loc = _session->locations()->auto_punch_location();
1368 loc->set_name (_("Punch"));
1371 refresh_location_display ();
1373 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1374 the selected Marker; this needs the LocationMarker list to be available.
1376 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1377 set_state (*node, Stateful::loading_state_version);
1379 /* catch up on selection state, etc. */
1382 sc.add (Properties::selected);
1383 presentation_info_changed (sc);
1385 /* catch up with the playhead */
1387 _session->request_locate (playhead_cursor->current_sample ());
1388 _pending_initial_locate = true;
1392 /* These signals can all be emitted by a non-GUI thread. Therefore the
1393 handlers for them must not attempt to directly interact with the GUI,
1394 but use PBD::Signal<T>::connect() which accepts an event loop
1395 ("context") where the handler will be asked to run.
1398 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1399 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1400 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1401 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1402 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1403 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1404 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1405 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1406 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1407 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1408 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1409 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1410 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1411 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1412 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1413 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1415 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1416 playhead_cursor->show ();
1418 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1419 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1420 snapped_cursor->show ();
1422 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1423 Config->map_parameters (pc);
1424 _session->config.map_parameters (pc);
1426 restore_ruler_visibility ();
1427 //tempo_map_changed (PropertyChange (0));
1428 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1430 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1431 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1434 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1435 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1438 /* register for undo history */
1439 _session->register_with_memento_command_factory(id(), this);
1440 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1442 LuaInstance::instance()->set_session(_session);
1444 start_updating_meters ();
1448 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1450 using namespace Menu_Helpers;
1452 void (Editor::*emf)(FadeShape);
1453 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1456 images = &_xfade_in_images;
1457 emf = &Editor::set_fade_in_shape;
1459 images = &_xfade_out_images;
1460 emf = &Editor::set_fade_out_shape;
1465 _("Linear (for highly correlated material)"),
1466 *(*images)[FadeLinear],
1467 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1471 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 _("Constant power"),
1476 *(*images)[FadeConstantPower],
1477 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *(*images)[FadeSymmetric],
1486 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 *(*images)[FadeSlow],
1496 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1499 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1504 *(*images)[FadeFast],
1505 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 /** Pop up a context menu for when the user clicks on a start crossfade */
1513 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1515 using namespace Menu_Helpers;
1516 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1521 MenuList& items (xfade_in_context_menu.items());
1524 if (arv->audio_region()->fade_in_active()) {
1525 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1527 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1530 items.push_back (SeparatorElem());
1531 fill_xfade_menu (items, true);
1533 xfade_in_context_menu.popup (button, time);
1536 /** Pop up a context menu for when the user clicks on an end crossfade */
1538 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1540 using namespace Menu_Helpers;
1541 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1546 MenuList& items (xfade_out_context_menu.items());
1549 if (arv->audio_region()->fade_out_active()) {
1550 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1552 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1555 items.push_back (SeparatorElem());
1556 fill_xfade_menu (items, false);
1558 xfade_out_context_menu.popup (button, time);
1562 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1564 using namespace Menu_Helpers;
1565 Menu* (Editor::*build_menu_function)();
1568 switch (item_type) {
1570 case RegionViewName:
1571 case RegionViewNameHighlight:
1572 case LeftFrameHandle:
1573 case RightFrameHandle:
1574 if (with_selection) {
1575 build_menu_function = &Editor::build_track_selection_context_menu;
1577 build_menu_function = &Editor::build_track_region_context_menu;
1582 if (with_selection) {
1583 build_menu_function = &Editor::build_track_selection_context_menu;
1585 build_menu_function = &Editor::build_track_context_menu;
1590 if (clicked_routeview->track()) {
1591 build_menu_function = &Editor::build_track_context_menu;
1593 build_menu_function = &Editor::build_track_bus_context_menu;
1598 /* probably shouldn't happen but if it does, we don't care */
1602 menu = (this->*build_menu_function)();
1603 menu->set_name ("ArdourContextMenu");
1605 /* now handle specific situations */
1607 switch (item_type) {
1609 case RegionViewName:
1610 case RegionViewNameHighlight:
1611 case LeftFrameHandle:
1612 case RightFrameHandle:
1613 if (!with_selection) {
1614 if (region_edit_menu_split_item) {
1615 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1616 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1618 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1621 if (region_edit_menu_split_multichannel_item) {
1622 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1623 region_edit_menu_split_multichannel_item->set_sensitive (true);
1625 region_edit_menu_split_multichannel_item->set_sensitive (false);
1638 /* probably shouldn't happen but if it does, we don't care */
1642 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1644 /* Bounce to disk */
1646 using namespace Menu_Helpers;
1647 MenuList& edit_items = menu->items();
1649 edit_items.push_back (SeparatorElem());
1651 switch (clicked_routeview->audio_track()->freeze_state()) {
1652 case AudioTrack::NoFreeze:
1653 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1656 case AudioTrack::Frozen:
1657 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1660 case AudioTrack::UnFrozen:
1661 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1667 if (item_type == StreamItem && clicked_routeview) {
1668 clicked_routeview->build_underlay_menu(menu);
1671 /* When the region menu is opened, we setup the actions so that they look right
1674 sensitize_the_right_region_actions (false);
1675 _last_region_menu_was_main = false;
1677 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1678 menu->popup (button, time);
1682 Editor::build_track_context_menu ()
1684 using namespace Menu_Helpers;
1686 MenuList& edit_items = track_context_menu.items();
1689 add_dstream_context_items (edit_items);
1690 return &track_context_menu;
1694 Editor::build_track_bus_context_menu ()
1696 using namespace Menu_Helpers;
1698 MenuList& edit_items = track_context_menu.items();
1701 add_bus_context_items (edit_items);
1702 return &track_context_menu;
1706 Editor::build_track_region_context_menu ()
1708 using namespace Menu_Helpers;
1709 MenuList& edit_items = track_region_context_menu.items();
1712 /* we've just cleared the track region context menu, so the menu that these
1713 two items were on will have disappeared; stop them dangling.
1715 region_edit_menu_split_item = 0;
1716 region_edit_menu_split_multichannel_item = 0;
1718 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1721 boost::shared_ptr<Track> tr;
1722 boost::shared_ptr<Playlist> pl;
1724 if ((tr = rtv->track())) {
1725 add_region_context_items (edit_items, tr);
1729 add_dstream_context_items (edit_items);
1731 return &track_region_context_menu;
1735 Editor::loudness_analyze_region_selection ()
1740 Selection& s (PublicEditor::instance ().get_selection ());
1741 RegionSelection ars = s.regions;
1742 ARDOUR::AnalysisGraph ag (_session);
1743 samplecnt_t total_work = 0;
1745 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1746 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1750 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1753 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1754 total_work += arv->region ()->length ();
1757 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1759 ag.set_total_samples (total_work);
1760 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1763 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1764 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1768 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1772 ag.analyze_region (ar);
1775 if (!ag.canceled ()) {
1776 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1782 Editor::loudness_analyze_range_selection ()
1787 Selection& s (PublicEditor::instance ().get_selection ());
1788 TimeSelection ts = s.time;
1789 ARDOUR::AnalysisGraph ag (_session);
1790 samplecnt_t total_work = 0;
1792 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1793 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1797 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1801 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1802 total_work += j->length ();
1806 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1808 ag.set_total_samples (total_work);
1809 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1812 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1813 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1817 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1821 ag.analyze_range (rui->route (), pl, ts);
1824 if (!ag.canceled ()) {
1825 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1831 Editor::spectral_analyze_region_selection ()
1833 if (analysis_window == 0) {
1834 analysis_window = new AnalysisWindow();
1837 analysis_window->set_session(_session);
1839 analysis_window->show_all();
1842 analysis_window->set_regionmode();
1843 analysis_window->analyze();
1845 analysis_window->present();
1849 Editor::spectral_analyze_range_selection()
1851 if (analysis_window == 0) {
1852 analysis_window = new AnalysisWindow();
1855 analysis_window->set_session(_session);
1857 analysis_window->show_all();
1860 analysis_window->set_rangemode();
1861 analysis_window->analyze();
1863 analysis_window->present();
1867 Editor::build_track_selection_context_menu ()
1869 using namespace Menu_Helpers;
1870 MenuList& edit_items = track_selection_context_menu.items();
1871 edit_items.clear ();
1873 add_selection_context_items (edit_items);
1874 // edit_items.push_back (SeparatorElem());
1875 // add_dstream_context_items (edit_items);
1877 return &track_selection_context_menu;
1881 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1883 using namespace Menu_Helpers;
1885 /* OK, stick the region submenu at the top of the list, and then add
1889 RegionSelection rs = get_regions_from_selection_and_entered ();
1891 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1893 if (_popup_region_menu_item == 0) {
1894 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1895 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1896 _popup_region_menu_item->show ();
1898 _popup_region_menu_item->set_label (menu_item_name);
1901 /* No layering allowed in later is higher layering model */
1902 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1903 if (act && Config->get_layer_model() == LaterHigher) {
1904 act->set_sensitive (false);
1906 act->set_sensitive (true);
1909 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1911 edit_items.push_back (*_popup_region_menu_item);
1912 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1913 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1915 edit_items.push_back (SeparatorElem());
1918 /** Add context menu items relevant to selection ranges.
1919 * @param edit_items List to add the items to.
1922 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1924 using namespace Menu_Helpers;
1926 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1927 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1932 edit_items.push_back (SeparatorElem());
1933 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1934 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1936 edit_items.push_back (SeparatorElem());
1938 edit_items.push_back (
1940 _("Move Range Start to Previous Region Boundary"),
1941 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1945 edit_items.push_back (
1947 _("Move Range Start to Next Region Boundary"),
1948 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1952 edit_items.push_back (
1954 _("Move Range End to Previous Region Boundary"),
1955 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1959 edit_items.push_back (
1961 _("Move Range End to Next Region Boundary"),
1962 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1966 edit_items.push_back (SeparatorElem());
1967 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1968 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1970 edit_items.push_back (SeparatorElem());
1971 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1973 edit_items.push_back (SeparatorElem());
1974 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1975 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1976 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1978 edit_items.push_back (SeparatorElem());
1979 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1981 edit_items.push_back (SeparatorElem());
1982 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1983 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1987 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1988 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1989 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1990 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1991 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1992 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1998 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
2000 using namespace Menu_Helpers;
2004 Menu *play_menu = manage (new Menu);
2005 MenuList& play_items = play_menu->items();
2006 play_menu->set_name ("ArdourContextMenu");
2008 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2009 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2010 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2011 play_items.push_back (SeparatorElem());
2012 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2014 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2018 Menu *select_menu = manage (new Menu);
2019 MenuList& select_items = select_menu->items();
2020 select_menu->set_name ("ArdourContextMenu");
2022 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2023 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2024 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2025 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2026 select_items.push_back (SeparatorElem());
2027 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2028 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2029 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2030 select_items.push_back (SeparatorElem());
2031 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2032 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2033 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2034 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2035 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2036 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2037 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2039 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2043 Menu *cutnpaste_menu = manage (new Menu);
2044 MenuList& cutnpaste_items = cutnpaste_menu->items();
2045 cutnpaste_menu->set_name ("ArdourContextMenu");
2047 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2048 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2049 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2051 cutnpaste_items.push_back (SeparatorElem());
2053 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2054 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2056 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2058 /* Adding new material */
2060 edit_items.push_back (SeparatorElem());
2061 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2062 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2066 Menu *nudge_menu = manage (new Menu());
2067 MenuList& nudge_items = nudge_menu->items();
2068 nudge_menu->set_name ("ArdourContextMenu");
2070 edit_items.push_back (SeparatorElem());
2071 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2072 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2073 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2074 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2076 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2080 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2082 using namespace Menu_Helpers;
2086 Menu *play_menu = manage (new Menu);
2087 MenuList& play_items = play_menu->items();
2088 play_menu->set_name ("ArdourContextMenu");
2090 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2091 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2092 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2096 Menu *select_menu = manage (new Menu);
2097 MenuList& select_items = select_menu->items();
2098 select_menu->set_name ("ArdourContextMenu");
2100 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2101 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2102 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2103 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2104 select_items.push_back (SeparatorElem());
2105 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2106 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2107 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2108 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2110 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2114 Menu *cutnpaste_menu = manage (new Menu);
2115 MenuList& cutnpaste_items = cutnpaste_menu->items();
2116 cutnpaste_menu->set_name ("ArdourContextMenu");
2118 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2119 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2120 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2122 Menu *nudge_menu = manage (new Menu());
2123 MenuList& nudge_items = nudge_menu->items();
2124 nudge_menu->set_name ("ArdourContextMenu");
2126 edit_items.push_back (SeparatorElem());
2127 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2128 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2129 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2130 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2132 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2136 Editor::grid_type() const
2142 Editor::grid_musical() const
2144 switch (_grid_type) {
2145 case GridTypeBeatDiv32:
2146 case GridTypeBeatDiv28:
2147 case GridTypeBeatDiv24:
2148 case GridTypeBeatDiv20:
2149 case GridTypeBeatDiv16:
2150 case GridTypeBeatDiv14:
2151 case GridTypeBeatDiv12:
2152 case GridTypeBeatDiv10:
2153 case GridTypeBeatDiv8:
2154 case GridTypeBeatDiv7:
2155 case GridTypeBeatDiv6:
2156 case GridTypeBeatDiv5:
2157 case GridTypeBeatDiv4:
2158 case GridTypeBeatDiv3:
2159 case GridTypeBeatDiv2:
2165 case GridTypeMinSec:
2166 case GridTypeSamples:
2173 Editor::grid_nonmusical() const
2175 switch (_grid_type) {
2177 case GridTypeMinSec:
2178 case GridTypeSamples:
2180 case GridTypeBeatDiv32:
2181 case GridTypeBeatDiv28:
2182 case GridTypeBeatDiv24:
2183 case GridTypeBeatDiv20:
2184 case GridTypeBeatDiv16:
2185 case GridTypeBeatDiv14:
2186 case GridTypeBeatDiv12:
2187 case GridTypeBeatDiv10:
2188 case GridTypeBeatDiv8:
2189 case GridTypeBeatDiv7:
2190 case GridTypeBeatDiv6:
2191 case GridTypeBeatDiv5:
2192 case GridTypeBeatDiv4:
2193 case GridTypeBeatDiv3:
2194 case GridTypeBeatDiv2:
2203 Editor::snap_mode() const
2209 Editor::set_grid_to (GridType gt)
2211 if (_grid_type == gt) { //already set
2215 unsigned int grid_ind = (unsigned int)gt;
2217 if (internal_editing()) {
2218 internal_grid_type = gt;
2220 pre_internal_grid_type = gt;
2225 if (grid_ind > grid_type_strings.size() - 1) {
2227 _grid_type = (GridType)grid_ind;
2230 string str = grid_type_strings[grid_ind];
2232 if (str != grid_type_selector.get_text()) {
2233 grid_type_selector.set_text (str);
2236 //show appropriate rulers for this grid setting. (ToDo: perhaps make this optional)
2237 //Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines
2238 if ( grid_musical() ) {
2239 ruler_tempo_action->set_active(true);
2240 ruler_meter_action->set_active(true);
2242 ruler_bbt_action->set_active(true);
2243 ruler_timecode_action->set_active(false);
2244 ruler_minsec_action->set_active(false);
2245 ruler_samples_action->set_active(false);
2246 } else if (_grid_type == GridTypeSmpte ) {
2247 ruler_tempo_action->set_active(false);
2248 ruler_meter_action->set_active(false);
2250 ruler_bbt_action->set_active(false);
2251 ruler_timecode_action->set_active(true);
2252 ruler_minsec_action->set_active(false);
2253 ruler_samples_action->set_active(false);
2254 } else if (_grid_type == GridTypeMinSec ) {
2255 ruler_tempo_action->set_active(false);
2256 ruler_meter_action->set_active(false);
2258 ruler_bbt_action->set_active(false);
2259 ruler_timecode_action->set_active(false);
2260 ruler_minsec_action->set_active(true);
2261 ruler_samples_action->set_active(false);
2262 } else if (_grid_type == GridTypeSamples ) {
2263 ruler_tempo_action->set_active(false);
2264 ruler_meter_action->set_active(false);
2266 ruler_bbt_action->set_active(false);
2267 ruler_timecode_action->set_active(false);
2268 ruler_minsec_action->set_active(false);
2269 ruler_samples_action->set_active(true);
2274 if ( grid_musical() ) {
2275 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2276 update_tempo_based_rulers ();
2279 mark_region_boundary_cache_dirty ();
2281 redisplay_grid (false);
2283 SnapChanged (); /* EMIT SIGNAL */
2287 Editor::set_snap_mode (SnapMode mode)
2289 if (internal_editing()) {
2290 internal_snap_mode = mode;
2292 pre_internal_snap_mode = mode;
2297 if (_snap_mode == SnapOff ) {
2298 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2300 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2307 Editor::set_edit_point_preference (EditPoint ep, bool force)
2309 bool changed = (_edit_point != ep);
2312 if (Profile->get_mixbus())
2313 if (ep == EditAtSelectedMarker)
2314 ep = EditAtPlayhead;
2316 string str = edit_point_strings[(int)ep];
2317 if (str != edit_point_selector.get_text ()) {
2318 edit_point_selector.set_text (str);
2321 update_all_enter_cursors();
2323 if (!force && !changed) {
2327 const char* action=NULL;
2329 switch (_edit_point) {
2330 case EditAtPlayhead:
2331 action = "edit-at-playhead";
2333 case EditAtSelectedMarker:
2334 action = "edit-at-marker";
2337 action = "edit-at-mouse";
2341 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2343 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2347 bool in_track_canvas;
2349 if (!mouse_sample (foo, in_track_canvas)) {
2350 in_track_canvas = false;
2353 reset_canvas_action_sensitivity (in_track_canvas);
2354 sensitize_the_right_region_actions (false);
2360 Editor::set_state (const XMLNode& node, int version)
2363 PBD::Unwinder<bool> nsi (no_save_instant, true);
2366 Tabbable::set_state (node, version);
2369 if (_session && node.get_property ("playhead", ph_pos)) {
2371 playhead_cursor->set_position (ph_pos);
2373 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2374 playhead_cursor->set_position (0);
2377 playhead_cursor->set_position (0);
2380 node.get_property ("mixer-width", editor_mixer_strip_width);
2382 node.get_property ("zoom-focus", zoom_focus);
2383 zoom_focus_selection_done (zoom_focus);
2386 if (node.get_property ("zoom", z)) {
2387 /* older versions of ardour used floating point samples_per_pixel */
2388 reset_zoom (llrintf (z));
2390 reset_zoom (samples_per_pixel);
2394 if (node.get_property ("visible-track-count", cnt)) {
2395 set_visible_track_count (cnt);
2399 if (!node.get_property ("grid-type", grid_type)) {
2400 grid_type = _grid_type;
2402 set_grid_to (grid_type);
2405 if (node.get_property ("snap-mode", sm)) {
2406 snap_mode_selection_done(sm);
2407 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2408 * snap_mode_selection_done() will only mark an already active item as active
2409 * which does not trigger set_text().
2413 set_snap_mode (_snap_mode);
2416 node.get_property ("internal-grid-type", internal_grid_type);
2417 node.get_property ("internal-snap-mode", internal_snap_mode);
2418 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2419 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2422 if (node.get_property ("mouse-mode", mm_str)) {
2423 MouseMode m = str2mousemode(mm_str);
2424 set_mouse_mode (m, true);
2426 set_mouse_mode (MouseObject, true);
2430 if (node.get_property ("left-frame", lf_pos)) {
2434 reset_x_origin (lf_pos);
2438 if (node.get_property ("y-origin", y_origin)) {
2439 reset_y_origin (y_origin);
2442 if (node.get_property ("join-object-range", yn)) {
2443 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2445 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2446 tact->set_active (!yn);
2447 tact->set_active (yn);
2449 set_mouse_mode(mouse_mode, true);
2453 if (node.get_property ("edit-point", ep)) {
2454 set_edit_point_preference (ep, true);
2456 set_edit_point_preference (_edit_point);
2459 if (node.get_property ("follow-playhead", yn)) {
2460 set_follow_playhead (yn);
2463 if (node.get_property ("stationary-playhead", yn)) {
2464 set_stationary_playhead (yn);
2467 RegionListSortType sort_type;
2468 if (node.get_property ("region-list-sort-type", sort_type)) {
2469 _regions->reset_sort_type (sort_type, true);
2472 if (node.get_property ("show-editor-mixer", yn)) {
2474 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2477 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2479 /* do it twice to force the change */
2481 tact->set_active (!yn);
2482 tact->set_active (yn);
2485 if (node.get_property ("show-editor-list", yn)) {
2487 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2490 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2492 /* do it twice to force the change */
2494 tact->set_active (!yn);
2495 tact->set_active (yn);
2499 if (node.get_property (X_("editor-list-page"), el_page)) {
2500 _the_notebook.set_current_page (el_page);
2503 if (node.get_property (X_("show-marker-lines"), yn)) {
2504 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2506 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2508 tact->set_active (!yn);
2509 tact->set_active (yn);
2512 XMLNodeList children = node.children ();
2513 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2514 selection->set_state (**i, Stateful::current_state_version);
2515 _regions->set_state (**i);
2516 _locations->set_state (**i);
2519 if (node.get_property ("maximised", yn)) {
2520 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2522 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2523 bool fs = tact && tact->get_active();
2525 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2529 samplepos_t nudge_clock_value;
2530 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2531 nudge_clock->set (nudge_clock_value);
2533 nudge_clock->set_mode (AudioClock::Timecode);
2534 nudge_clock->set (_session->sample_rate() * 5, true);
2539 * Not all properties may have been in XML, but
2540 * those that are linked to a private variable may need changing
2544 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2545 yn = _follow_playhead;
2547 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2548 if (tact->get_active() != yn) {
2549 tact->set_active (yn);
2553 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2554 yn = _stationary_playhead;
2556 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2557 if (tact->get_active() != yn) {
2558 tact->set_active (yn);
2563 return LuaInstance::instance()->set_state(node);
2567 Editor::get_state ()
2569 XMLNode* node = new XMLNode (X_("Editor"));
2571 node->set_property ("id", id().to_s ());
2573 node->add_child_nocopy (Tabbable::get_state());
2575 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2576 node->set_property("notebook-shrunk", _notebook_shrunk);
2577 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2579 maybe_add_mixer_strip_width (*node);
2581 node->set_property ("zoom-focus", zoom_focus);
2583 node->set_property ("zoom", samples_per_pixel);
2584 node->set_property ("grid-type", _grid_type);
2585 node->set_property ("snap-mode", _snap_mode);
2586 node->set_property ("internal-grid-type", internal_grid_type);
2587 node->set_property ("internal-snap-mode", internal_snap_mode);
2588 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2589 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2590 node->set_property ("edit-point", _edit_point);
2591 node->set_property ("visible-track-count", _visible_track_count);
2593 node->set_property ("playhead", playhead_cursor->current_sample ());
2594 node->set_property ("left-frame", _leftmost_sample);
2595 node->set_property ("y-origin", vertical_adjustment.get_value ());
2597 node->set_property ("maximised", _maximised);
2598 node->set_property ("follow-playhead", _follow_playhead);
2599 node->set_property ("stationary-playhead", _stationary_playhead);
2600 node->set_property ("region-list-sort-type", _regions->sort_type ());
2601 node->set_property ("mouse-mode", mouse_mode);
2602 node->set_property ("join-object-range", smart_mode_action->get_active ());
2604 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2606 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2607 node->set_property (X_("show-editor-mixer"), tact->get_active());
2610 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2612 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2613 node->set_property (X_("show-editor-list"), tact->get_active());
2616 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2618 if (button_bindings) {
2619 XMLNode* bb = new XMLNode (X_("Buttons"));
2620 button_bindings->save (*bb);
2621 node->add_child_nocopy (*bb);
2624 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2626 node->add_child_nocopy (selection->get_state ());
2627 node->add_child_nocopy (_regions->get_state ());
2629 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2631 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2632 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2633 node->add_child_nocopy (_locations->get_state ());
2638 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2639 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2641 * @return pair: TimeAxisView that y is over, layer index.
2643 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2644 * in stacked or expanded region display mode, otherwise 0.
2646 std::pair<TimeAxisView *, double>
2647 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2649 if (!trackview_relative_offset) {
2650 y -= _trackview_group->canvas_origin().y;
2654 return std::make_pair ( (TimeAxisView *) 0, 0);
2657 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2659 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2666 return std::make_pair ( (TimeAxisView *) 0, 0);
2670 Editor::set_snapped_cursor_position (samplepos_t pos)
2672 if ( _edit_point == EditAtMouse ) {
2673 snapped_cursor->set_position(pos);
2678 /** Snap a position to the grid, if appropriate, taking into account current
2679 * grid settings and also the state of any snap modifier keys that may be pressed.
2680 * @param start Position to snap.
2681 * @param event Event to get current key modifier information from, or 0.
2684 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
2686 if (!_session || !event) {
2690 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2691 if (_snap_mode == SnapOff) {
2692 snap_to_internal (start, direction, pref, for_mark);
2694 start.set (start.sample, 0);
2697 if (_snap_mode != SnapOff) {
2698 snap_to_internal (start, direction, pref, for_mark);
2699 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2700 /* SnapOff, but we pressed the snap_delta modifier */
2701 snap_to_internal (start, direction, pref, for_mark);
2703 start.set (start.sample, 0);
2709 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2711 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2712 start.set (start.sample, 0);
2716 snap_to_internal (start, direction, pref, for_mark, ensure_snap);
2720 check_best_snap ( samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best )
2722 samplepos_t diff = abs( test - presnap );
2723 if ( diff < dist ) {
2728 test = max_samplepos; //reset this so it doesn't get accidentally reused
2732 Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
2734 if (marks.empty() ) return presnap;
2738 samplepos_t test = presnap;
2740 before = after = max_samplepos;
2742 //get marks to either side of presnap
2743 vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
2744 while ( m != marks.end() && (m->position < presnap) ) {
2748 if (m == marks.end ()) {
2749 /* ran out of marks */
2750 before = marks.back().position;
2753 after = m->position;
2755 if (m != marks.begin ()) {
2757 before = m->position;
2760 if (before == max_samplepos && after == max_samplepos) {
2761 /* No grid to snap to, so just don't snap */
2763 } else if (before == max_samplepos) {
2765 } else if (after == max_samplepos) {
2768 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2770 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2772 else if (direction == 0 ) {
2773 if ((presnap - before) < (after - presnap)) {
2785 Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
2791 _session->locations()->marks_either_side (presnap, before, after);
2793 if (before == max_samplepos && after == max_samplepos) {
2794 /* No marks to snap to, so just don't snap */
2796 } else if (before == max_samplepos) {
2798 } else if (after == max_samplepos) {
2801 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2803 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2805 } else if (direction == 0 ) {
2806 if ((presnap - before) < (after - presnap)) {
2818 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2820 const samplepos_t presnap = start.sample;
2822 samplepos_t test = max_samplepos; //for each snap, we'll use this value
2823 samplepos_t dist = max_samplepos; //this records the distance of the best snap result we've found so far
2824 samplepos_t best = max_samplepos; //this records the best snap-result we've found so far
2826 //check snap-to-marker
2827 if ( UIConfiguration::instance().get_snap_to_marks() ) {
2832 test = marker_snap_to_internal ( presnap, direction );
2833 check_best_snap(presnap, test, dist, best);
2836 //check snap-to-region-{start/end/sync}
2837 if ( UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync() ) {
2838 if (!region_boundary_cache.empty()) {
2840 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2841 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2843 if (direction > 0) {
2844 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2846 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2849 if (next != region_boundary_cache.begin ()) {
2854 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2855 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2857 if (presnap > (p + n) / 2) {
2864 check_best_snap(presnap, test, dist, best);
2868 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone) ) {
2870 //if SnapToGrid is selected, the user wants to prioritize the music grid
2871 //in this case we should reset the best distance, so Grid will prevail
2872 dist = max_samplepos;
2874 test = snap_to_grid (grid_marks, presnap, direction);
2875 check_best_snap(presnap, test, dist, best);
2878 //now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
2879 //this also helps to avoid snapping to somewhere the user can't see. ( i.e.: I clicked on a region and it disappeared!! )
2880 //ToDo: perhaps this should only occur if EditPointMouse?
2881 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2883 start.set (best, 0);
2885 } else if (presnap > best) {
2886 if (presnap > (best+ snap_threshold_s)) {
2889 } else if (presnap < best) {
2890 if (presnap < (best - snap_threshold_s)) {
2895 start.set (best, 0);
2900 Editor::setup_toolbar ()
2902 HBox* mode_box = manage(new HBox);
2903 mode_box->set_border_width (2);
2904 mode_box->set_spacing(2);
2906 HBox* mouse_mode_box = manage (new HBox);
2907 HBox* mouse_mode_hbox = manage (new HBox);
2908 VBox* mouse_mode_vbox = manage (new VBox);
2909 Alignment* mouse_mode_align = manage (new Alignment);
2911 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2912 mouse_mode_size_group->add_widget (smart_mode_button);
2913 mouse_mode_size_group->add_widget (mouse_move_button);
2914 mouse_mode_size_group->add_widget (mouse_cut_button);
2915 mouse_mode_size_group->add_widget (mouse_select_button);
2916 mouse_mode_size_group->add_widget (mouse_timefx_button);
2917 mouse_mode_size_group->add_widget (mouse_audition_button);
2918 mouse_mode_size_group->add_widget (mouse_draw_button);
2919 mouse_mode_size_group->add_widget (mouse_content_button);
2921 if (!Profile->get_mixbus()) {
2922 mouse_mode_size_group->add_widget (zoom_in_button);
2923 mouse_mode_size_group->add_widget (zoom_out_button);
2924 mouse_mode_size_group->add_widget (zoom_out_full_button);
2925 mouse_mode_size_group->add_widget (zoom_focus_selector);
2926 mouse_mode_size_group->add_widget (tav_shrink_button);
2927 mouse_mode_size_group->add_widget (tav_expand_button);
2929 mouse_mode_size_group->add_widget (zoom_preset_selector);
2930 mouse_mode_size_group->add_widget (visible_tracks_selector);
2933 mouse_mode_size_group->add_widget (grid_type_selector);
2934 mouse_mode_size_group->add_widget (snap_mode_button);
2936 mouse_mode_size_group->add_widget (edit_point_selector);
2937 mouse_mode_size_group->add_widget (edit_mode_selector);
2939 mouse_mode_size_group->add_widget (*nudge_clock);
2940 mouse_mode_size_group->add_widget (nudge_forward_button);
2941 mouse_mode_size_group->add_widget (nudge_backward_button);
2943 mouse_mode_hbox->set_spacing (2);
2945 if (!ARDOUR::Profile->get_trx()) {
2946 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2949 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2950 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2952 if (!ARDOUR::Profile->get_mixbus()) {
2953 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2954 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2957 if (!ARDOUR::Profile->get_trx()) {
2958 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2959 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2960 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2963 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2965 mouse_mode_align->add (*mouse_mode_vbox);
2966 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2968 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2970 edit_mode_selector.set_name ("mouse mode button");
2972 if (!ARDOUR::Profile->get_trx()) {
2973 mode_box->pack_start (edit_mode_selector, false, false);
2974 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2975 mode_box->pack_start (edit_point_selector, false, false);
2976 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2979 mode_box->pack_start (*mouse_mode_box, false, false);
2983 _zoom_box.set_spacing (2);
2984 _zoom_box.set_border_width (2);
2988 zoom_preset_selector.set_name ("zoom button");
2989 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
2991 zoom_in_button.set_name ("zoom button");
2992 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2993 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2994 zoom_in_button.set_related_action (act);
2996 zoom_out_button.set_name ("zoom button");
2997 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2998 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2999 zoom_out_button.set_related_action (act);
3001 zoom_out_full_button.set_name ("zoom button");
3002 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3003 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3004 zoom_out_full_button.set_related_action (act);
3006 zoom_focus_selector.set_name ("zoom button");
3008 if (ARDOUR::Profile->get_mixbus()) {
3009 _zoom_box.pack_start (zoom_preset_selector, false, false);
3010 } else if (ARDOUR::Profile->get_trx()) {
3011 mode_box->pack_start (zoom_out_button, false, false);
3012 mode_box->pack_start (zoom_in_button, false, false);
3014 _zoom_box.pack_start (zoom_out_button, false, false);
3015 _zoom_box.pack_start (zoom_in_button, false, false);
3016 _zoom_box.pack_start (zoom_out_full_button, false, false);
3017 _zoom_box.pack_start (zoom_focus_selector, false, false);
3020 /* Track zoom buttons */
3021 _track_box.set_spacing (2);
3022 _track_box.set_border_width (2);
3024 visible_tracks_selector.set_name ("zoom button");
3025 if (Profile->get_mixbus()) {
3026 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3028 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3031 tav_expand_button.set_name ("zoom button");
3032 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3033 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3034 tav_expand_button.set_related_action (act);
3036 tav_shrink_button.set_name ("zoom button");
3037 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3038 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3039 tav_shrink_button.set_related_action (act);
3041 if (ARDOUR::Profile->get_mixbus()) {
3042 _track_box.pack_start (visible_tracks_selector);
3043 } else if (ARDOUR::Profile->get_trx()) {
3044 _track_box.pack_start (tav_shrink_button);
3045 _track_box.pack_start (tav_expand_button);
3047 _track_box.pack_start (visible_tracks_selector);
3048 _track_box.pack_start (tav_shrink_button);
3049 _track_box.pack_start (tav_expand_button);
3052 snap_box.set_spacing (2);
3053 snap_box.set_border_width (2);
3055 grid_type_selector.set_name ("mouse mode button");
3057 snap_mode_button.set_name ("mouse mode button");
3059 edit_point_selector.set_name ("mouse mode button");
3061 snap_box.pack_start (snap_mode_button, false, false);
3062 snap_box.pack_start (grid_type_selector, false, false);
3066 HBox *nudge_box = manage (new HBox);
3067 nudge_box->set_spacing (2);
3068 nudge_box->set_border_width (2);
3070 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3071 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3073 nudge_box->pack_start (nudge_backward_button, false, false);
3074 nudge_box->pack_start (nudge_forward_button, false, false);
3075 nudge_box->pack_start (*nudge_clock, false, false);
3078 /* Pack everything in... */
3080 toolbar_hbox.set_spacing (2);
3081 toolbar_hbox.set_border_width (2);
3083 ArdourWidgets::ArdourDropShadow *tool_shadow = manage (new (ArdourWidgets::ArdourDropShadow));
3084 tool_shadow->set_size_request( 4, -1 );
3085 tool_shadow->show();
3087 ebox_hpacker.pack_start (*tool_shadow, false, false);
3088 ebox_hpacker.pack_start(ebox_vpacker, true, true);
3090 Gtk::EventBox* spacer = manage (new Gtk::EventBox); //extra space under the mouse toolbar, for aesthetics
3091 spacer->set_name("EditorWindow");
3092 spacer->set_size_request(-1,4);
3095 ebox_vpacker.pack_start(toolbar_hbox, false, false);
3096 ebox_vpacker.pack_start(*spacer, false, false);
3097 ebox_vpacker.show();
3099 toolbar_hbox.pack_start (*mode_box, false, false);
3101 if (!ARDOUR::Profile->get_trx()) {
3103 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3105 toolbar_hbox.pack_start (snap_box, false, false);
3107 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3109 toolbar_hbox.pack_start (*nudge_box, false, false);
3111 //zoom tools on right ege
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)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3144 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3145 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
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));
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));
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)GridTypeSmpte], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSmpte)));
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)GridTypeSamples], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSamples)));
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()) {
3381 The user has undone some selection ops and then made a new one,
3382 making anything earlier in the list invalid.
3385 list<XMLNode *>::iterator it = selection_op_history.begin();
3386 list<XMLNode *>::iterator e_it = it;
3387 advance (e_it, selection_op_history_it);
3389 for ( ; it != e_it; ++it) {
3392 selection_op_history.erase (selection_op_history.begin(), e_it);
3395 selection_op_history.push_front (&_selection_memento->get_state ());
3396 selection_op_history_it = 0;
3398 selection_undo_action->set_sensitive (true);
3399 selection_redo_action->set_sensitive (false);
3402 if (selection_op_cmd_depth > 0) {
3403 selection_op_cmd_depth--;
3409 Editor::undo_selection_op ()
3412 selection_op_history_it++;
3414 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3415 if (n == selection_op_history_it) {
3416 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3417 selection_redo_action->set_sensitive (true);
3421 /* is there an earlier entry? */
3422 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3423 selection_undo_action->set_sensitive (false);
3429 Editor::redo_selection_op ()
3432 if (selection_op_history_it > 0) {
3433 selection_op_history_it--;
3436 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3437 if (n == selection_op_history_it) {
3438 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3439 selection_undo_action->set_sensitive (true);
3444 if (selection_op_history_it == 0) {
3445 selection_redo_action->set_sensitive (false);
3451 Editor::begin_reversible_command (string name)
3454 before.push_back (&_selection_memento->get_state ());
3455 _session->begin_reversible_command (name);
3460 Editor::begin_reversible_command (GQuark q)
3463 before.push_back (&_selection_memento->get_state ());
3464 _session->begin_reversible_command (q);
3469 Editor::abort_reversible_command ()
3472 while(!before.empty()) {
3473 delete before.front();
3476 _session->abort_reversible_command ();
3481 Editor::commit_reversible_command ()
3484 if (before.size() == 1) {
3485 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3486 redo_action->set_sensitive(false);
3487 undo_action->set_sensitive(true);
3488 begin_selection_op_history ();
3491 if (before.empty()) {
3492 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3497 _session->commit_reversible_command ();
3502 Editor::history_changed ()
3506 if (undo_action && _session) {
3507 if (_session->undo_depth() == 0) {
3508 label = S_("Command|Undo");
3510 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3512 undo_action->property_label() = label;
3515 if (redo_action && _session) {
3516 if (_session->redo_depth() == 0) {
3518 redo_action->set_sensitive (false);
3520 label = string_compose(_("Redo (%1)"), _session->next_redo());
3521 redo_action->set_sensitive (true);
3523 redo_action->property_label() = label;
3528 Editor::duplicate_range (bool with_dialog)
3532 RegionSelection rs = get_regions_from_selection_and_entered ();
3534 if ( selection->time.length() == 0 && rs.empty()) {
3540 ArdourDialog win (_("Duplicate"));
3541 Label label (_("Number of duplications:"));
3542 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3543 SpinButton spinner (adjustment, 0.0, 1);
3546 win.get_vbox()->set_spacing (12);
3547 win.get_vbox()->pack_start (hbox);
3548 hbox.set_border_width (6);
3549 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3551 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3552 place, visually. so do this by hand.
3555 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3556 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3557 spinner.grab_focus();
3563 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3564 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3565 win.set_default_response (RESPONSE_ACCEPT);
3567 spinner.grab_focus ();
3569 switch (win.run ()) {
3570 case RESPONSE_ACCEPT:
3576 times = adjustment.get_value();
3579 if ((current_mouse_mode() == MouseRange)) {
3580 if (selection->time.length()) {
3581 duplicate_selection (times);
3583 } else if (get_smart_mode()) {
3584 if (selection->time.length()) {
3585 duplicate_selection (times);
3587 duplicate_some_regions (rs, times);
3589 duplicate_some_regions (rs, times);
3594 Editor::set_edit_mode (EditMode m)
3596 Config->set_edit_mode (m);
3600 Editor::cycle_edit_mode ()
3602 switch (Config->get_edit_mode()) {
3604 Config->set_edit_mode (Ripple);
3608 Config->set_edit_mode (Lock);
3611 Config->set_edit_mode (Slide);
3617 Editor::edit_mode_selection_done ( EditMode m )
3619 Config->set_edit_mode ( m );
3623 Editor::grid_type_selection_done (GridType gridtype)
3625 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3627 ract->set_active ();
3632 Editor::snap_mode_selection_done (SnapMode mode)
3634 RefPtr<RadioAction> ract = snap_mode_action (mode);
3637 ract->set_active (true);
3642 Editor::cycle_edit_point (bool with_marker)
3644 if(Profile->get_mixbus())
3645 with_marker = false;
3647 switch (_edit_point) {
3649 set_edit_point_preference (EditAtPlayhead);
3651 case EditAtPlayhead:
3653 set_edit_point_preference (EditAtSelectedMarker);
3655 set_edit_point_preference (EditAtMouse);
3658 case EditAtSelectedMarker:
3659 set_edit_point_preference (EditAtMouse);
3665 Editor::edit_point_selection_done (EditPoint ep)
3667 set_edit_point_preference ( ep );
3671 Editor::build_zoom_focus_menu ()
3673 using namespace Menu_Helpers;
3675 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3676 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3677 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3678 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3679 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3680 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3682 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3686 Editor::zoom_focus_selection_done ( ZoomFocus f )
3688 RefPtr<RadioAction> ract = zoom_focus_action (f);
3690 ract->set_active ();
3695 Editor::build_track_count_menu ()
3697 using namespace Menu_Helpers;
3699 if (!Profile->get_mixbus()) {
3700 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3709 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3725 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3731 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3732 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3733 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3734 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3735 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3736 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3741 Editor::set_zoom_preset (int64_t ms)
3744 temporal_zoom_session();
3748 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3749 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3753 Editor::set_visible_track_count (int32_t n)
3755 _visible_track_count = n;
3757 /* if the canvas hasn't really been allocated any size yet, just
3758 record the desired number of visible tracks and return. when canvas
3759 allocation happens, we will get called again and then we can do the
3763 if (_visible_canvas_height <= 1) {
3769 DisplaySuspender ds;
3771 if (_visible_track_count > 0) {
3772 h = trackviews_height() / _visible_track_count;
3773 std::ostringstream s;
3774 s << _visible_track_count;
3776 } else if (_visible_track_count == 0) {
3778 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3779 if ((*i)->marked_for_display()) {
3781 TimeAxisView::Children cl ((*i)->get_child_list ());
3782 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3783 if ((*j)->marked_for_display()) {
3790 visible_tracks_selector.set_text (X_("*"));
3793 h = trackviews_height() / n;
3796 /* negative value means that the visible track count has
3797 been overridden by explicit track height changes.
3799 visible_tracks_selector.set_text (X_("*"));
3803 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3804 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3807 if (str != visible_tracks_selector.get_text()) {
3808 visible_tracks_selector.set_text (str);
3813 Editor::override_visible_track_count ()
3815 _visible_track_count = -1;
3816 visible_tracks_selector.set_text ( _("*") );
3820 Editor::edit_controls_button_release (GdkEventButton* ev)
3822 if (Keyboard::is_context_menu_event (ev)) {
3823 ARDOUR_UI::instance()->add_route ();
3824 } else if (ev->button == 1) {
3825 selection->clear_tracks ();
3832 Editor::mouse_select_button_release (GdkEventButton* ev)
3834 /* this handles just right-clicks */
3836 if (ev->button != 3) {
3844 Editor::set_zoom_focus (ZoomFocus f)
3846 string str = zoom_focus_strings[(int)f];
3848 if (str != zoom_focus_selector.get_text()) {
3849 zoom_focus_selector.set_text (str);
3852 if (zoom_focus != f) {
3859 Editor::cycle_zoom_focus ()
3861 switch (zoom_focus) {
3863 set_zoom_focus (ZoomFocusRight);
3865 case ZoomFocusRight:
3866 set_zoom_focus (ZoomFocusCenter);
3868 case ZoomFocusCenter:
3869 set_zoom_focus (ZoomFocusPlayhead);
3871 case ZoomFocusPlayhead:
3872 set_zoom_focus (ZoomFocusMouse);
3874 case ZoomFocusMouse:
3875 set_zoom_focus (ZoomFocusEdit);
3878 set_zoom_focus (ZoomFocusLeft);
3884 Editor::update_grid ()
3886 if ( grid_musical() ) {
3887 std::vector<TempoMap::BBTPoint> grid;
3888 if (bbt_ruler_scale != bbt_show_many) {
3889 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3891 maybe_draw_grid_lines ();
3892 } else if ( grid_nonmusical() ) {
3893 maybe_draw_grid_lines ();
3900 Editor::toggle_follow_playhead ()
3902 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3904 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3905 set_follow_playhead (tact->get_active());
3909 /** @param yn true to follow playhead, otherwise false.
3910 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3913 Editor::set_follow_playhead (bool yn, bool catch_up)
3915 if (_follow_playhead != yn) {
3916 if ((_follow_playhead = yn) == true && catch_up) {
3918 reset_x_origin_to_follow_playhead ();
3925 Editor::toggle_stationary_playhead ()
3927 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3929 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3930 set_stationary_playhead (tact->get_active());
3935 Editor::set_stationary_playhead (bool yn)
3937 if (_stationary_playhead != yn) {
3938 if ((_stationary_playhead = yn) == true) {
3940 // FIXME need a 3.0 equivalent of this 2.X call
3941 // update_current_screen ();
3948 Editor::playlist_selector () const
3950 return *_playlist_selector;
3954 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
3956 if (paste_count == 0) {
3957 /* don't bother calculating an offset that will be zero anyway */
3961 /* calculate basic unsnapped multi-paste offset */
3962 samplecnt_t offset = paste_count * duration;
3964 /* snap offset so pos + offset is aligned to the grid */
3965 MusicSample offset_pos (pos + offset, 0);
3966 snap_to(offset_pos, RoundUpMaybe);
3967 offset = offset_pos.sample - pos;
3973 Editor::get_grid_beat_divisions(samplepos_t position)
3975 switch (_grid_type) {
3976 case GridTypeBeatDiv32: return 32;
3977 case GridTypeBeatDiv28: return 28;
3978 case GridTypeBeatDiv24: return 24;
3979 case GridTypeBeatDiv20: return 20;
3980 case GridTypeBeatDiv16: return 16;
3981 case GridTypeBeatDiv14: return 14;
3982 case GridTypeBeatDiv12: return 12;
3983 case GridTypeBeatDiv10: return 10;
3984 case GridTypeBeatDiv8: return 8;
3985 case GridTypeBeatDiv7: return 7;
3986 case GridTypeBeatDiv6: return 6;
3987 case GridTypeBeatDiv5: return 5;
3988 case GridTypeBeatDiv4: return 4;
3989 case GridTypeBeatDiv3: return 3;
3990 case GridTypeBeatDiv2: return 2;
3992 case GridTypeNone: return 0;
3993 case GridTypeSmpte: return 0;
3994 case GridTypeMinSec: return 0;
3995 case GridTypeSamples: return 0;
4001 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
4002 if the grid is non-musical, returns 0.
4003 if the grid is snapped to bars, returns -1.
4004 @param event_state the current keyboard modifier mask.
4007 Editor::get_grid_music_divisions (uint32_t event_state)
4009 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
4013 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
4017 switch (_grid_type) {
4018 case GridTypeBeatDiv32: return 32;
4019 case GridTypeBeatDiv28: return 28;
4020 case GridTypeBeatDiv24: return 24;
4021 case GridTypeBeatDiv20: return 20;
4022 case GridTypeBeatDiv16: return 16;
4023 case GridTypeBeatDiv14: return 14;
4024 case GridTypeBeatDiv12: return 12;
4025 case GridTypeBeatDiv10: return 10;
4026 case GridTypeBeatDiv8: return 8;
4027 case GridTypeBeatDiv7: return 7;
4028 case GridTypeBeatDiv6: return 6;
4029 case GridTypeBeatDiv5: return 5;
4030 case GridTypeBeatDiv4: return 4;
4031 case GridTypeBeatDiv3: return 3;
4032 case GridTypeBeatDiv2: return 2;
4033 case GridTypeBeat: return 1;
4034 case GridTypeBar : return -1;
4036 case GridTypeNone: return 0;
4037 case GridTypeSmpte: return 0;
4038 case GridTypeMinSec: return 0;
4039 case GridTypeSamples: return 0;
4045 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4049 const unsigned divisions = get_grid_beat_divisions(position);
4051 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4054 switch (_grid_type) {
4056 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4059 const Meter& m = _session->tempo_map().meter_at_sample (position);
4060 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4068 return Temporal::Beats();
4072 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4076 ret = nudge_clock->current_duration (pos);
4077 next = ret + 1; /* XXXX fix me */
4083 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4085 ArdourDialog dialog (_("Playlist Deletion"));
4086 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4087 "If it is kept, its audio files will not be cleaned.\n"
4088 "If it is deleted, audio files used by it alone will be cleaned."),
4091 dialog.set_position (WIN_POS_CENTER);
4092 dialog.get_vbox()->pack_start (label);
4096 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4097 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4098 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4099 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4100 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4102 // by default gtk uses the left most button
4103 keep->grab_focus ();
4105 switch (dialog.run ()) {
4107 /* keep this and all remaining ones */
4112 /* delete this and all others */
4116 case RESPONSE_ACCEPT:
4117 /* delete the playlist */
4121 case RESPONSE_REJECT:
4122 /* keep the playlist */
4134 Editor::audio_region_selection_covers (samplepos_t where)
4136 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4137 if ((*a)->region()->covers (where)) {
4146 Editor::prepare_for_cleanup ()
4148 cut_buffer->clear_regions ();
4149 cut_buffer->clear_playlists ();
4151 selection->clear_regions ();
4152 selection->clear_playlists ();
4154 _regions->suspend_redisplay ();
4158 Editor::finish_cleanup ()
4160 _regions->resume_redisplay ();
4164 Editor::transport_loop_location()
4167 return _session->locations()->auto_loop_location();
4174 Editor::transport_punch_location()
4177 return _session->locations()->auto_punch_location();
4184 Editor::control_layout_scroll (GdkEventScroll* ev)
4186 /* Just forward to the normal canvas scroll method. The coordinate
4187 systems are different but since the canvas is always larger than the
4188 track headers, and aligned with the trackview area, this will work.
4190 In the not too distant future this layout is going away anyway and
4191 headers will be on the canvas.
4193 return canvas_scroll_event (ev, false);
4197 Editor::session_state_saved (string)
4200 _snapshots->redisplay ();
4204 Editor::maximise_editing_space ()
4210 Gtk::Window* toplevel = current_toplevel();
4213 toplevel->fullscreen ();
4219 Editor::restore_editing_space ()
4225 Gtk::Window* toplevel = current_toplevel();
4228 toplevel->unfullscreen();
4234 * Make new playlists for a given track and also any others that belong
4235 * to the same active route group with the `select' property.
4240 Editor::new_playlists (TimeAxisView* v)
4242 begin_reversible_command (_("new playlists"));
4243 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4244 _session->playlists->get (playlists);
4245 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4246 commit_reversible_command ();
4250 * Use a copy of the current playlist for a given track and also any others that belong
4251 * to the same active route group with the `select' property.
4256 Editor::copy_playlists (TimeAxisView* v)
4258 begin_reversible_command (_("copy playlists"));
4259 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4260 _session->playlists->get (playlists);
4261 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4262 commit_reversible_command ();
4265 /** Clear the current playlist for a given track and also any others that belong
4266 * to the same active route group with the `select' property.
4271 Editor::clear_playlists (TimeAxisView* v)
4273 begin_reversible_command (_("clear playlists"));
4274 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4275 _session->playlists->get (playlists);
4276 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4277 commit_reversible_command ();
4281 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4283 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4287 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4289 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4293 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4295 atv.clear_playlist ();
4299 Editor::get_y_origin () const
4301 return vertical_adjustment.get_value ();
4304 /** Queue up a change to the viewport x origin.
4305 * @param sample New x origin.
4308 Editor::reset_x_origin (samplepos_t sample)
4310 pending_visual_change.add (VisualChange::TimeOrigin);
4311 pending_visual_change.time_origin = sample;
4312 ensure_visual_change_idle_handler ();
4316 Editor::reset_y_origin (double y)
4318 pending_visual_change.add (VisualChange::YOrigin);
4319 pending_visual_change.y_origin = y;
4320 ensure_visual_change_idle_handler ();
4324 Editor::reset_zoom (samplecnt_t spp)
4326 if (spp == samples_per_pixel) {
4330 pending_visual_change.add (VisualChange::ZoomLevel);
4331 pending_visual_change.samples_per_pixel = spp;
4332 ensure_visual_change_idle_handler ();
4336 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4338 reset_x_origin (sample);
4341 if (!no_save_visual) {
4342 undo_visual_stack.push_back (current_visual_state(false));
4346 Editor::VisualState::VisualState (bool with_tracks)
4347 : gui_state (with_tracks ? new GUIObjectState : 0)
4351 Editor::VisualState::~VisualState ()
4356 Editor::VisualState*
4357 Editor::current_visual_state (bool with_tracks)
4359 VisualState* vs = new VisualState (with_tracks);
4360 vs->y_position = vertical_adjustment.get_value();
4361 vs->samples_per_pixel = samples_per_pixel;
4362 vs->_leftmost_sample = _leftmost_sample;
4363 vs->zoom_focus = zoom_focus;
4366 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4373 Editor::undo_visual_state ()
4375 if (undo_visual_stack.empty()) {
4379 VisualState* vs = undo_visual_stack.back();
4380 undo_visual_stack.pop_back();
4383 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4386 use_visual_state (*vs);
4391 Editor::redo_visual_state ()
4393 if (redo_visual_stack.empty()) {
4397 VisualState* vs = redo_visual_stack.back();
4398 redo_visual_stack.pop_back();
4400 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4401 // why do we check here?
4402 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4405 use_visual_state (*vs);
4410 Editor::swap_visual_state ()
4412 if (undo_visual_stack.empty()) {
4413 redo_visual_state ();
4415 undo_visual_state ();
4420 Editor::use_visual_state (VisualState& vs)
4422 PBD::Unwinder<bool> nsv (no_save_visual, true);
4423 DisplaySuspender ds;
4425 vertical_adjustment.set_value (vs.y_position);
4427 set_zoom_focus (vs.zoom_focus);
4428 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4431 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4433 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4434 (*i)->clear_property_cache();
4435 (*i)->reset_visual_state ();
4439 _routes->update_visibility ();
4442 /** This is the core function that controls the zoom level of the canvas. It is called
4443 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4444 * @param spp new number of samples per pixel
4447 Editor::set_samples_per_pixel (samplecnt_t spp)
4453 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4454 const samplecnt_t lots_of_pixels = 4000;
4456 /* if the zoom level is greater than what you'd get trying to display 3
4457 * days of audio on a really big screen, then it's too big.
4460 if (spp * lots_of_pixels > three_days) {
4464 samples_per_pixel = spp;
4468 Editor::on_samples_per_pixel_changed ()
4470 bool const showing_time_selection = selection->time.length() > 0;
4472 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4473 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4474 (*i)->reshow_selection (selection->time);
4478 ZoomChanged (); /* EMIT_SIGNAL */
4480 ArdourCanvas::GtkCanvasViewport* c;
4482 c = get_track_canvas();
4484 c->canvas()->zoomed ();
4487 if (playhead_cursor) {
4488 playhead_cursor->set_position (playhead_cursor->current_sample ());
4491 refresh_location_display();
4492 _summary->set_overlays_dirty ();
4494 update_marker_labels ();
4500 Editor::playhead_cursor_sample () const
4502 return playhead_cursor->current_sample();
4506 Editor::queue_visual_videotimeline_update ()
4508 pending_visual_change.add (VisualChange::VideoTimeline);
4509 ensure_visual_change_idle_handler ();
4513 Editor::ensure_visual_change_idle_handler ()
4515 if (pending_visual_change.idle_handler_id < 0) {
4516 // see comment in add_to_idle_resize above.
4517 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4518 pending_visual_change.being_handled = false;
4523 Editor::_idle_visual_changer (void* arg)
4525 return static_cast<Editor*>(arg)->idle_visual_changer ();
4529 Editor::pre_render ()
4531 visual_change_queued = false;
4533 if (pending_visual_change.pending != 0) {
4534 ensure_visual_change_idle_handler();
4539 Editor::idle_visual_changer ()
4541 pending_visual_change.idle_handler_id = -1;
4543 if (pending_visual_change.pending == 0) {
4547 /* set_horizontal_position() below (and maybe other calls) call
4548 gtk_main_iteration(), so it's possible that a signal will be handled
4549 half-way through this method. If this signal wants an
4550 idle_visual_changer we must schedule another one after this one, so
4551 mark the idle_handler_id as -1 here to allow that. Also make a note
4552 that we are doing the visual change, so that changes in response to
4553 super-rapid-screen-update can be dropped if we are still processing
4557 if (visual_change_queued) {
4561 pending_visual_change.being_handled = true;
4563 VisualChange vc = pending_visual_change;
4565 pending_visual_change.pending = (VisualChange::Type) 0;
4567 visual_changer (vc);
4569 pending_visual_change.being_handled = false;
4571 visual_change_queued = true;
4573 return 0; /* this is always a one-shot call */
4577 Editor::visual_changer (const VisualChange& vc)
4580 * Changed first so the correct horizontal canvas position is calculated in
4581 * Editor::set_horizontal_position
4583 if (vc.pending & VisualChange::ZoomLevel) {
4584 set_samples_per_pixel (vc.samples_per_pixel);
4587 if (vc.pending & VisualChange::TimeOrigin) {
4588 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4589 set_horizontal_position (new_time_origin);
4592 if (vc.pending & VisualChange::YOrigin) {
4593 vertical_adjustment.set_value (vc.y_origin);
4597 * Now the canvas is in the final state before render the canvas items that
4598 * support the Item::prepare_for_render interface can calculate the correct
4599 * item to visible canvas intersection.
4601 if (vc.pending & VisualChange::ZoomLevel) {
4602 on_samples_per_pixel_changed ();
4604 compute_fixed_ruler_scale ();
4606 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4607 update_tempo_based_rulers ();
4610 if (!(vc.pending & VisualChange::ZoomLevel)) {
4612 * If the canvas is not being zoomed then the canvas items will not change
4613 * and cause Item::prepare_for_render to be called so do it here manually.
4615 * Not ideal, but I can't think of a better solution atm.
4617 _track_canvas->prepare_for_render();
4620 // If we are only scrolling vertically there is no need to update these
4621 if (vc.pending != VisualChange::YOrigin) {
4622 update_fixed_rulers ();
4623 redisplay_grid (true);
4625 /* video frames & position need to be updated for zoom, horiz-scroll
4626 * and (explicitly) VisualChange::VideoTimeline.
4628 update_video_timeline();
4631 _summary->set_overlays_dirty ();
4634 struct EditorOrderTimeAxisSorter {
4635 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4636 return a->order () < b->order ();
4641 Editor::sort_track_selection (TrackViewList& sel)
4643 EditorOrderTimeAxisSorter cmp;
4648 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4651 samplepos_t where = 0;
4652 EditPoint ep = _edit_point;
4654 if (Profile->get_mixbus()) {
4655 if (ep == EditAtSelectedMarker) {
4656 ep = EditAtPlayhead;
4660 if (from_outside_canvas && (ep == EditAtMouse)) {
4661 ep = EditAtPlayhead;
4662 } else if (from_context_menu && (ep == EditAtMouse)) {
4663 return canvas_event_sample (&context_click_event, 0, 0);
4666 if (entered_marker) {
4667 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4668 return entered_marker->position();
4671 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4672 ep = EditAtSelectedMarker;
4675 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4676 ep = EditAtPlayhead;
4679 MusicSample snap_mf (0, 0);
4682 case EditAtPlayhead:
4683 if (_dragging_playhead && _control_scroll_target) {
4684 where = *_control_scroll_target;
4686 where = _session->audible_sample();
4688 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4691 case EditAtSelectedMarker:
4692 if (!selection->markers.empty()) {
4694 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4697 where = loc->start();
4701 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4709 if (!mouse_sample (where, ignored)) {
4710 /* XXX not right but what can we do ? */
4713 snap_mf.sample = where;
4715 where = snap_mf.sample;
4716 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4724 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4726 if (!_session) return;
4728 begin_reversible_command (cmd);
4732 if ((tll = transport_loop_location()) == 0) {
4733 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4734 XMLNode &before = _session->locations()->get_state();
4735 _session->locations()->add (loc, true);
4736 _session->set_auto_loop_location (loc);
4737 XMLNode &after = _session->locations()->get_state();
4738 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4740 XMLNode &before = tll->get_state();
4741 tll->set_hidden (false, this);
4742 tll->set (start, end);
4743 XMLNode &after = tll->get_state();
4744 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4747 commit_reversible_command ();
4751 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4753 if (!_session) return;
4755 begin_reversible_command (cmd);
4759 if ((tpl = transport_punch_location()) == 0) {
4760 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4761 XMLNode &before = _session->locations()->get_state();
4762 _session->locations()->add (loc, true);
4763 _session->set_auto_punch_location (loc);
4764 XMLNode &after = _session->locations()->get_state();
4765 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4767 XMLNode &before = tpl->get_state();
4768 tpl->set_hidden (false, this);
4769 tpl->set (start, end);
4770 XMLNode &after = tpl->get_state();
4771 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4774 commit_reversible_command ();
4777 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4778 * @param rs List to which found regions are added.
4779 * @param where Time to look at.
4780 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4783 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4785 const TrackViewList* tracks;
4788 tracks = &track_views;
4793 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4795 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4798 boost::shared_ptr<Track> tr;
4799 boost::shared_ptr<Playlist> pl;
4801 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4803 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4805 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4806 RegionView* rv = rtv->view()->find_view (*i);
4817 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4819 const TrackViewList* tracks;
4822 tracks = &track_views;
4827 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4828 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4830 boost::shared_ptr<Track> tr;
4831 boost::shared_ptr<Playlist> pl;
4833 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4835 boost::shared_ptr<RegionList> regions = pl->regions_touched (where, max_samplepos);
4837 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4839 RegionView* rv = rtv->view()->find_view (*i);
4850 /** Get regions using the following method:
4852 * Make a region list using:
4853 * (a) any selected regions
4854 * (b) the intersection of any selected tracks and the edit point(*)
4855 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4857 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4859 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4863 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4865 RegionSelection regions;
4867 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4868 regions.add (entered_regionview);
4870 regions = selection->regions;
4873 if ( regions.empty() ) {
4874 TrackViewList tracks = selection->tracks;
4876 if (!tracks.empty()) {
4877 /* no region selected or entered, but some selected tracks:
4878 * act on all regions on the selected tracks at the edit point
4880 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4881 get_regions_at(regions, where, tracks);
4888 /** Get regions using the following method:
4890 * Make a region list using:
4891 * (a) any selected regions
4892 * (b) the intersection of any selected tracks and the edit point(*)
4893 * (c) if neither exists, then whatever region is under the mouse
4895 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4897 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4900 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4902 RegionSelection regions;
4904 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4905 regions.add (entered_regionview);
4907 regions = selection->regions;
4910 if ( regions.empty() ) {
4911 TrackViewList tracks = selection->tracks;
4913 if (!tracks.empty()) {
4914 /* no region selected or entered, but some selected tracks:
4915 * act on all regions on the selected tracks at the edit point
4917 get_regions_at(regions, pos, tracks);
4924 /** Start with regions that are selected, or the entered regionview if none are selected.
4925 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4926 * of the regions that we started with.
4930 Editor::get_regions_from_selection_and_entered () const
4932 RegionSelection regions = selection->regions;
4934 if (regions.empty() && entered_regionview) {
4935 regions.add (entered_regionview);
4942 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4944 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4945 RouteTimeAxisView* rtav;
4947 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4948 boost::shared_ptr<Playlist> pl;
4949 std::vector<boost::shared_ptr<Region> > results;
4950 boost::shared_ptr<Track> tr;
4952 if ((tr = rtav->track()) == 0) {
4957 if ((pl = (tr->playlist())) != 0) {
4958 boost::shared_ptr<Region> r = pl->region_by_id (id);
4960 RegionView* rv = rtav->view()->find_view (r);
4962 regions.push_back (rv);
4971 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4974 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4975 MidiTimeAxisView* mtav;
4977 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4979 mtav->get_per_region_note_selection (selection);
4986 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4988 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4990 RouteTimeAxisView* tatv;
4992 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4994 boost::shared_ptr<Playlist> pl;
4995 vector<boost::shared_ptr<Region> > results;
4997 boost::shared_ptr<Track> tr;
4999 if ((tr = tatv->track()) == 0) {
5004 if ((pl = (tr->playlist())) != 0) {
5005 if (src_comparison) {
5006 pl->get_source_equivalent_regions (region, results);
5008 pl->get_region_list_equivalent_regions (region, results);
5012 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
5013 if ((marv = tatv->view()->find_view (*ir)) != 0) {
5014 regions.push_back (marv);
5023 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
5025 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5026 RouteTimeAxisView* tatv;
5027 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5028 if (!tatv->track()) {
5031 RegionView* marv = tatv->view()->find_view (region);
5041 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5043 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5044 RouteTimeAxisView* rtav;
5045 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5046 if (rtav->route() == route) {
5055 Editor::show_rhythm_ferret ()
5057 if (rhythm_ferret == 0) {
5058 rhythm_ferret = new RhythmFerret(*this);
5061 rhythm_ferret->set_session (_session);
5062 rhythm_ferret->show ();
5063 rhythm_ferret->present ();
5067 Editor::first_idle ()
5069 MessageDialog* dialog = 0;
5071 if (track_views.size() > 1) {
5072 Timers::TimerSuspender t;
5073 dialog = new MessageDialog (
5074 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5078 ARDOUR_UI::instance()->flush_pending (60);
5081 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5085 /* now that all regionviews should exist, setup region selection */
5089 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5090 /* this is cumulative: rs is NOT cleared each time */
5091 get_regionviews_by_id (*pr, rs);
5094 selection->set (rs);
5096 // first idle adds route children (automation tracks), so we need to redisplay here
5097 _routes->redisplay ();
5101 if (_session->undo_depth() == 0) {
5102 undo_action->set_sensitive(false);
5104 redo_action->set_sensitive(false);
5105 begin_selection_op_history ();
5111 Editor::_idle_resize (gpointer arg)
5113 return ((Editor*)arg)->idle_resize ();
5117 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5119 if (resize_idle_id < 0) {
5120 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5121 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5122 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5124 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5125 _pending_resize_amount = 0;
5128 /* make a note of the smallest resulting height, so that we can clamp the
5129 lower limit at TimeAxisView::hSmall */
5131 int32_t min_resulting = INT32_MAX;
5133 _pending_resize_amount += h;
5134 _pending_resize_view = view;
5136 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5138 if (selection->tracks.contains (_pending_resize_view)) {
5139 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5140 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5144 if (min_resulting < 0) {
5149 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5150 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5154 /** Handle pending resizing of tracks */
5156 Editor::idle_resize ()
5158 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5160 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5161 selection->tracks.contains (_pending_resize_view)) {
5163 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5164 if (*i != _pending_resize_view) {
5165 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5170 _pending_resize_amount = 0;
5171 _group_tabs->set_dirty ();
5172 resize_idle_id = -1;
5180 ENSURE_GUI_THREAD (*this, &Editor::located);
5183 playhead_cursor->set_position (_session->audible_sample ());
5184 if (_follow_playhead && !_pending_initial_locate) {
5185 reset_x_origin_to_follow_playhead ();
5189 _pending_locate_request = false;
5190 _pending_initial_locate = false;
5191 _last_update_time = 0;
5195 Editor::region_view_added (RegionView * rv)
5197 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5199 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5200 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5201 if (rv->region()->id () == (*rnote).first) {
5202 mrv->select_notes ((*rnote).second);
5203 selection->pending_midi_note_selection.erase(rnote);
5209 _summary->set_background_dirty ();
5211 mark_region_boundary_cache_dirty ();
5215 Editor::region_view_removed ()
5217 _summary->set_background_dirty ();
5219 mark_region_boundary_cache_dirty ();
5223 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5225 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5226 if ((*j)->stripable() == s) {
5235 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5237 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5238 if ((*j)->control() == c) {
5242 TimeAxisView::Children kids = (*j)->get_child_list ();
5244 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5245 if ((*k)->control() == c) {
5255 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5259 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5260 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5270 Editor::suspend_route_redisplay ()
5273 _routes->suspend_redisplay();
5278 Editor::resume_route_redisplay ()
5281 _routes->redisplay(); // queue redisplay
5282 _routes->resume_redisplay();
5287 Editor::add_vcas (VCAList& vlist)
5291 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5292 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5295 add_stripables (sl);
5299 Editor::add_routes (RouteList& rlist)
5303 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5307 add_stripables (sl);
5311 Editor::add_stripables (StripableList& sl)
5313 list<TimeAxisView*> new_views;
5314 boost::shared_ptr<VCA> v;
5315 boost::shared_ptr<Route> r;
5316 TrackViewList new_selection;
5317 bool from_scratch = (track_views.size() == 0);
5319 sl.sort (Stripable::Sorter());
5321 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5323 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5325 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5327 new_views.push_back (vtv);
5329 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5331 if (r->is_auditioner() || r->is_monitor()) {
5335 RouteTimeAxisView* rtv;
5336 DataType dt = r->input()->default_type();
5338 if (dt == ARDOUR::DataType::AUDIO) {
5339 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5341 } else if (dt == ARDOUR::DataType::MIDI) {
5342 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5345 throw unknown_type();
5348 new_views.push_back (rtv);
5349 track_views.push_back (rtv);
5350 new_selection.push_back (rtv);
5352 rtv->effective_gain_display ();
5354 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5355 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5359 if (new_views.size() > 0) {
5360 _routes->time_axis_views_added (new_views);
5361 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5364 /* note: !new_selection.empty() means that we got some routes rather
5368 if (!from_scratch && !new_selection.empty()) {
5369 selection->set (new_selection);
5370 begin_selection_op_history();
5373 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5374 show_editor_mixer (true);
5377 editor_list_button.set_sensitive (true);
5381 Editor::timeaxisview_deleted (TimeAxisView *tv)
5383 if (tv == entered_track) {
5387 if (_session && _session->deletion_in_progress()) {
5388 /* the situation is under control */
5392 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5394 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5396 _routes->route_removed (tv);
5398 TimeAxisView::Children c = tv->get_child_list ();
5399 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5400 if (entered_track == i->get()) {
5405 /* remove it from the list of track views */
5407 TrackViewList::iterator i;
5409 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5410 i = track_views.erase (i);
5413 /* update whatever the current mixer strip is displaying, if revelant */
5415 boost::shared_ptr<Route> route;
5418 route = rtav->route ();
5421 if (current_mixer_strip && current_mixer_strip->route() == route) {
5423 TimeAxisView* next_tv;
5425 if (track_views.empty()) {
5427 } else if (i == track_views.end()) {
5428 next_tv = track_views.front();
5433 // skip VCAs (cannot be selected, n/a in editor-mixer)
5434 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5435 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5436 next_tv = track_views.front();
5438 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5439 /* just in case: no master, only a VCA remains */
5445 set_selected_mixer_strip (*next_tv);
5447 /* make the editor mixer strip go away setting the
5448 * button to inactive (which also unticks the menu option)
5451 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5457 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5463 DisplaySuspender ds;
5464 PresentationInfo::ChangeSuspender cs;
5466 if (apply_to_selection) {
5467 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5469 TrackSelection::iterator j = i;
5472 hide_track_in_display (*i, false);
5477 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5479 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5480 // this will hide the mixer strip
5481 set_selected_mixer_strip (*tv);
5484 _routes->hide_track_in_display (*tv);
5489 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5494 _routes->show_track_in_display (*tv);
5495 if (move_into_view) {
5496 ensure_time_axis_view_is_visible (*tv, false);
5501 Editor::sync_track_view_list_and_routes ()
5503 track_views = TrackViewList (_routes->views ());
5505 _summary->set_background_dirty();
5506 _group_tabs->set_dirty ();
5508 return false; // do not call again (until needed)
5512 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5514 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5519 /** Find a StripableTimeAxisView by the ID of its stripable */
5520 StripableTimeAxisView*
5521 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5523 StripableTimeAxisView* v;
5525 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5526 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5527 if(v->stripable()->id() == id) {
5537 Editor::fit_route_group (RouteGroup *g)
5539 TrackViewList ts = axis_views_from_routes (g->route_list ());
5544 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5546 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5549 _session->cancel_audition ();
5553 if (_session->is_auditioning()) {
5554 _session->cancel_audition ();
5555 if (r == last_audition_region) {
5560 _session->audition_region (r);
5561 last_audition_region = r;
5566 Editor::hide_a_region (boost::shared_ptr<Region> r)
5568 r->set_hidden (true);
5572 Editor::show_a_region (boost::shared_ptr<Region> r)
5574 r->set_hidden (false);
5578 Editor::audition_region_from_region_list ()
5580 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5584 Editor::hide_region_from_region_list ()
5586 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5590 Editor::show_region_in_region_list ()
5592 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5596 Editor::step_edit_status_change (bool yn)
5599 start_step_editing ();
5601 stop_step_editing ();
5606 Editor::start_step_editing ()
5608 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5612 Editor::stop_step_editing ()
5614 step_edit_connection.disconnect ();
5618 Editor::check_step_edit ()
5620 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5621 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5623 mtv->check_step_edit ();
5627 return true; // do it again, till we stop
5631 Editor::scroll_press (Direction dir)
5633 ++_scroll_callbacks;
5635 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5636 /* delay the first auto-repeat */
5642 scroll_backward (1);
5650 scroll_up_one_track ();
5654 scroll_down_one_track ();
5658 /* do hacky auto-repeat */
5659 if (!_scroll_connection.connected ()) {
5661 _scroll_connection = Glib::signal_timeout().connect (
5662 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5665 _scroll_callbacks = 0;
5672 Editor::scroll_release ()
5674 _scroll_connection.disconnect ();
5677 /** Queue a change for the Editor viewport x origin to follow the playhead */
5679 Editor::reset_x_origin_to_follow_playhead ()
5681 samplepos_t const sample = playhead_cursor->current_sample ();
5683 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5685 if (_session->transport_speed() < 0) {
5687 if (sample > (current_page_samples() / 2)) {
5688 center_screen (sample-(current_page_samples()/2));
5690 center_screen (current_page_samples()/2);
5697 if (sample < _leftmost_sample) {
5699 if (_session->transport_rolling()) {
5700 /* rolling; end up with the playhead at the right of the page */
5701 l = sample - current_page_samples ();
5703 /* not rolling: end up with the playhead 1/4 of the way along the page */
5704 l = sample - current_page_samples() / 4;
5708 if (_session->transport_rolling()) {
5709 /* rolling: end up with the playhead on the left of the page */
5712 /* not rolling: end up with the playhead 3/4 of the way along the page */
5713 l = sample - 3 * current_page_samples() / 4;
5721 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5727 Editor::super_rapid_screen_update ()
5729 if (!_session || !_session->engine().running()) {
5733 /* METERING / MIXER STRIPS */
5735 /* update track meters, if required */
5736 if (contents().is_mapped() && meters_running) {
5737 RouteTimeAxisView* rtv;
5738 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5739 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5740 rtv->fast_update ();
5745 /* and any current mixer strip */
5746 if (current_mixer_strip) {
5747 current_mixer_strip->fast_update ();
5750 bool latent_locate = false;
5751 samplepos_t sample = _session->audible_sample (&latent_locate);
5752 const int64_t now = g_get_monotonic_time ();
5755 if (_session->exporting ()) {
5756 /* freewheel/export may be faster or slower than transport_speed() / SR.
5757 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5759 _last_update_time = 0;
5762 if (_session->transport_stopped()) {
5763 //we are stopped. don't interpolate the playhead position; just set it
5764 _last_update_time = 0;
5767 if (_last_update_time > 0) {
5768 /* interpolate and smoothen playhead position */
5769 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5770 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5771 err = sample - guess;
5773 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5774 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5777 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5779 err, _err_screen_engine);
5784 _err_screen_engine = 0;
5787 if (err > 8192 || latent_locate) {
5788 // in case of x-runs or freewheeling
5789 _last_update_time = 0;
5790 sample = _session->audible_sample ();
5792 _last_update_time = now;
5795 //snapped cursor stuff ( the snapped_cursor shows where an operation is going to occur )
5797 MusicSample where (sample, 0);
5798 if ( !UIConfiguration::instance().get_show_snapped_cursor() ) {
5799 snapped_cursor->hide ();
5800 } else if ( _edit_point == EditAtPlayhead && !_dragging_playhead) {
5801 snap_to (where); // can't use snap_to_with_modifier?
5802 snapped_cursor->set_position (where.sample);
5803 snapped_cursor->show ();
5804 } else if ( _edit_point == EditAtSelectedMarker ) {
5805 //NOTE: I don't think EditAtSelectedMarker should snap. they are what they are.
5806 //however, the current editing code -does- snap so I'll draw it that way for now.
5807 if ( !selection->markers.empty() ) {
5808 MusicSample ms (selection->markers.front()->position(), 0);
5809 snap_to (ms); // should use snap_to_with_modifier?
5810 snapped_cursor->set_position ( ms.sample );
5811 snapped_cursor->show ();
5813 } else if (mouse_sample (where.sample, ignored)) { //cursor is in the editing canvas. show it.
5814 snapped_cursor->show ();
5815 } else { //mouse is out of the editing canvas. hide the snapped_cursor
5816 snapped_cursor->hide ();
5819 /* There are a few reasons why we might not update the playhead / viewport stuff:
5821 * 1. we don't update things when there's a pending locate request, otherwise
5822 * when the editor requests a locate there is a chance that this method
5823 * will move the playhead before the locate request is processed, causing
5825 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5826 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5828 if (_pending_locate_request) {
5829 _last_update_time = 0;
5833 if (_dragging_playhead) {
5834 _last_update_time = 0;
5838 if (playhead_cursor->current_sample () == sample) {
5842 playhead_cursor->set_position (sample);
5844 if (_session->requested_return_sample() >= 0) {
5845 _last_update_time = 0;
5849 if (!_follow_playhead || pending_visual_change.being_handled) {
5850 /* We only do this if we aren't already
5851 * handling a visual change (ie if
5852 * pending_visual_change.being_handled is
5853 * false) so that these requests don't stack
5854 * up there are too many of them to handle in
5860 if (!_stationary_playhead) {
5861 reset_x_origin_to_follow_playhead ();
5863 samplepos_t const sample = playhead_cursor->current_sample ();
5864 double target = ((double)sample - (double)current_page_samples() / 2.0);
5865 if (target <= 0.0) {
5868 // compare to EditorCursor::set_position()
5869 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5870 double const new_pos = sample_to_pixel_unrounded (target);
5871 if (rint (new_pos) != rint (old_pos)) {
5872 reset_x_origin (pixel_to_sample (new_pos));
5879 Editor::session_going_away ()
5881 _have_idled = false;
5883 _session_connections.drop_connections ();
5885 super_rapid_screen_update_connection.disconnect ();
5887 selection->clear ();
5888 cut_buffer->clear ();
5890 clicked_regionview = 0;
5891 clicked_axisview = 0;
5892 clicked_routeview = 0;
5893 entered_regionview = 0;
5895 _last_update_time = 0;
5898 playhead_cursor->hide ();
5900 /* rip everything out of the list displays */
5904 _route_groups->clear ();
5906 /* do this first so that deleting a track doesn't reset cms to null
5907 and thus cause a leak.
5910 if (current_mixer_strip) {
5911 if (current_mixer_strip->get_parent() != 0) {
5912 global_hpacker.remove (*current_mixer_strip);
5914 delete current_mixer_strip;
5915 current_mixer_strip = 0;
5918 /* delete all trackviews */
5920 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5923 track_views.clear ();
5925 nudge_clock->set_session (0);
5927 editor_list_button.set_active(false);
5928 editor_list_button.set_sensitive(false);
5930 /* clear tempo/meter rulers */
5931 remove_metric_marks ();
5932 clear_marker_display ();
5938 stop_step_editing ();
5942 /* get rid of any existing editor mixer strip */
5944 WindowTitle title(Glib::get_application_name());
5945 title += _("Editor");
5947 own_window()->set_title (title.get_string());
5950 SessionHandlePtr::session_going_away ();
5954 Editor::trigger_script (int i)
5956 LuaInstance::instance()-> call_action (i);
5960 Editor::show_editor_list (bool yn)
5963 _editor_list_vbox.show ();
5965 _editor_list_vbox.hide ();
5970 Editor::change_region_layering_order (bool from_context_menu)
5972 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5974 if (!clicked_routeview) {
5975 if (layering_order_editor) {
5976 layering_order_editor->hide ();
5981 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5987 boost::shared_ptr<Playlist> pl = track->playlist();
5993 if (layering_order_editor == 0) {
5994 layering_order_editor = new RegionLayeringOrderEditor (*this);
5997 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5998 layering_order_editor->maybe_present ();
6002 Editor::update_region_layering_order_editor ()
6004 if (layering_order_editor && layering_order_editor->is_visible ()) {
6005 change_region_layering_order (true);
6010 Editor::setup_fade_images ()
6012 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
6013 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
6014 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
6015 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
6016 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
6018 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
6019 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
6020 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
6021 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
6022 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
6026 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
6028 Editor::action_menu_item (std::string const & name)
6030 Glib::RefPtr<Action> a = editor_actions->get_action (name);
6033 return *manage (a->create_menu_item ());
6037 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6039 EventBox* b = manage (new EventBox);
6040 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6041 Label* l = manage (new Label (name));
6045 _the_notebook.append_page (widget, *b);
6049 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6051 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6052 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6055 if (ev->type == GDK_2BUTTON_PRESS) {
6057 /* double-click on a notebook tab shrinks or expands the notebook */
6059 if (_notebook_shrunk) {
6060 if (pre_notebook_shrink_pane_width) {
6061 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6063 _notebook_shrunk = false;
6065 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6067 /* this expands the LHS of the edit pane to cover the notebook
6068 PAGE but leaves the tabs visible.
6070 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6071 _notebook_shrunk = true;
6079 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6081 using namespace Menu_Helpers;
6083 MenuList& items = _control_point_context_menu.items ();
6086 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6087 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6088 if (!can_remove_control_point (item)) {
6089 items.back().set_sensitive (false);
6092 _control_point_context_menu.popup (event->button.button, event->button.time);
6096 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6098 using namespace Menu_Helpers;
6100 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6105 /* We need to get the selection here and pass it to the operations, since
6106 popping up the menu will cause a region leave event which clears
6107 entered_regionview. */
6109 MidiRegionView& mrv = note->region_view();
6110 const RegionSelection rs = get_regions_from_selection_and_entered ();
6111 const uint32_t sel_size = mrv.selection_size ();
6113 MenuList& items = _note_context_menu.items();
6117 items.push_back(MenuElem(_("Delete"),
6118 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6121 items.push_back(MenuElem(_("Edit..."),
6122 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6123 if (sel_size != 1) {
6124 items.back().set_sensitive (false);
6127 items.push_back(MenuElem(_("Transpose..."),
6128 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6131 items.push_back(MenuElem(_("Legatize"),
6132 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6134 items.back().set_sensitive (false);
6137 items.push_back(MenuElem(_("Quantize..."),
6138 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6140 items.push_back(MenuElem(_("Remove Overlap"),
6141 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6143 items.back().set_sensitive (false);
6146 items.push_back(MenuElem(_("Transform..."),
6147 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6149 _note_context_menu.popup (event->button.button, event->button.time);
6153 Editor::zoom_vertical_modifier_released()
6155 _stepping_axis_view = 0;
6159 Editor::ui_parameter_changed (string parameter)
6161 if (parameter == "icon-set") {
6162 while (!_cursor_stack.empty()) {
6163 _cursor_stack.pop_back();
6165 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6166 _cursor_stack.push_back(_cursors->grabber);
6167 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6168 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6170 } else if (parameter == "draggable-playhead") {
6171 if (_verbose_cursor) {
6172 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6178 Editor::use_own_window (bool and_fill_it)
6180 bool new_window = !own_window();
6182 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6184 if (win && new_window) {
6185 win->set_name ("EditorWindow");
6187 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6189 // win->signal_realize().connect (*this, &Editor::on_realize);
6190 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6191 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6192 win->set_data ("ardour-bindings", bindings);
6197 DisplaySuspender ds;
6198 contents().show_all ();
6200 /* XXX: this is a bit unfortunate; it would probably
6201 be nicer if we could just call show () above rather
6202 than needing the show_all ()
6205 /* re-hide stuff if necessary */
6206 editor_list_button_toggled ();
6207 parameter_changed ("show-summary");
6208 parameter_changed ("show-group-tabs");
6209 parameter_changed ("show-zoom-tools");
6211 /* now reset all audio_time_axis heights, because widgets might need
6217 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6218 tv = (static_cast<TimeAxisView*>(*i));
6219 tv->reset_height ();
6222 if (current_mixer_strip) {
6223 current_mixer_strip->hide_things ();
6224 current_mixer_strip->parameter_changed ("mixer-element-visibility");