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 25 // 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 /* labels for the time bars */
628 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
630 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
632 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
634 bottom_hbox.set_border_width (2);
635 bottom_hbox.set_spacing (3);
637 PresentationInfo::Change.connect (*this, MISSING_INVALIDATOR, boost::bind (&Editor::presentation_info_changed, this, _1), gui_context());
639 _route_groups = new EditorRouteGroups (this);
640 _routes = new EditorRoutes (this);
641 _regions = new EditorRegions (this);
642 _snapshots = new EditorSnapshots (this);
643 _locations = new EditorLocations (this);
644 _time_info_box = new TimeInfoBox ("EditorTimeInfo", true);
646 /* these are static location signals */
648 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
649 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
650 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
652 add_notebook_page (_("Regions"), _regions->widget ());
653 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
654 add_notebook_page (_("Snapshots"), _snapshots->widget ());
655 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
656 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
658 _the_notebook.set_show_tabs (true);
659 _the_notebook.set_scrollable (true);
660 _the_notebook.popup_disable ();
661 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
662 _the_notebook.show_all ();
664 _notebook_shrunk = false;
667 /* Pick up some settings we need to cache, early */
669 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
672 settings->get_property ("notebook-shrunk", _notebook_shrunk);
675 editor_summary_pane.set_check_divider_position (true);
676 editor_summary_pane.add (edit_packer);
678 Button* summary_arrow_left = manage (new Button);
679 summary_arrow_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
680 summary_arrow_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
681 summary_arrow_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
683 Button* summary_arrow_right = manage (new Button);
684 summary_arrow_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
685 summary_arrow_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
686 summary_arrow_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
688 VBox* summary_arrows_left = manage (new VBox);
689 summary_arrows_left->pack_start (*summary_arrow_left);
691 VBox* summary_arrows_right = manage (new VBox);
692 summary_arrows_right->pack_start (*summary_arrow_right);
694 Frame* summary_sample = manage (new Frame);
695 summary_sample->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
697 summary_sample->add (*_summary);
698 summary_sample->show ();
700 _summary_hbox.pack_start (*summary_arrows_left, false, false);
701 _summary_hbox.pack_start (*summary_sample, true, true);
702 _summary_hbox.pack_start (*summary_arrows_right, false, false);
704 if (!ARDOUR::Profile->get_trx()) {
705 editor_summary_pane.add (_summary_hbox);
708 edit_pane.set_check_divider_position (true);
709 edit_pane.add (editor_summary_pane);
710 if (!ARDOUR::Profile->get_trx()) {
711 _editor_list_vbox.pack_start (*_time_info_box, false, false, 0);
712 _editor_list_vbox.pack_start (_the_notebook);
713 edit_pane.add (_editor_list_vbox);
714 edit_pane.set_child_minsize (_editor_list_vbox, 30); /* rough guess at width of notebook tabs */
717 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
718 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
721 if (!settings || !settings->get_property ("edit-horizontal-pane-pos", fract) || fract > 1.0) {
722 /* initial allocation is 90% to canvas, 10% to notebook */
725 edit_pane.set_divider (0, fract);
727 if (!settings || !settings->get_property ("edit-vertical-pane-pos", fract) || fract > 1.0) {
728 /* initial allocation is 90% to canvas, 10% to summary */
731 editor_summary_pane.set_divider (0, fract);
733 global_vpacker.set_spacing (2);
734 global_vpacker.set_border_width (0);
736 //the next three EventBoxes provide the ability for their child widgets to have a background color. That is all.
738 Gtk::EventBox* ebox = manage (new Gtk::EventBox); //a themeable box
739 ebox->set_name("EditorWindow");
740 ebox->add (toolbar_hbox);
742 Gtk::EventBox* epane_box = manage (new EventBoxExt); //a themeable box
743 epane_box->set_name("EditorWindow");
744 epane_box->add (edit_pane);
746 Gtk::EventBox* epane_box2 = manage (new EventBoxExt); //a themeable box
747 epane_box2->set_name("EditorWindow");
748 epane_box2->add (global_vpacker);
750 global_vpacker.pack_start (*ebox, false, false);
751 global_vpacker.pack_start (*epane_box, true, true);
752 global_hpacker.pack_start (*epane_box2, true, true);
754 /* need to show the "contents" widget so that notebook will show if tab is switched to
757 global_hpacker.show ();
759 /* register actions now so that set_state() can find them and set toggles/checks etc */
766 _playlist_selector = new PlaylistSelector();
767 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
769 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
773 nudge_forward_button.set_name ("nudge button");
774 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
776 nudge_backward_button.set_name ("nudge button");
777 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
779 fade_context_menu.set_name ("ArdourContextMenu");
781 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
783 /* allow external control surfaces/protocols to do various things */
785 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
786 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
787 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
788 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
789 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
790 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
791 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
792 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
793 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
794 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
795 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
796 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
797 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
798 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
800 ControlProtocol::AddStripableToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
801 ControlProtocol::RemoveStripableFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
802 ControlProtocol::SetStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
803 ControlProtocol::ToggleStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
804 ControlProtocol::ClearStripableSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
806 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
810 ARDOUR_UI::instance()->Escape.connect (*this, invalidator (*this), boost::bind (&Editor::escape, this), gui_context());
812 /* problematic: has to return a value and thus cannot be x-thread */
814 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
816 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
817 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
819 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
821 _ignore_region_action = false;
822 _last_region_menu_was_main = false;
823 _popup_region_menu_item = 0;
825 _show_marker_lines = false;
827 /* Button bindings */
829 button_bindings = new Bindings ("editor-mouse");
831 XMLNode* node = button_settings();
833 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
834 button_bindings->load_operation (**i);
840 /* grab current parameter state */
841 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
842 UIConfiguration::instance().map_parameters (pc);
844 setup_fade_images ();
846 set_grid_to (GridTypeNone);
853 delete button_bindings;
855 delete _route_groups;
856 delete _track_canvas_viewport;
859 delete _verbose_cursor;
860 delete quantize_dialog;
866 delete _playlist_selector;
867 delete _time_info_box;
872 LuaInstance::destroy_instance ();
874 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
877 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_in_images.begin(); i != _xfade_in_images.end (); ++i) {
880 for (std::map<ARDOUR::FadeShape, Gtk::Image*>::const_iterator i = _xfade_out_images.begin(); i != _xfade_out_images.end (); ++i) {
886 Editor::button_settings () const
888 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
889 XMLNode* node = find_named_node (*settings, X_("Buttons"));
892 node = new XMLNode (X_("Buttons"));
899 Editor::get_smart_mode () const
901 return ((current_mouse_mode() == MouseObject) && smart_mode_action->get_active());
905 Editor::catch_vanishing_regionview (RegionView *rv)
907 /* note: the selection will take care of the vanishing
908 audioregionview by itself.
911 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
915 if (clicked_regionview == rv) {
916 clicked_regionview = 0;
919 if (entered_regionview == rv) {
920 set_entered_regionview (0);
923 if (!_all_region_actions_sensitized) {
924 sensitize_all_region_actions (true);
929 Editor::set_entered_regionview (RegionView* rv)
931 if (rv == entered_regionview) {
935 if (entered_regionview) {
936 entered_regionview->exited ();
939 entered_regionview = rv;
941 if (entered_regionview != 0) {
942 entered_regionview->entered ();
945 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
946 /* This RegionView entry might have changed what region actions
947 are allowed, so sensitize them all in case a key is pressed.
949 sensitize_all_region_actions (true);
954 Editor::set_entered_track (TimeAxisView* tav)
957 entered_track->exited ();
963 entered_track->entered ();
968 Editor::instant_save ()
970 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
975 _session->add_instant_xml(get_state());
977 Config->add_instant_xml(get_state());
982 Editor::control_vertical_zoom_in_all ()
984 tav_zoom_smooth (false, true);
988 Editor::control_vertical_zoom_out_all ()
990 tav_zoom_smooth (true, true);
994 Editor::control_vertical_zoom_in_selected ()
996 tav_zoom_smooth (false, false);
1000 Editor::control_vertical_zoom_out_selected ()
1002 tav_zoom_smooth (true, false);
1006 Editor::control_view (uint32_t view)
1008 goto_visual_state (view);
1012 Editor::control_unselect ()
1014 selection->clear_tracks ();
1018 Editor::control_select (boost::shared_ptr<Stripable> s, Selection::Operation op)
1020 TimeAxisView* tav = time_axis_view_from_stripable (s);
1024 case Selection::Add:
1025 selection->add (tav);
1027 case Selection::Toggle:
1028 selection->toggle (tav);
1030 case Selection::Extend:
1032 case Selection::Set:
1033 selection->set (tav);
1037 selection->clear_tracks ();
1042 Editor::control_step_tracks_up ()
1044 scroll_tracks_up_line ();
1048 Editor::control_step_tracks_down ()
1050 scroll_tracks_down_line ();
1054 Editor::control_scroll (float fraction)
1056 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1062 double step = fraction * current_page_samples();
1065 _control_scroll_target is an optional<T>
1067 it acts like a pointer to an samplepos_t, with
1068 a operator conversion to boolean to check
1069 that it has a value could possibly use
1070 playhead_cursor->current_sample to store the
1071 value and a boolean in the class to know
1072 when it's out of date
1075 if (!_control_scroll_target) {
1076 _control_scroll_target = _session->transport_sample();
1077 _dragging_playhead = true;
1080 if ((fraction < 0.0f) && (*_control_scroll_target <= (samplepos_t) fabs(step))) {
1081 *_control_scroll_target = 0;
1082 } else if ((fraction > 0.0f) && (max_samplepos - *_control_scroll_target < step)) {
1083 *_control_scroll_target = max_samplepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1085 *_control_scroll_target += (samplepos_t) trunc (step);
1088 /* move visuals, we'll catch up with it later */
1090 playhead_cursor->set_position (*_control_scroll_target);
1091 UpdateAllTransportClocks (*_control_scroll_target);
1093 if (*_control_scroll_target > (current_page_samples() / 2)) {
1094 /* try to center PH in window */
1095 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1101 Now we do a timeout to actually bring the session to the right place
1102 according to the playhead. This is to avoid reading disk buffers on every
1103 call to control_scroll, which is driven by ScrollTimeline and therefore
1104 probably by a control surface wheel which can generate lots of events.
1106 /* cancel the existing timeout */
1108 control_scroll_connection.disconnect ();
1110 /* add the next timeout */
1112 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1116 Editor::deferred_control_scroll (samplepos_t /*target*/)
1118 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1119 // reset for next stream
1120 _control_scroll_target = boost::none;
1121 _dragging_playhead = false;
1126 Editor::access_action (const std::string& action_group, const std::string& action_item)
1132 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1135 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1143 Editor::set_toggleaction (const std::string& action_group, const std::string& action_item, bool s)
1145 ActionManager::set_toggleaction_state (action_group.c_str(), action_item.c_str(), s);
1149 Editor::on_realize ()
1153 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1154 start_lock_event_timing ();
1159 Editor::start_lock_event_timing ()
1161 /* check if we should lock the GUI every 30 seconds */
1163 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1167 Editor::generic_event_handler (GdkEvent* ev)
1170 case GDK_BUTTON_PRESS:
1171 case GDK_BUTTON_RELEASE:
1172 case GDK_MOTION_NOTIFY:
1174 case GDK_KEY_RELEASE:
1175 if (contents().is_mapped()) {
1176 gettimeofday (&last_event_time, 0);
1180 case GDK_LEAVE_NOTIFY:
1181 switch (ev->crossing.detail) {
1182 case GDK_NOTIFY_UNKNOWN:
1183 case GDK_NOTIFY_INFERIOR:
1184 case GDK_NOTIFY_ANCESTOR:
1186 case GDK_NOTIFY_VIRTUAL:
1187 case GDK_NOTIFY_NONLINEAR:
1188 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1189 /* leaving window, so reset focus, thus ending any and
1190 all text entry operations.
1192 ARDOUR_UI::instance()->reset_focus (&contents());
1205 Editor::lock_timeout_callback ()
1207 struct timeval now, delta;
1209 gettimeofday (&now, 0);
1211 timersub (&now, &last_event_time, &delta);
1213 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1215 /* don't call again. Returning false will effectively
1216 disconnect us from the timer callback.
1218 unlock() will call start_lock_event_timing() to get things
1228 Editor::map_position_change (samplepos_t sample)
1230 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, sample)
1232 if (_session == 0) {
1236 if (_follow_playhead) {
1237 center_screen (sample);
1240 playhead_cursor->set_position (sample);
1244 Editor::center_screen (samplepos_t sample)
1246 samplecnt_t const page = _visible_canvas_width * samples_per_pixel;
1248 /* if we're off the page, then scroll.
1251 if (sample < _leftmost_sample || sample >= _leftmost_sample + page) {
1252 center_screen_internal (sample, page);
1257 Editor::center_screen_internal (samplepos_t sample, float page)
1261 if (sample > page) {
1262 sample -= (samplepos_t) page;
1267 reset_x_origin (sample);
1272 Editor::update_title ()
1274 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1276 if (!own_window()) {
1281 bool dirty = _session->dirty();
1283 string session_name;
1285 if (_session->snap_name() != _session->name()) {
1286 session_name = _session->snap_name();
1288 session_name = _session->name();
1292 session_name = "*" + session_name;
1295 WindowTitle title(session_name);
1296 title += S_("Window|Editor");
1297 title += Glib::get_application_name();
1298 own_window()->set_title (title.get_string());
1300 /* ::session_going_away() will have taken care of it */
1305 Editor::set_session (Session *t)
1307 SessionHandlePtr::set_session (t);
1313 //initialize _leftmost_sample to the extents of the session
1314 //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
1315 _leftmost_sample = session_gui_extents().first;
1317 _playlist_selector->set_session (_session);
1318 nudge_clock->set_session (_session);
1319 _summary->set_session (_session);
1320 _group_tabs->set_session (_session);
1321 _route_groups->set_session (_session);
1322 _regions->set_session (_session);
1323 _snapshots->set_session (_session);
1324 _routes->set_session (_session);
1325 _locations->set_session (_session);
1326 _time_info_box->set_session (_session);
1328 if (rhythm_ferret) {
1329 rhythm_ferret->set_session (_session);
1332 if (analysis_window) {
1333 analysis_window->set_session (_session);
1337 sfbrowser->set_session (_session);
1340 compute_fixed_ruler_scale ();
1342 /* Make sure we have auto loop and auto punch ranges */
1344 Location* loc = _session->locations()->auto_loop_location();
1346 loc->set_name (_("Loop"));
1349 loc = _session->locations()->auto_punch_location();
1352 loc->set_name (_("Punch"));
1355 refresh_location_display ();
1357 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1358 the selected Marker; this needs the LocationMarker list to be available.
1360 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1361 set_state (*node, Stateful::loading_state_version);
1363 /* catch up on selection state, etc. */
1366 sc.add (Properties::selected);
1367 presentation_info_changed (sc);
1369 /* catch up with the playhead */
1371 _session->request_locate (playhead_cursor->current_sample ());
1372 _pending_initial_locate = true;
1376 /* These signals can all be emitted by a non-GUI thread. Therefore the
1377 handlers for them must not attempt to directly interact with the GUI,
1378 but use PBD::Signal<T>::connect() which accepts an event loop
1379 ("context") where the handler will be asked to run.
1382 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1383 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1384 _session->TransportLooped.connect (_session_connections, invalidator (*this), boost::bind (&Editor::transport_looped, this), gui_context());
1385 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1386 _session->vca_manager().VCAAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_vcas, this, _1), gui_context());
1387 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1388 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1389 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1390 _session->tempo_map().MetricPositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempometric_position_changed, this, _1), gui_context());
1391 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1392 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1393 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1394 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1395 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1396 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1397 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1399 playhead_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1400 playhead_cursor->show ();
1402 snapped_cursor->track_canvas_item().reparent ((ArdourCanvas::Item*) get_cursor_scroll_group());
1403 snapped_cursor->set_color (UIConfiguration::instance().color ("edit point"));
1404 snapped_cursor->show ();
1406 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1407 Config->map_parameters (pc);
1408 _session->config.map_parameters (pc);
1410 restore_ruler_visibility ();
1411 //tempo_map_changed (PropertyChange (0));
1412 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1414 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1415 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1418 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1419 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1422 /* register for undo history */
1423 _session->register_with_memento_command_factory(id(), this);
1424 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1426 LuaInstance::instance()->set_session(_session);
1428 start_updating_meters ();
1432 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1434 using namespace Menu_Helpers;
1436 void (Editor::*emf)(FadeShape);
1437 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1440 images = &_xfade_in_images;
1441 emf = &Editor::set_fade_in_shape;
1443 images = &_xfade_out_images;
1444 emf = &Editor::set_fade_out_shape;
1449 _("Linear (for highly correlated material)"),
1450 *(*images)[FadeLinear],
1451 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1455 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1459 _("Constant power"),
1460 *(*images)[FadeConstantPower],
1461 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1464 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1469 *(*images)[FadeSymmetric],
1470 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *(*images)[FadeSlow],
1480 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 *(*images)[FadeFast],
1489 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 /** Pop up a context menu for when the user clicks on a start crossfade */
1497 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1499 using namespace Menu_Helpers;
1500 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1505 MenuList& items (xfade_in_context_menu.items());
1508 if (arv->audio_region()->fade_in_active()) {
1509 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1511 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1514 items.push_back (SeparatorElem());
1515 fill_xfade_menu (items, true);
1517 xfade_in_context_menu.popup (button, time);
1520 /** Pop up a context menu for when the user clicks on an end crossfade */
1522 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1524 using namespace Menu_Helpers;
1525 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1530 MenuList& items (xfade_out_context_menu.items());
1533 if (arv->audio_region()->fade_out_active()) {
1534 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1536 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1539 items.push_back (SeparatorElem());
1540 fill_xfade_menu (items, false);
1542 xfade_out_context_menu.popup (button, time);
1546 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1548 using namespace Menu_Helpers;
1549 Menu* (Editor::*build_menu_function)();
1552 switch (item_type) {
1554 case RegionViewName:
1555 case RegionViewNameHighlight:
1556 case LeftFrameHandle:
1557 case RightFrameHandle:
1558 if (with_selection) {
1559 build_menu_function = &Editor::build_track_selection_context_menu;
1561 build_menu_function = &Editor::build_track_region_context_menu;
1566 if (with_selection) {
1567 build_menu_function = &Editor::build_track_selection_context_menu;
1569 build_menu_function = &Editor::build_track_context_menu;
1574 if (clicked_routeview->track()) {
1575 build_menu_function = &Editor::build_track_context_menu;
1577 build_menu_function = &Editor::build_track_bus_context_menu;
1582 /* probably shouldn't happen but if it does, we don't care */
1586 menu = (this->*build_menu_function)();
1587 menu->set_name ("ArdourContextMenu");
1589 /* now handle specific situations */
1591 switch (item_type) {
1593 case RegionViewName:
1594 case RegionViewNameHighlight:
1595 case LeftFrameHandle:
1596 case RightFrameHandle:
1597 if (!with_selection) {
1598 if (region_edit_menu_split_item) {
1599 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1600 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1602 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1605 if (region_edit_menu_split_multichannel_item) {
1606 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1607 region_edit_menu_split_multichannel_item->set_sensitive (true);
1609 region_edit_menu_split_multichannel_item->set_sensitive (false);
1622 /* probably shouldn't happen but if it does, we don't care */
1626 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1628 /* Bounce to disk */
1630 using namespace Menu_Helpers;
1631 MenuList& edit_items = menu->items();
1633 edit_items.push_back (SeparatorElem());
1635 switch (clicked_routeview->audio_track()->freeze_state()) {
1636 case AudioTrack::NoFreeze:
1637 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1640 case AudioTrack::Frozen:
1641 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1644 case AudioTrack::UnFrozen:
1645 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1651 if (item_type == StreamItem && clicked_routeview) {
1652 clicked_routeview->build_underlay_menu(menu);
1655 /* When the region menu is opened, we setup the actions so that they look right
1658 sensitize_the_right_region_actions (false);
1659 _last_region_menu_was_main = false;
1661 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1662 menu->popup (button, time);
1666 Editor::build_track_context_menu ()
1668 using namespace Menu_Helpers;
1670 MenuList& edit_items = track_context_menu.items();
1673 add_dstream_context_items (edit_items);
1674 return &track_context_menu;
1678 Editor::build_track_bus_context_menu ()
1680 using namespace Menu_Helpers;
1682 MenuList& edit_items = track_context_menu.items();
1685 add_bus_context_items (edit_items);
1686 return &track_context_menu;
1690 Editor::build_track_region_context_menu ()
1692 using namespace Menu_Helpers;
1693 MenuList& edit_items = track_region_context_menu.items();
1696 /* we've just cleared the track region context menu, so the menu that these
1697 two items were on will have disappeared; stop them dangling.
1699 region_edit_menu_split_item = 0;
1700 region_edit_menu_split_multichannel_item = 0;
1702 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1705 boost::shared_ptr<Track> tr;
1706 boost::shared_ptr<Playlist> pl;
1708 if ((tr = rtv->track())) {
1709 add_region_context_items (edit_items, tr);
1713 add_dstream_context_items (edit_items);
1715 return &track_region_context_menu;
1719 Editor::loudness_analyze_region_selection ()
1724 Selection& s (PublicEditor::instance ().get_selection ());
1725 RegionSelection ars = s.regions;
1726 ARDOUR::AnalysisGraph ag (_session);
1727 samplecnt_t total_work = 0;
1729 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1730 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1734 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1737 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1738 total_work += arv->region ()->length ();
1741 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1743 ag.set_total_samples (total_work);
1744 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1747 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1748 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1752 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1756 ag.analyze_region (ar);
1759 if (!ag.canceled ()) {
1760 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1766 Editor::loudness_analyze_range_selection ()
1771 Selection& s (PublicEditor::instance ().get_selection ());
1772 TimeSelection ts = s.time;
1773 ARDOUR::AnalysisGraph ag (_session);
1774 samplecnt_t total_work = 0;
1776 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1777 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1781 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1785 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1786 total_work += j->length ();
1790 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1792 ag.set_total_samples (total_work);
1793 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1796 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1797 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1801 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1805 ag.analyze_range (rui->route (), pl, ts);
1808 if (!ag.canceled ()) {
1809 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1815 Editor::spectral_analyze_region_selection ()
1817 if (analysis_window == 0) {
1818 analysis_window = new AnalysisWindow();
1821 analysis_window->set_session(_session);
1823 analysis_window->show_all();
1826 analysis_window->set_regionmode();
1827 analysis_window->analyze();
1829 analysis_window->present();
1833 Editor::spectral_analyze_range_selection()
1835 if (analysis_window == 0) {
1836 analysis_window = new AnalysisWindow();
1839 analysis_window->set_session(_session);
1841 analysis_window->show_all();
1844 analysis_window->set_rangemode();
1845 analysis_window->analyze();
1847 analysis_window->present();
1851 Editor::build_track_selection_context_menu ()
1853 using namespace Menu_Helpers;
1854 MenuList& edit_items = track_selection_context_menu.items();
1855 edit_items.clear ();
1857 add_selection_context_items (edit_items);
1858 // edit_items.push_back (SeparatorElem());
1859 // add_dstream_context_items (edit_items);
1861 return &track_selection_context_menu;
1865 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1867 using namespace Menu_Helpers;
1869 /* OK, stick the region submenu at the top of the list, and then add
1873 RegionSelection rs = get_regions_from_selection_and_entered ();
1875 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1877 if (_popup_region_menu_item == 0) {
1878 _popup_region_menu_item = new MenuItem (menu_item_name, false);
1879 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1880 _popup_region_menu_item->show ();
1882 _popup_region_menu_item->set_label (menu_item_name);
1885 /* No layering allowed in later is higher layering model */
1886 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1887 if (act && Config->get_layer_model() == LaterHigher) {
1888 act->set_sensitive (false);
1890 act->set_sensitive (true);
1893 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1895 edit_items.push_back (*_popup_region_menu_item);
1896 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1897 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1899 edit_items.push_back (SeparatorElem());
1902 /** Add context menu items relevant to selection ranges.
1903 * @param edit_items List to add the items to.
1906 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1908 using namespace Menu_Helpers;
1910 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1911 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1913 edit_items.push_back (SeparatorElem());
1914 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
1916 edit_items.push_back (SeparatorElem());
1917 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1918 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1920 edit_items.push_back (SeparatorElem());
1922 edit_items.push_back (
1924 _("Move Range Start to Previous Region Boundary"),
1925 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1929 edit_items.push_back (
1931 _("Move Range Start to Next Region Boundary"),
1932 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1936 edit_items.push_back (
1938 _("Move Range End to Previous Region Boundary"),
1939 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1943 edit_items.push_back (
1945 _("Move Range End to Next Region Boundary"),
1946 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1950 edit_items.push_back (SeparatorElem());
1951 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1952 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1954 edit_items.push_back (SeparatorElem());
1955 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1957 edit_items.push_back (SeparatorElem());
1958 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1959 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1960 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1962 edit_items.push_back (SeparatorElem());
1963 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1965 edit_items.push_back (SeparatorElem());
1966 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1967 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1969 edit_items.push_back (SeparatorElem());
1970 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1971 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1972 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1973 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1974 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1975 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1976 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1982 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1984 using namespace Menu_Helpers;
1988 Menu *play_menu = manage (new Menu);
1989 MenuList& play_items = play_menu->items();
1990 play_menu->set_name ("ArdourContextMenu");
1992 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1993 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1994 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1995 play_items.push_back (SeparatorElem());
1996 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1998 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2002 Menu *select_menu = manage (new Menu);
2003 MenuList& select_items = select_menu->items();
2004 select_menu->set_name ("ArdourContextMenu");
2006 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2007 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2008 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2009 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2010 select_items.push_back (SeparatorElem());
2011 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2012 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2013 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2014 select_items.push_back (SeparatorElem());
2015 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2016 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2017 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2018 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2019 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2020 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2021 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2023 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2027 Menu *cutnpaste_menu = manage (new Menu);
2028 MenuList& cutnpaste_items = cutnpaste_menu->items();
2029 cutnpaste_menu->set_name ("ArdourContextMenu");
2031 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2032 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2033 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2035 cutnpaste_items.push_back (SeparatorElem());
2037 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2038 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2040 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2042 /* Adding new material */
2044 edit_items.push_back (SeparatorElem());
2045 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2046 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2050 Menu *nudge_menu = manage (new Menu());
2051 MenuList& nudge_items = nudge_menu->items();
2052 nudge_menu->set_name ("ArdourContextMenu");
2054 edit_items.push_back (SeparatorElem());
2055 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2056 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2057 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2058 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2060 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2064 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2066 using namespace Menu_Helpers;
2070 Menu *play_menu = manage (new Menu);
2071 MenuList& play_items = play_menu->items();
2072 play_menu->set_name ("ArdourContextMenu");
2074 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2075 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2076 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2080 Menu *select_menu = manage (new Menu);
2081 MenuList& select_items = select_menu->items();
2082 select_menu->set_name ("ArdourContextMenu");
2084 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2085 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2086 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2087 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2088 select_items.push_back (SeparatorElem());
2089 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2090 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2091 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2092 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2094 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2098 Menu *cutnpaste_menu = manage (new Menu);
2099 MenuList& cutnpaste_items = cutnpaste_menu->items();
2100 cutnpaste_menu->set_name ("ArdourContextMenu");
2102 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2103 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2104 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2106 Menu *nudge_menu = manage (new Menu());
2107 MenuList& nudge_items = nudge_menu->items();
2108 nudge_menu->set_name ("ArdourContextMenu");
2110 edit_items.push_back (SeparatorElem());
2111 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2112 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2113 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2114 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2116 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2120 Editor::grid_type() const
2126 Editor::grid_musical() const
2128 switch (_grid_type) {
2129 case GridTypeBeatDiv32:
2130 case GridTypeBeatDiv28:
2131 case GridTypeBeatDiv24:
2132 case GridTypeBeatDiv20:
2133 case GridTypeBeatDiv16:
2134 case GridTypeBeatDiv14:
2135 case GridTypeBeatDiv12:
2136 case GridTypeBeatDiv10:
2137 case GridTypeBeatDiv8:
2138 case GridTypeBeatDiv7:
2139 case GridTypeBeatDiv6:
2140 case GridTypeBeatDiv5:
2141 case GridTypeBeatDiv4:
2142 case GridTypeBeatDiv3:
2143 case GridTypeBeatDiv2:
2149 case GridTypeMinSec:
2150 case GridTypeSamples:
2157 Editor::grid_nonmusical() const
2159 switch (_grid_type) {
2161 case GridTypeMinSec:
2162 case GridTypeSamples:
2164 case GridTypeBeatDiv32:
2165 case GridTypeBeatDiv28:
2166 case GridTypeBeatDiv24:
2167 case GridTypeBeatDiv20:
2168 case GridTypeBeatDiv16:
2169 case GridTypeBeatDiv14:
2170 case GridTypeBeatDiv12:
2171 case GridTypeBeatDiv10:
2172 case GridTypeBeatDiv8:
2173 case GridTypeBeatDiv7:
2174 case GridTypeBeatDiv6:
2175 case GridTypeBeatDiv5:
2176 case GridTypeBeatDiv4:
2177 case GridTypeBeatDiv3:
2178 case GridTypeBeatDiv2:
2187 Editor::snap_mode() const
2193 Editor::set_grid_to (GridType gt)
2195 if (_grid_type == gt) { //already set
2199 unsigned int grid_ind = (unsigned int)gt;
2201 if (internal_editing()) {
2202 internal_grid_type = gt;
2204 pre_internal_grid_type = gt;
2209 if (grid_ind > grid_type_strings.size() - 1) {
2211 _grid_type = (GridType)grid_ind;
2214 string str = grid_type_strings[grid_ind];
2216 if (str != grid_type_selector.get_text()) {
2217 grid_type_selector.set_text (str);
2220 //show appropriate rulers for this grid setting. (ToDo: perhaps make this optional)
2221 //Currently this is 'required' because the RULER calculates the grid_marks which will be used by grid_lines
2222 if ( grid_musical() ) {
2223 ruler_tempo_action->set_active(true);
2224 ruler_meter_action->set_active(true);
2226 ruler_bbt_action->set_active(true);
2227 ruler_timecode_action->set_active(false);
2228 ruler_minsec_action->set_active(false);
2229 ruler_samples_action->set_active(false);
2230 } else if (_grid_type == GridTypeSmpte ) {
2231 ruler_tempo_action->set_active(false);
2232 ruler_meter_action->set_active(false);
2234 ruler_bbt_action->set_active(false);
2235 ruler_timecode_action->set_active(true);
2236 ruler_minsec_action->set_active(false);
2237 ruler_samples_action->set_active(false);
2238 } else if (_grid_type == GridTypeMinSec ) {
2239 ruler_tempo_action->set_active(false);
2240 ruler_meter_action->set_active(false);
2242 ruler_bbt_action->set_active(false);
2243 ruler_timecode_action->set_active(false);
2244 ruler_minsec_action->set_active(true);
2245 ruler_samples_action->set_active(false);
2246 } else if (_grid_type == GridTypeSamples ) {
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(false);
2252 ruler_minsec_action->set_active(false);
2253 ruler_samples_action->set_active(true);
2258 if ( grid_musical() ) {
2259 compute_bbt_ruler_scale (_leftmost_sample, _leftmost_sample + current_page_samples());
2260 update_tempo_based_rulers ();
2263 mark_region_boundary_cache_dirty ();
2265 redisplay_grid (false);
2267 SnapChanged (); /* EMIT SIGNAL */
2271 Editor::set_snap_mode (SnapMode mode)
2273 if (internal_editing()) {
2274 internal_snap_mode = mode;
2276 pre_internal_snap_mode = mode;
2281 if (_snap_mode == SnapOff ) {
2282 snap_mode_button.set_active_state (Gtkmm2ext::Off);
2284 snap_mode_button.set_active_state (Gtkmm2ext::ExplicitActive);
2291 Editor::set_edit_point_preference (EditPoint ep, bool force)
2293 bool changed = (_edit_point != ep);
2296 if (Profile->get_mixbus())
2297 if (ep == EditAtSelectedMarker)
2298 ep = EditAtPlayhead;
2300 string str = edit_point_strings[(int)ep];
2301 if (str != edit_point_selector.get_text ()) {
2302 edit_point_selector.set_text (str);
2305 update_all_enter_cursors();
2307 if (!force && !changed) {
2311 const char* action=NULL;
2313 switch (_edit_point) {
2314 case EditAtPlayhead:
2315 action = "edit-at-playhead";
2317 case EditAtSelectedMarker:
2318 action = "edit-at-marker";
2321 action = "edit-at-mouse";
2325 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2327 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2331 bool in_track_canvas;
2333 if (!mouse_sample (foo, in_track_canvas)) {
2334 in_track_canvas = false;
2337 reset_canvas_action_sensitivity (in_track_canvas);
2338 sensitize_the_right_region_actions (false);
2344 Editor::set_state (const XMLNode& node, int version)
2347 PBD::Unwinder<bool> nsi (no_save_instant, true);
2350 Tabbable::set_state (node, version);
2353 if (_session && node.get_property ("playhead", ph_pos)) {
2355 playhead_cursor->set_position (ph_pos);
2357 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2358 playhead_cursor->set_position (0);
2361 playhead_cursor->set_position (0);
2364 node.get_property ("mixer-width", editor_mixer_strip_width);
2366 node.get_property ("zoom-focus", zoom_focus);
2367 zoom_focus_selection_done (zoom_focus);
2370 if (node.get_property ("zoom", z)) {
2371 /* older versions of ardour used floating point samples_per_pixel */
2372 reset_zoom (llrintf (z));
2374 reset_zoom (samples_per_pixel);
2378 if (node.get_property ("visible-track-count", cnt)) {
2379 set_visible_track_count (cnt);
2383 if (!node.get_property ("grid-type", grid_type)) {
2384 grid_type = _grid_type;
2386 set_grid_to (grid_type);
2389 if (node.get_property ("snap-mode", sm)) {
2390 snap_mode_selection_done(sm);
2391 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2392 * snap_mode_selection_done() will only mark an already active item as active
2393 * which does not trigger set_text().
2397 set_snap_mode (_snap_mode);
2400 node.get_property ("internal-grid-type", internal_grid_type);
2401 node.get_property ("internal-snap-mode", internal_snap_mode);
2402 node.get_property ("pre-internal-grid-type", pre_internal_grid_type);
2403 node.get_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2406 if (node.get_property ("mouse-mode", mm_str)) {
2407 MouseMode m = str2mousemode(mm_str);
2408 set_mouse_mode (m, true);
2410 set_mouse_mode (MouseObject, true);
2414 if (node.get_property ("left-frame", lf_pos)) {
2418 reset_x_origin (lf_pos);
2422 if (node.get_property ("y-origin", y_origin)) {
2423 reset_y_origin (y_origin);
2426 if (node.get_property ("join-object-range", yn)) {
2427 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2429 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2430 tact->set_active (!yn);
2431 tact->set_active (yn);
2433 set_mouse_mode(mouse_mode, true);
2437 if (node.get_property ("edit-point", ep)) {
2438 set_edit_point_preference (ep, true);
2440 set_edit_point_preference (_edit_point);
2443 if (node.get_property ("follow-playhead", yn)) {
2444 set_follow_playhead (yn);
2447 if (node.get_property ("stationary-playhead", yn)) {
2448 set_stationary_playhead (yn);
2451 RegionListSortType sort_type;
2452 if (node.get_property ("region-list-sort-type", sort_type)) {
2453 _regions->reset_sort_type (sort_type, true);
2456 if (node.get_property ("show-editor-mixer", yn)) {
2458 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2461 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2463 /* do it twice to force the change */
2465 tact->set_active (!yn);
2466 tact->set_active (yn);
2469 if (node.get_property ("show-editor-list", yn)) {
2471 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2474 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2476 /* do it twice to force the change */
2478 tact->set_active (!yn);
2479 tact->set_active (yn);
2483 if (node.get_property (X_("editor-list-page"), el_page)) {
2484 _the_notebook.set_current_page (el_page);
2487 if (node.get_property (X_("show-marker-lines"), yn)) {
2488 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2490 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2492 tact->set_active (!yn);
2493 tact->set_active (yn);
2496 XMLNodeList children = node.children ();
2497 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2498 selection->set_state (**i, Stateful::current_state_version);
2499 _regions->set_state (**i);
2500 _locations->set_state (**i);
2503 if (node.get_property ("maximised", yn)) {
2504 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2506 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2507 bool fs = tact && tact->get_active();
2509 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2513 samplepos_t nudge_clock_value;
2514 if (node.get_property ("nudge-clock-value", nudge_clock_value)) {
2515 nudge_clock->set (nudge_clock_value);
2517 nudge_clock->set_mode (AudioClock::Timecode);
2518 nudge_clock->set (_session->sample_rate() * 5, true);
2523 * Not all properties may have been in XML, but
2524 * those that are linked to a private variable may need changing
2528 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2529 yn = _follow_playhead;
2531 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2532 if (tact->get_active() != yn) {
2533 tact->set_active (yn);
2537 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2538 yn = _stationary_playhead;
2540 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2541 if (tact->get_active() != yn) {
2542 tact->set_active (yn);
2547 return LuaInstance::instance()->set_state(node);
2551 Editor::get_state ()
2553 XMLNode* node = new XMLNode (X_("Editor"));
2555 node->set_property ("id", id().to_s ());
2557 node->add_child_nocopy (Tabbable::get_state());
2559 node->set_property("edit-horizontal-pane-pos", edit_pane.get_divider ());
2560 node->set_property("notebook-shrunk", _notebook_shrunk);
2561 node->set_property("edit-vertical-pane-pos", editor_summary_pane.get_divider());
2563 maybe_add_mixer_strip_width (*node);
2565 node->set_property ("zoom-focus", zoom_focus);
2567 node->set_property ("zoom", samples_per_pixel);
2568 node->set_property ("grid-type", _grid_type);
2569 node->set_property ("snap-mode", _snap_mode);
2570 node->set_property ("internal-grid-type", internal_grid_type);
2571 node->set_property ("internal-snap-mode", internal_snap_mode);
2572 node->set_property ("pre-internal-grid-type", pre_internal_grid_type);
2573 node->set_property ("pre-internal-snap-mode", pre_internal_snap_mode);
2574 node->set_property ("edit-point", _edit_point);
2575 node->set_property ("visible-track-count", _visible_track_count);
2577 node->set_property ("playhead", playhead_cursor->current_sample ());
2578 node->set_property ("left-frame", _leftmost_sample);
2579 node->set_property ("y-origin", vertical_adjustment.get_value ());
2581 node->set_property ("maximised", _maximised);
2582 node->set_property ("follow-playhead", _follow_playhead);
2583 node->set_property ("stationary-playhead", _stationary_playhead);
2584 node->set_property ("region-list-sort-type", _regions->sort_type ());
2585 node->set_property ("mouse-mode", mouse_mode);
2586 node->set_property ("join-object-range", smart_mode_action->get_active ());
2588 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2590 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2591 node->set_property (X_("show-editor-mixer"), tact->get_active());
2594 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2596 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2597 node->set_property (X_("show-editor-list"), tact->get_active());
2600 node->set_property (X_("editor-list-page"), _the_notebook.get_current_page ());
2602 if (button_bindings) {
2603 XMLNode* bb = new XMLNode (X_("Buttons"));
2604 button_bindings->save (*bb);
2605 node->add_child_nocopy (*bb);
2608 node->set_property (X_("show-marker-lines"), _show_marker_lines);
2610 node->add_child_nocopy (selection->get_state ());
2611 node->add_child_nocopy (_regions->get_state ());
2613 node->set_property ("nudge-clock-value", nudge_clock->current_duration());
2615 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2616 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2617 node->add_child_nocopy (_locations->get_state ());
2622 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2623 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2625 * @return pair: TimeAxisView that y is over, layer index.
2627 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2628 * in stacked or expanded region display mode, otherwise 0.
2630 std::pair<TimeAxisView *, double>
2631 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2633 if (!trackview_relative_offset) {
2634 y -= _trackview_group->canvas_origin().y;
2638 return std::make_pair ( (TimeAxisView *) 0, 0);
2641 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2643 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2650 return std::make_pair ( (TimeAxisView *) 0, 0);
2654 Editor::set_snapped_cursor_position (samplepos_t pos)
2656 if ( _edit_point == EditAtMouse ) {
2657 snapped_cursor->set_position(pos);
2662 /** Snap a position to the grid, if appropriate, taking into account current
2663 * grid settings and also the state of any snap modifier keys that may be pressed.
2664 * @param start Position to snap.
2665 * @param event Event to get current key modifier information from, or 0.
2668 Editor::snap_to_with_modifier (MusicSample& start, GdkEvent const * event, RoundMode direction, SnapPref pref, bool for_mark)
2670 if (!_session || !event) {
2674 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2675 if (_snap_mode == SnapOff) {
2676 snap_to_internal (start, direction, pref, for_mark);
2678 start.set (start.sample, 0);
2681 if (_snap_mode != SnapOff) {
2682 snap_to_internal (start, direction, pref, for_mark);
2683 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2684 /* SnapOff, but we pressed the snap_delta modifier */
2685 snap_to_internal (start, direction, pref, for_mark);
2687 start.set (start.sample, 0);
2693 Editor::snap_to (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2695 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2696 start.set (start.sample, 0);
2700 snap_to_internal (start, direction, pref, for_mark, ensure_snap);
2704 check_best_snap ( samplepos_t presnap, samplepos_t &test, samplepos_t &dist, samplepos_t &best )
2706 samplepos_t diff = abs( test - presnap );
2707 if ( diff < dist ) {
2712 test = max_samplepos; //reset this so it doesn't get accidentally reused
2716 Editor::snap_to_grid (vector<ArdourCanvas::Ruler::Mark> marks, samplepos_t presnap, RoundMode direction)
2718 if (marks.empty() ) return presnap;
2722 samplepos_t test = presnap;
2724 before = after = max_samplepos;
2726 //get marks to either side of presnap
2727 vector<ArdourCanvas::Ruler::Mark>::const_iterator m = marks.begin();
2728 while ( m != marks.end() && (m->position < presnap) ) {
2732 if (m == marks.end ()) {
2733 /* ran out of marks */
2734 before = marks.back().position;
2737 after = m->position;
2739 if (m != marks.begin ()) {
2741 before = m->position;
2744 if (before == max_samplepos && after == max_samplepos) {
2745 /* No grid to snap to, so just don't snap */
2747 } else if (before == max_samplepos) {
2749 } else if (after == max_samplepos) {
2752 if ((direction == RoundUpMaybe || direction == RoundUpAlways))
2754 else if ((direction == RoundDownMaybe || direction == RoundDownAlways))
2756 else if (direction == 0 ) {
2757 if ((presnap - before) < (after - presnap)) {
2769 Editor::marker_snap_to_internal (samplepos_t presnap, RoundMode direction)
2775 _session->locations()->marks_either_side (presnap, before, after);
2777 if (before == max_samplepos && after == max_samplepos) {
2778 /* No marks to snap to, so just don't snap */
2780 } else if (before == max_samplepos) {
2782 } else if (after == max_samplepos) {
2785 if ((direction == RoundUpMaybe || direction == RoundUpAlways)) {
2787 } else if ((direction == RoundDownMaybe || direction == RoundDownAlways)) {
2789 } else if (direction == 0 ) {
2790 if ((presnap - before) < (after - presnap)) {
2802 Editor::snap_to_internal (MusicSample& start, RoundMode direction, SnapPref pref, bool for_mark, bool ensure_snap)
2804 const samplepos_t presnap = start.sample;
2806 samplepos_t test = max_samplepos; //for each snap, we'll use this value
2807 samplepos_t dist = max_samplepos; //this records the distance of the best snap result we've found so far
2808 samplepos_t best = max_samplepos; //this records the best snap-result we've found so far
2810 //check snap-to-marker
2811 if ( UIConfiguration::instance().get_snap_to_marks() ) {
2816 test = marker_snap_to_internal ( presnap, direction );
2817 check_best_snap(presnap, test, dist, best);
2820 //check snap-to-region-{start/end/sync}
2821 if ( UIConfiguration::instance().get_snap_to_region_start() || UIConfiguration::instance().get_snap_to_region_end() || UIConfiguration::instance().get_snap_to_region_sync() ) {
2822 if (!region_boundary_cache.empty()) {
2824 vector<samplepos_t>::iterator prev = region_boundary_cache.end ();
2825 vector<samplepos_t>::iterator next = region_boundary_cache.end ();
2827 if (direction > 0) {
2828 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2830 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), presnap);
2833 if (next != region_boundary_cache.begin ()) {
2838 samplepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2839 samplepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2841 if (presnap > (p + n) / 2) {
2848 check_best_snap(presnap, test, dist, best);
2852 if (UIConfiguration::instance().get_snap_to_grid() && (_grid_type != GridTypeNone) ) {
2854 //if SnapToGrid is selected, the user wants to prioritize the music grid
2855 //in this case we should reset the best distance, so Grid will prevail
2856 dist = max_samplepos;
2858 test = snap_to_grid (grid_marks, presnap, direction);
2859 check_best_snap(presnap, test, dist, best);
2862 //now check "magnetic" state: is the grid within reasonable on-screen distance to trigger a snap?
2863 //this also helps to avoid snapping to somewhere the user can't see. ( i.e.: I clicked on a region and it disappeared!! )
2864 //ToDo: perhaps this should only occur if EditPointMouse?
2865 int snap_threshold_s = pixel_to_sample(UIConfiguration::instance().get_snap_threshold());
2867 start.set (best, 0);
2869 } else if (presnap > best) {
2870 if (presnap > (best+ snap_threshold_s)) {
2873 } else if (presnap < best) {
2874 if (presnap < (best - snap_threshold_s)) {
2879 start.set (best, 0);
2884 Editor::setup_toolbar ()
2886 HBox* mode_box = manage(new HBox);
2887 mode_box->set_border_width (2);
2888 mode_box->set_spacing(2);
2890 HBox* mouse_mode_box = manage (new HBox);
2891 HBox* mouse_mode_hbox = manage (new HBox);
2892 VBox* mouse_mode_vbox = manage (new VBox);
2893 Alignment* mouse_mode_align = manage (new Alignment);
2895 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2896 mouse_mode_size_group->add_widget (smart_mode_button);
2897 mouse_mode_size_group->add_widget (mouse_move_button);
2898 mouse_mode_size_group->add_widget (mouse_cut_button);
2899 mouse_mode_size_group->add_widget (mouse_select_button);
2900 mouse_mode_size_group->add_widget (mouse_timefx_button);
2901 mouse_mode_size_group->add_widget (mouse_audition_button);
2902 mouse_mode_size_group->add_widget (mouse_draw_button);
2903 mouse_mode_size_group->add_widget (mouse_content_button);
2905 if (!Profile->get_mixbus()) {
2906 mouse_mode_size_group->add_widget (zoom_in_button);
2907 mouse_mode_size_group->add_widget (zoom_out_button);
2908 mouse_mode_size_group->add_widget (zoom_out_full_button);
2909 mouse_mode_size_group->add_widget (zoom_focus_selector);
2910 mouse_mode_size_group->add_widget (tav_shrink_button);
2911 mouse_mode_size_group->add_widget (tav_expand_button);
2913 mouse_mode_size_group->add_widget (zoom_preset_selector);
2914 mouse_mode_size_group->add_widget (visible_tracks_selector);
2917 mouse_mode_size_group->add_widget (grid_type_selector);
2918 mouse_mode_size_group->add_widget (snap_mode_button);
2920 mouse_mode_size_group->add_widget (edit_point_selector);
2921 mouse_mode_size_group->add_widget (edit_mode_selector);
2923 mouse_mode_size_group->add_widget (*nudge_clock);
2924 mouse_mode_size_group->add_widget (nudge_forward_button);
2925 mouse_mode_size_group->add_widget (nudge_backward_button);
2927 mouse_mode_hbox->set_spacing (2);
2929 if (!ARDOUR::Profile->get_trx()) {
2930 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2933 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2934 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2936 if (!ARDOUR::Profile->get_mixbus()) {
2937 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2938 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2941 if (!ARDOUR::Profile->get_trx()) {
2942 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2943 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2944 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2947 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2949 mouse_mode_align->add (*mouse_mode_vbox);
2950 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2952 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2954 edit_mode_selector.set_name ("mouse mode button");
2956 if (!ARDOUR::Profile->get_trx()) {
2957 mode_box->pack_start (edit_mode_selector, false, false);
2958 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2959 mode_box->pack_start (edit_point_selector, false, false);
2960 mode_box->pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
2963 mode_box->pack_start (*mouse_mode_box, false, false);
2967 _zoom_box.set_spacing (2);
2968 _zoom_box.set_border_width (2);
2972 zoom_preset_selector.set_name ("zoom button");
2973 zoom_preset_selector.set_icon (ArdourIcon::ZoomExpand);
2975 zoom_in_button.set_name ("zoom button");
2976 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
2977 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2978 zoom_in_button.set_related_action (act);
2980 zoom_out_button.set_name ("zoom button");
2981 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
2982 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2983 zoom_out_button.set_related_action (act);
2985 zoom_out_full_button.set_name ("zoom button");
2986 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
2987 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2988 zoom_out_full_button.set_related_action (act);
2990 zoom_focus_selector.set_name ("zoom button");
2992 if (ARDOUR::Profile->get_mixbus()) {
2993 _zoom_box.pack_start (zoom_preset_selector, false, false);
2994 } else if (ARDOUR::Profile->get_trx()) {
2995 mode_box->pack_start (zoom_out_button, false, false);
2996 mode_box->pack_start (zoom_in_button, false, false);
2998 _zoom_box.pack_start (zoom_out_button, false, false);
2999 _zoom_box.pack_start (zoom_in_button, false, false);
3000 _zoom_box.pack_start (zoom_out_full_button, false, false);
3001 _zoom_box.pack_start (zoom_focus_selector, false, false);
3004 /* Track zoom buttons */
3005 _track_box.set_spacing (2);
3006 _track_box.set_border_width (2);
3008 visible_tracks_selector.set_name ("zoom button");
3009 if (Profile->get_mixbus()) {
3010 visible_tracks_selector.set_icon (ArdourIcon::TimeAxisExpand);
3012 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3015 tav_expand_button.set_name ("zoom button");
3016 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3017 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3018 tav_expand_button.set_related_action (act);
3020 tav_shrink_button.set_name ("zoom button");
3021 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3022 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3023 tav_shrink_button.set_related_action (act);
3025 if (ARDOUR::Profile->get_mixbus()) {
3026 _track_box.pack_start (visible_tracks_selector);
3027 } else if (ARDOUR::Profile->get_trx()) {
3028 _track_box.pack_start (tav_shrink_button);
3029 _track_box.pack_start (tav_expand_button);
3031 _track_box.pack_start (visible_tracks_selector);
3032 _track_box.pack_start (tav_shrink_button);
3033 _track_box.pack_start (tav_expand_button);
3036 snap_box.set_spacing (2);
3037 snap_box.set_border_width (2);
3039 grid_type_selector.set_name ("mouse mode button");
3041 snap_mode_button.set_name ("mouse mode button");
3043 edit_point_selector.set_name ("mouse mode button");
3045 snap_box.pack_start (snap_mode_button, false, false);
3046 snap_box.pack_start (grid_type_selector, false, false);
3050 HBox *nudge_box = manage (new HBox);
3051 nudge_box->set_spacing (2);
3052 nudge_box->set_border_width (2);
3054 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3055 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3057 nudge_box->pack_start (nudge_backward_button, false, false);
3058 nudge_box->pack_start (nudge_forward_button, false, false);
3059 nudge_box->pack_start (*nudge_clock, false, false);
3062 /* Pack everything in... */
3064 toolbar_hbox.set_spacing (2);
3065 toolbar_hbox.set_border_width (2);
3067 toolbar_hbox.pack_start (*mode_box, false, false);
3069 if (!ARDOUR::Profile->get_trx()) {
3071 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3073 toolbar_hbox.pack_start (snap_box, false, false);
3075 toolbar_hbox.pack_start (*(manage (new ArdourVSpacer ())), false, false, 3);
3077 toolbar_hbox.pack_start (*nudge_box, false, false);
3079 //zoom tools on right ege
3081 toolbar_hbox.pack_end (_zoom_box, false, false);
3083 toolbar_hbox.pack_end (*(manage (new ArdourVSpacer ())), false, false, 3);
3085 toolbar_hbox.pack_end (_track_box, false, false);
3089 toolbar_hbox.show_all ();
3093 Editor::build_edit_point_menu ()
3095 using namespace Menu_Helpers;
3097 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3098 if(!Profile->get_mixbus())
3099 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3100 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3102 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3106 Editor::build_edit_mode_menu ()
3108 using namespace Menu_Helpers;
3110 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3111 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3112 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3113 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3115 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3119 Editor::build_grid_type_menu ()
3121 using namespace Menu_Helpers;
3123 //main grid: bars, quarter-notes, etc
3124 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeNone], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeNone)));
3125 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBar], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBar)));
3126 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeat], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeat)));
3127 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv2)));
3128 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv4)));
3129 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv8)));
3130 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv16)));
3131 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv32)));
3134 grid_type_selector.AddMenuElem(SeparatorElem());
3135 Gtk::Menu *_triplet_menu = manage (new Menu);
3136 MenuList& triplet_items (_triplet_menu->items());
3138 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv3) ));
3139 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv6) ));
3140 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv12) ));
3141 triplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv24) ));
3143 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Triplets"), *_triplet_menu));
3146 Gtk::Menu *_quintuplet_menu = manage (new Menu);
3147 MenuList& quintuplet_items (_quintuplet_menu->items());
3149 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv5) ));
3150 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv10) ));
3151 quintuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv20) ));
3153 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Quintuplets"), *_quintuplet_menu));
3156 Gtk::Menu *_septuplet_menu = manage (new Menu);
3157 MenuList& septuplet_items (_septuplet_menu->items());
3159 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv7) ));
3160 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv14) ));
3161 septuplet_items.push_back( MenuElem( grid_type_strings[(int)GridTypeBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeBeatDiv28) ));
3163 grid_type_selector.AddMenuElem (Menu_Helpers::MenuElem (_("Septuplets"), *_septuplet_menu));
3165 grid_type_selector.AddMenuElem(SeparatorElem());
3166 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeSmpte], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSmpte)));
3167 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeMinSec], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeMinSec)));
3168 grid_type_selector.AddMenuElem (MenuElem ( grid_type_strings[(int)GridTypeSamples], sigc::bind (sigc::mem_fun(*this, &Editor::grid_type_selection_done), (GridType) GridTypeSamples)));
3170 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
3174 Editor::setup_tooltips ()
3176 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3177 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3178 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3179 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3180 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3181 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3182 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3183 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3184 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3185 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3186 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3187 set_tooltip (zoom_in_button, _("Zoom In"));
3188 set_tooltip (zoom_out_button, _("Zoom Out"));
3189 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3190 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3191 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3192 set_tooltip (tav_expand_button, _("Expand Tracks"));
3193 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3194 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3195 set_tooltip (grid_type_selector, _("Grid Mode"));
3196 set_tooltip (snap_mode_button, _("Snap Mode\n\nRight-click to visit Snap preferences."));
3197 set_tooltip (edit_point_selector, _("Edit Point"));
3198 set_tooltip (edit_mode_selector, _("Edit Mode"));
3199 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3203 Editor::convert_drop_to_paths (
3204 vector<string>& paths,
3205 const RefPtr<Gdk::DragContext>& /*context*/,
3208 const SelectionData& data,
3212 if (_session == 0) {
3216 vector<string> uris = data.get_uris();
3220 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3221 are actually URI lists. So do it by hand.
3224 if (data.get_target() != "text/plain") {
3228 /* Parse the "uri-list" format that Nautilus provides,
3229 where each pathname is delimited by \r\n.
3231 THERE MAY BE NO NULL TERMINATING CHAR!!!
3234 string txt = data.get_text();
3238 p = (char *) malloc (txt.length() + 1);
3239 txt.copy (p, txt.length(), 0);
3240 p[txt.length()] = '\0';
3246 while (g_ascii_isspace (*p))
3250 while (*q && (*q != '\n') && (*q != '\r')) {
3257 while (q > p && g_ascii_isspace (*q))
3262 uris.push_back (string (p, q - p + 1));
3266 p = strchr (p, '\n');
3278 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3279 if ((*i).substr (0,7) == "file://") {
3280 paths.push_back (Glib::filename_from_uri (*i));
3288 Editor::new_tempo_section ()
3293 Editor::map_transport_state ()
3295 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3297 if (_session && _session->transport_stopped()) {
3298 have_pending_keyboard_selection = false;
3301 update_loop_range_view ();
3305 Editor::transport_looped ()
3307 /* reset Playhead position interpolation.
3308 * see Editor::super_rapid_screen_update
3310 _last_update_time = 0;
3316 Editor::begin_selection_op_history ()
3318 selection_op_cmd_depth = 0;
3319 selection_op_history_it = 0;
3321 while(!selection_op_history.empty()) {
3322 delete selection_op_history.front();
3323 selection_op_history.pop_front();
3326 selection_undo_action->set_sensitive (false);
3327 selection_redo_action->set_sensitive (false);
3328 selection_op_history.push_front (&_selection_memento->get_state ());
3332 Editor::begin_reversible_selection_op (string name)
3335 //cerr << name << endl;
3336 /* begin/commit pairs can be nested */
3337 selection_op_cmd_depth++;
3342 Editor::commit_reversible_selection_op ()
3345 if (selection_op_cmd_depth == 1) {
3347 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3349 The user has undone some selection ops and then made a new one,
3350 making anything earlier in the list invalid.
3353 list<XMLNode *>::iterator it = selection_op_history.begin();
3354 list<XMLNode *>::iterator e_it = it;
3355 advance (e_it, selection_op_history_it);
3357 for ( ; it != e_it; ++it) {
3360 selection_op_history.erase (selection_op_history.begin(), e_it);
3363 selection_op_history.push_front (&_selection_memento->get_state ());
3364 selection_op_history_it = 0;
3366 selection_undo_action->set_sensitive (true);
3367 selection_redo_action->set_sensitive (false);
3370 if (selection_op_cmd_depth > 0) {
3371 selection_op_cmd_depth--;
3377 Editor::undo_selection_op ()
3380 selection_op_history_it++;
3382 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3383 if (n == selection_op_history_it) {
3384 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3385 selection_redo_action->set_sensitive (true);
3389 /* is there an earlier entry? */
3390 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3391 selection_undo_action->set_sensitive (false);
3397 Editor::redo_selection_op ()
3400 if (selection_op_history_it > 0) {
3401 selection_op_history_it--;
3404 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3405 if (n == selection_op_history_it) {
3406 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3407 selection_undo_action->set_sensitive (true);
3412 if (selection_op_history_it == 0) {
3413 selection_redo_action->set_sensitive (false);
3419 Editor::begin_reversible_command (string name)
3422 before.push_back (&_selection_memento->get_state ());
3423 _session->begin_reversible_command (name);
3428 Editor::begin_reversible_command (GQuark q)
3431 before.push_back (&_selection_memento->get_state ());
3432 _session->begin_reversible_command (q);
3437 Editor::abort_reversible_command ()
3440 while(!before.empty()) {
3441 delete before.front();
3444 _session->abort_reversible_command ();
3449 Editor::commit_reversible_command ()
3452 if (before.size() == 1) {
3453 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3454 redo_action->set_sensitive(false);
3455 undo_action->set_sensitive(true);
3456 begin_selection_op_history ();
3459 if (before.empty()) {
3460 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3465 _session->commit_reversible_command ();
3470 Editor::history_changed ()
3474 if (undo_action && _session) {
3475 if (_session->undo_depth() == 0) {
3476 label = S_("Command|Undo");
3478 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3480 undo_action->property_label() = label;
3483 if (redo_action && _session) {
3484 if (_session->redo_depth() == 0) {
3486 redo_action->set_sensitive (false);
3488 label = string_compose(_("Redo (%1)"), _session->next_redo());
3489 redo_action->set_sensitive (true);
3491 redo_action->property_label() = label;
3496 Editor::duplicate_range (bool with_dialog)
3500 RegionSelection rs = get_regions_from_selection_and_entered ();
3502 if ( selection->time.length() == 0 && rs.empty()) {
3508 ArdourDialog win (_("Duplicate"));
3509 Label label (_("Number of duplications:"));
3510 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3511 SpinButton spinner (adjustment, 0.0, 1);
3514 win.get_vbox()->set_spacing (12);
3515 win.get_vbox()->pack_start (hbox);
3516 hbox.set_border_width (6);
3517 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3519 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3520 place, visually. so do this by hand.
3523 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3524 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3525 spinner.grab_focus();
3531 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3532 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3533 win.set_default_response (RESPONSE_ACCEPT);
3535 spinner.grab_focus ();
3537 switch (win.run ()) {
3538 case RESPONSE_ACCEPT:
3544 times = adjustment.get_value();
3547 if ((current_mouse_mode() == MouseRange)) {
3548 if (selection->time.length()) {
3549 duplicate_selection (times);
3551 } else if (get_smart_mode()) {
3552 if (selection->time.length()) {
3553 duplicate_selection (times);
3555 duplicate_some_regions (rs, times);
3557 duplicate_some_regions (rs, times);
3562 Editor::set_edit_mode (EditMode m)
3564 Config->set_edit_mode (m);
3568 Editor::cycle_edit_mode ()
3570 switch (Config->get_edit_mode()) {
3572 Config->set_edit_mode (Ripple);
3576 Config->set_edit_mode (Lock);
3579 Config->set_edit_mode (Slide);
3585 Editor::edit_mode_selection_done ( EditMode m )
3587 Config->set_edit_mode ( m );
3591 Editor::grid_type_selection_done (GridType gridtype)
3593 RefPtr<RadioAction> ract = grid_type_action (gridtype);
3595 ract->set_active ();
3600 Editor::snap_mode_selection_done (SnapMode mode)
3602 RefPtr<RadioAction> ract = snap_mode_action (mode);
3605 ract->set_active (true);
3610 Editor::cycle_edit_point (bool with_marker)
3612 if(Profile->get_mixbus())
3613 with_marker = false;
3615 switch (_edit_point) {
3617 set_edit_point_preference (EditAtPlayhead);
3619 case EditAtPlayhead:
3621 set_edit_point_preference (EditAtSelectedMarker);
3623 set_edit_point_preference (EditAtMouse);
3626 case EditAtSelectedMarker:
3627 set_edit_point_preference (EditAtMouse);
3633 Editor::edit_point_selection_done (EditPoint ep)
3635 set_edit_point_preference ( ep );
3639 Editor::build_zoom_focus_menu ()
3641 using namespace Menu_Helpers;
3643 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3644 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3645 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3646 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3647 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3648 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3650 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3654 Editor::zoom_focus_selection_done ( ZoomFocus f )
3656 RefPtr<RadioAction> ract = zoom_focus_action (f);
3658 ract->set_active ();
3663 Editor::build_track_count_menu ()
3665 using namespace Menu_Helpers;
3667 if (!Profile->get_mixbus()) {
3668 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3669 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3670 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3671 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3672 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3673 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3674 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3675 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3676 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3677 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3678 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3679 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3680 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3682 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3683 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3684 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3685 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3686 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3687 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3688 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3689 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3690 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3691 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3693 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3694 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3695 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3696 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3697 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3698 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3699 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3700 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3701 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3702 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3703 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Extents"), sigc::mem_fun(*this, &Editor::temporal_zoom_extents)));
3704 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), Horizontal)));
3709 Editor::set_zoom_preset (int64_t ms)
3712 temporal_zoom_session();
3716 ARDOUR::samplecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3717 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3721 Editor::set_visible_track_count (int32_t n)
3723 _visible_track_count = n;
3725 /* if the canvas hasn't really been allocated any size yet, just
3726 record the desired number of visible tracks and return. when canvas
3727 allocation happens, we will get called again and then we can do the
3731 if (_visible_canvas_height <= 1) {
3737 DisplaySuspender ds;
3739 if (_visible_track_count > 0) {
3740 h = trackviews_height() / _visible_track_count;
3741 std::ostringstream s;
3742 s << _visible_track_count;
3744 } else if (_visible_track_count == 0) {
3746 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
3747 if ((*i)->marked_for_display()) {
3749 TimeAxisView::Children cl ((*i)->get_child_list ());
3750 for (TimeAxisView::Children::const_iterator j = cl.begin(); j != cl.end(); ++j) {
3751 if ((*j)->marked_for_display()) {
3758 visible_tracks_selector.set_text (X_("*"));
3761 h = trackviews_height() / n;
3764 /* negative value means that the visible track count has
3765 been overridden by explicit track height changes.
3767 visible_tracks_selector.set_text (X_("*"));
3771 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3772 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3775 if (str != visible_tracks_selector.get_text()) {
3776 visible_tracks_selector.set_text (str);
3781 Editor::override_visible_track_count ()
3783 _visible_track_count = -1;
3784 visible_tracks_selector.set_text ( _("*") );
3788 Editor::edit_controls_button_release (GdkEventButton* ev)
3790 if (Keyboard::is_context_menu_event (ev)) {
3791 ARDOUR_UI::instance()->add_route ();
3792 } else if (ev->button == 1) {
3793 selection->clear_tracks ();
3800 Editor::mouse_select_button_release (GdkEventButton* ev)
3802 /* this handles just right-clicks */
3804 if (ev->button != 3) {
3812 Editor::set_zoom_focus (ZoomFocus f)
3814 string str = zoom_focus_strings[(int)f];
3816 if (str != zoom_focus_selector.get_text()) {
3817 zoom_focus_selector.set_text (str);
3820 if (zoom_focus != f) {
3827 Editor::cycle_zoom_focus ()
3829 switch (zoom_focus) {
3831 set_zoom_focus (ZoomFocusRight);
3833 case ZoomFocusRight:
3834 set_zoom_focus (ZoomFocusCenter);
3836 case ZoomFocusCenter:
3837 set_zoom_focus (ZoomFocusPlayhead);
3839 case ZoomFocusPlayhead:
3840 set_zoom_focus (ZoomFocusMouse);
3842 case ZoomFocusMouse:
3843 set_zoom_focus (ZoomFocusEdit);
3846 set_zoom_focus (ZoomFocusLeft);
3852 Editor::update_grid ()
3854 if ( grid_musical() ) {
3855 std::vector<TempoMap::BBTPoint> grid;
3856 if (bbt_ruler_scale != bbt_show_many) {
3857 compute_current_bbt_points (grid, _leftmost_sample, _leftmost_sample + current_page_samples());
3859 maybe_draw_grid_lines ();
3860 } else if ( grid_nonmusical() ) {
3861 maybe_draw_grid_lines ();
3868 Editor::toggle_follow_playhead ()
3870 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3872 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3873 set_follow_playhead (tact->get_active());
3877 /** @param yn true to follow playhead, otherwise false.
3878 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3881 Editor::set_follow_playhead (bool yn, bool catch_up)
3883 if (_follow_playhead != yn) {
3884 if ((_follow_playhead = yn) == true && catch_up) {
3886 reset_x_origin_to_follow_playhead ();
3893 Editor::toggle_stationary_playhead ()
3895 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3897 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3898 set_stationary_playhead (tact->get_active());
3903 Editor::set_stationary_playhead (bool yn)
3905 if (_stationary_playhead != yn) {
3906 if ((_stationary_playhead = yn) == true) {
3908 // FIXME need a 3.0 equivalent of this 2.X call
3909 // update_current_screen ();
3916 Editor::playlist_selector () const
3918 return *_playlist_selector;
3922 Editor::get_paste_offset (samplepos_t pos, unsigned paste_count, samplecnt_t duration)
3924 if (paste_count == 0) {
3925 /* don't bother calculating an offset that will be zero anyway */
3929 /* calculate basic unsnapped multi-paste offset */
3930 samplecnt_t offset = paste_count * duration;
3932 /* snap offset so pos + offset is aligned to the grid */
3933 MusicSample offset_pos (pos + offset, 0);
3934 snap_to(offset_pos, RoundUpMaybe);
3935 offset = offset_pos.sample - pos;
3941 Editor::get_grid_beat_divisions(samplepos_t position)
3943 switch (_grid_type) {
3944 case GridTypeBeatDiv32: return 32;
3945 case GridTypeBeatDiv28: return 28;
3946 case GridTypeBeatDiv24: return 24;
3947 case GridTypeBeatDiv20: return 20;
3948 case GridTypeBeatDiv16: return 16;
3949 case GridTypeBeatDiv14: return 14;
3950 case GridTypeBeatDiv12: return 12;
3951 case GridTypeBeatDiv10: return 10;
3952 case GridTypeBeatDiv8: return 8;
3953 case GridTypeBeatDiv7: return 7;
3954 case GridTypeBeatDiv6: return 6;
3955 case GridTypeBeatDiv5: return 5;
3956 case GridTypeBeatDiv4: return 4;
3957 case GridTypeBeatDiv3: return 3;
3958 case GridTypeBeatDiv2: return 2;
3960 case GridTypeNone: return 0;
3961 case GridTypeSmpte: return 0;
3962 case GridTypeMinSec: return 0;
3963 case GridTypeSamples: return 0;
3969 /** returns the current musical grid divisiions using the supplied modifier mask from a GtkEvent.
3970 if the grid is non-musical, returns 0.
3971 if the grid is snapped to bars, returns -1.
3972 @param event_state the current keyboard modifier mask.
3975 Editor::get_grid_music_divisions (uint32_t event_state)
3977 if (snap_mode() == SnapOff && !ArdourKeyboard::indicates_snap (event_state)) {
3981 if (snap_mode() != SnapOff && ArdourKeyboard::indicates_snap (event_state)) {
3985 switch (_grid_type) {
3986 case GridTypeBeatDiv32: return 32;
3987 case GridTypeBeatDiv28: return 28;
3988 case GridTypeBeatDiv24: return 24;
3989 case GridTypeBeatDiv20: return 20;
3990 case GridTypeBeatDiv16: return 16;
3991 case GridTypeBeatDiv14: return 14;
3992 case GridTypeBeatDiv12: return 12;
3993 case GridTypeBeatDiv10: return 10;
3994 case GridTypeBeatDiv8: return 8;
3995 case GridTypeBeatDiv7: return 7;
3996 case GridTypeBeatDiv6: return 6;
3997 case GridTypeBeatDiv5: return 5;
3998 case GridTypeBeatDiv4: return 4;
3999 case GridTypeBeatDiv3: return 3;
4000 case GridTypeBeatDiv2: return 2;
4001 case GridTypeBeat: return 1;
4002 case GridTypeBar : return -1;
4004 case GridTypeNone: return 0;
4005 case GridTypeSmpte: return 0;
4006 case GridTypeMinSec: return 0;
4007 case GridTypeSamples: return 0;
4013 Editor::get_grid_type_as_beats (bool& success, samplepos_t position)
4017 const unsigned divisions = get_grid_beat_divisions(position);
4019 return Temporal::Beats(1.0 / (double)get_grid_beat_divisions(position));
4022 switch (_grid_type) {
4024 return Temporal::Beats(4.0 / _session->tempo_map().meter_at_sample (position).note_divisor());
4027 const Meter& m = _session->tempo_map().meter_at_sample (position);
4028 return Temporal::Beats((4.0 * m.divisions_per_bar()) / m.note_divisor());
4036 return Temporal::Beats();
4040 Editor::get_nudge_distance (samplepos_t pos, samplecnt_t& next)
4044 ret = nudge_clock->current_duration (pos);
4045 next = ret + 1; /* XXXX fix me */
4051 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4053 ArdourDialog dialog (_("Playlist Deletion"));
4054 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4055 "If it is kept, its audio files will not be cleaned.\n"
4056 "If it is deleted, audio files used by it alone will be cleaned."),
4059 dialog.set_position (WIN_POS_CENTER);
4060 dialog.get_vbox()->pack_start (label);
4064 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4065 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4066 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4067 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4068 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4070 // by default gtk uses the left most button
4071 keep->grab_focus ();
4073 switch (dialog.run ()) {
4075 /* keep this and all remaining ones */
4080 /* delete this and all others */
4084 case RESPONSE_ACCEPT:
4085 /* delete the playlist */
4089 case RESPONSE_REJECT:
4090 /* keep the playlist */
4102 Editor::audio_region_selection_covers (samplepos_t where)
4104 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4105 if ((*a)->region()->covers (where)) {
4114 Editor::prepare_for_cleanup ()
4116 cut_buffer->clear_regions ();
4117 cut_buffer->clear_playlists ();
4119 selection->clear_regions ();
4120 selection->clear_playlists ();
4122 _regions->suspend_redisplay ();
4126 Editor::finish_cleanup ()
4128 _regions->resume_redisplay ();
4132 Editor::transport_loop_location()
4135 return _session->locations()->auto_loop_location();
4142 Editor::transport_punch_location()
4145 return _session->locations()->auto_punch_location();
4152 Editor::control_layout_scroll (GdkEventScroll* ev)
4154 /* Just forward to the normal canvas scroll method. The coordinate
4155 systems are different but since the canvas is always larger than the
4156 track headers, and aligned with the trackview area, this will work.
4158 In the not too distant future this layout is going away anyway and
4159 headers will be on the canvas.
4161 return canvas_scroll_event (ev, false);
4165 Editor::session_state_saved (string)
4168 _snapshots->redisplay ();
4172 Editor::maximise_editing_space ()
4178 Gtk::Window* toplevel = current_toplevel();
4181 toplevel->fullscreen ();
4187 Editor::restore_editing_space ()
4193 Gtk::Window* toplevel = current_toplevel();
4196 toplevel->unfullscreen();
4202 * Make new playlists for a given track and also any others that belong
4203 * to the same active route group with the `select' property.
4208 Editor::new_playlists (TimeAxisView* v)
4210 begin_reversible_command (_("new playlists"));
4211 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4212 _session->playlists->get (playlists);
4213 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4214 commit_reversible_command ();
4218 * Use a copy of the current playlist for a given track and also any others that belong
4219 * to the same active route group with the `select' property.
4224 Editor::copy_playlists (TimeAxisView* v)
4226 begin_reversible_command (_("copy playlists"));
4227 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4228 _session->playlists->get (playlists);
4229 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::group_select.property_id);
4230 commit_reversible_command ();
4233 /** Clear the current playlist for a given track and also any others that belong
4234 * to the same active route group with the `select' property.
4239 Editor::clear_playlists (TimeAxisView* v)
4241 begin_reversible_command (_("clear playlists"));
4242 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4243 _session->playlists->get (playlists);
4244 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::group_select.property_id);
4245 commit_reversible_command ();
4249 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4251 atv.use_new_playlist (sz > 1 ? false : true, playlists, false);
4255 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4257 atv.use_new_playlist (sz > 1 ? false : true, playlists, true);
4261 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4263 atv.clear_playlist ();
4267 Editor::get_y_origin () const
4269 return vertical_adjustment.get_value ();
4272 /** Queue up a change to the viewport x origin.
4273 * @param sample New x origin.
4276 Editor::reset_x_origin (samplepos_t sample)
4278 pending_visual_change.add (VisualChange::TimeOrigin);
4279 pending_visual_change.time_origin = sample;
4280 ensure_visual_change_idle_handler ();
4284 Editor::reset_y_origin (double y)
4286 pending_visual_change.add (VisualChange::YOrigin);
4287 pending_visual_change.y_origin = y;
4288 ensure_visual_change_idle_handler ();
4292 Editor::reset_zoom (samplecnt_t spp)
4294 if (spp == samples_per_pixel) {
4298 pending_visual_change.add (VisualChange::ZoomLevel);
4299 pending_visual_change.samples_per_pixel = spp;
4300 ensure_visual_change_idle_handler ();
4304 Editor::reposition_and_zoom (samplepos_t sample, double fpu)
4306 reset_x_origin (sample);
4309 if (!no_save_visual) {
4310 undo_visual_stack.push_back (current_visual_state(false));
4314 Editor::VisualState::VisualState (bool with_tracks)
4315 : gui_state (with_tracks ? new GUIObjectState : 0)
4319 Editor::VisualState::~VisualState ()
4324 Editor::VisualState*
4325 Editor::current_visual_state (bool with_tracks)
4327 VisualState* vs = new VisualState (with_tracks);
4328 vs->y_position = vertical_adjustment.get_value();
4329 vs->samples_per_pixel = samples_per_pixel;
4330 vs->_leftmost_sample = _leftmost_sample;
4331 vs->zoom_focus = zoom_focus;
4334 vs->gui_state->set_state (ARDOUR_UI::instance()->gui_object_state->get_state());
4341 Editor::undo_visual_state ()
4343 if (undo_visual_stack.empty()) {
4347 VisualState* vs = undo_visual_stack.back();
4348 undo_visual_stack.pop_back();
4351 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4354 use_visual_state (*vs);
4359 Editor::redo_visual_state ()
4361 if (redo_visual_stack.empty()) {
4365 VisualState* vs = redo_visual_stack.back();
4366 redo_visual_stack.pop_back();
4368 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4369 // why do we check here?
4370 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4373 use_visual_state (*vs);
4378 Editor::swap_visual_state ()
4380 if (undo_visual_stack.empty()) {
4381 redo_visual_state ();
4383 undo_visual_state ();
4388 Editor::use_visual_state (VisualState& vs)
4390 PBD::Unwinder<bool> nsv (no_save_visual, true);
4391 DisplaySuspender ds;
4393 vertical_adjustment.set_value (vs.y_position);
4395 set_zoom_focus (vs.zoom_focus);
4396 reposition_and_zoom (vs._leftmost_sample, vs.samples_per_pixel);
4399 ARDOUR_UI::instance()->gui_object_state->set_state (vs.gui_state->get_state());
4401 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4402 (*i)->clear_property_cache();
4403 (*i)->reset_visual_state ();
4407 _routes->update_visibility ();
4410 /** This is the core function that controls the zoom level of the canvas. It is called
4411 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4412 * @param spp new number of samples per pixel
4415 Editor::set_samples_per_pixel (samplecnt_t spp)
4421 const samplecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->sample_rate() : 48000);
4422 const samplecnt_t lots_of_pixels = 4000;
4424 /* if the zoom level is greater than what you'd get trying to display 3
4425 * days of audio on a really big screen, then it's too big.
4428 if (spp * lots_of_pixels > three_days) {
4432 samples_per_pixel = spp;
4436 Editor::on_samples_per_pixel_changed ()
4438 bool const showing_time_selection = selection->time.length() > 0;
4440 if (showing_time_selection && selection->time.start () != selection->time.end_sample ()) {
4441 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4442 (*i)->reshow_selection (selection->time);
4446 ZoomChanged (); /* EMIT_SIGNAL */
4448 ArdourCanvas::GtkCanvasViewport* c;
4450 c = get_track_canvas();
4452 c->canvas()->zoomed ();
4455 if (playhead_cursor) {
4456 playhead_cursor->set_position (playhead_cursor->current_sample ());
4459 refresh_location_display();
4460 _summary->set_overlays_dirty ();
4462 update_marker_labels ();
4468 Editor::playhead_cursor_sample () const
4470 return playhead_cursor->current_sample();
4474 Editor::queue_visual_videotimeline_update ()
4476 pending_visual_change.add (VisualChange::VideoTimeline);
4477 ensure_visual_change_idle_handler ();
4481 Editor::ensure_visual_change_idle_handler ()
4483 if (pending_visual_change.idle_handler_id < 0) {
4484 // see comment in add_to_idle_resize above.
4485 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4486 pending_visual_change.being_handled = false;
4491 Editor::_idle_visual_changer (void* arg)
4493 return static_cast<Editor*>(arg)->idle_visual_changer ();
4497 Editor::pre_render ()
4499 visual_change_queued = false;
4501 if (pending_visual_change.pending != 0) {
4502 ensure_visual_change_idle_handler();
4507 Editor::idle_visual_changer ()
4509 pending_visual_change.idle_handler_id = -1;
4511 if (pending_visual_change.pending == 0) {
4515 /* set_horizontal_position() below (and maybe other calls) call
4516 gtk_main_iteration(), so it's possible that a signal will be handled
4517 half-way through this method. If this signal wants an
4518 idle_visual_changer we must schedule another one after this one, so
4519 mark the idle_handler_id as -1 here to allow that. Also make a note
4520 that we are doing the visual change, so that changes in response to
4521 super-rapid-screen-update can be dropped if we are still processing
4525 if (visual_change_queued) {
4529 pending_visual_change.being_handled = true;
4531 VisualChange vc = pending_visual_change;
4533 pending_visual_change.pending = (VisualChange::Type) 0;
4535 visual_changer (vc);
4537 pending_visual_change.being_handled = false;
4539 visual_change_queued = true;
4541 return 0; /* this is always a one-shot call */
4545 Editor::visual_changer (const VisualChange& vc)
4548 * Changed first so the correct horizontal canvas position is calculated in
4549 * Editor::set_horizontal_position
4551 if (vc.pending & VisualChange::ZoomLevel) {
4552 set_samples_per_pixel (vc.samples_per_pixel);
4555 if (vc.pending & VisualChange::TimeOrigin) {
4556 double new_time_origin = sample_to_pixel_unrounded (vc.time_origin);
4557 set_horizontal_position (new_time_origin);
4560 if (vc.pending & VisualChange::YOrigin) {
4561 vertical_adjustment.set_value (vc.y_origin);
4565 * Now the canvas is in the final state before render the canvas items that
4566 * support the Item::prepare_for_render interface can calculate the correct
4567 * item to visible canvas intersection.
4569 if (vc.pending & VisualChange::ZoomLevel) {
4570 on_samples_per_pixel_changed ();
4572 compute_fixed_ruler_scale ();
4574 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4575 update_tempo_based_rulers ();
4578 if (!(vc.pending & VisualChange::ZoomLevel)) {
4580 * If the canvas is not being zoomed then the canvas items will not change
4581 * and cause Item::prepare_for_render to be called so do it here manually.
4583 * Not ideal, but I can't think of a better solution atm.
4585 _track_canvas->prepare_for_render();
4588 // If we are only scrolling vertically there is no need to update these
4589 if (vc.pending != VisualChange::YOrigin) {
4590 update_fixed_rulers ();
4591 redisplay_grid (true);
4593 /* video frames & position need to be updated for zoom, horiz-scroll
4594 * and (explicitly) VisualChange::VideoTimeline.
4596 update_video_timeline();
4599 _summary->set_overlays_dirty ();
4602 struct EditorOrderTimeAxisSorter {
4603 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4604 return a->order () < b->order ();
4609 Editor::sort_track_selection (TrackViewList& sel)
4611 EditorOrderTimeAxisSorter cmp;
4616 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4619 samplepos_t where = 0;
4620 EditPoint ep = _edit_point;
4622 if (Profile->get_mixbus()) {
4623 if (ep == EditAtSelectedMarker) {
4624 ep = EditAtPlayhead;
4628 if (from_outside_canvas && (ep == EditAtMouse)) {
4629 ep = EditAtPlayhead;
4630 } else if (from_context_menu && (ep == EditAtMouse)) {
4631 return canvas_event_sample (&context_click_event, 0, 0);
4634 if (entered_marker) {
4635 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4636 return entered_marker->position();
4639 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4640 ep = EditAtSelectedMarker;
4643 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4644 ep = EditAtPlayhead;
4647 MusicSample snap_mf (0, 0);
4650 case EditAtPlayhead:
4651 if (_dragging_playhead && _control_scroll_target) {
4652 where = *_control_scroll_target;
4654 where = _session->audible_sample();
4656 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4659 case EditAtSelectedMarker:
4660 if (!selection->markers.empty()) {
4662 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4665 where = loc->start();
4669 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4677 if (!mouse_sample (where, ignored)) {
4678 /* XXX not right but what can we do ? */
4681 snap_mf.sample = where;
4683 where = snap_mf.sample;
4684 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4692 Editor::set_loop_range (samplepos_t start, samplepos_t end, string cmd)
4694 if (!_session) return;
4696 begin_reversible_command (cmd);
4700 if ((tll = transport_loop_location()) == 0) {
4701 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop, get_grid_music_divisions(0));
4702 XMLNode &before = _session->locations()->get_state();
4703 _session->locations()->add (loc, true);
4704 _session->set_auto_loop_location (loc);
4705 XMLNode &after = _session->locations()->get_state();
4706 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4708 XMLNode &before = tll->get_state();
4709 tll->set_hidden (false, this);
4710 tll->set (start, end);
4711 XMLNode &after = tll->get_state();
4712 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4715 commit_reversible_command ();
4719 Editor::set_punch_range (samplepos_t start, samplepos_t end, string cmd)
4721 if (!_session) return;
4723 begin_reversible_command (cmd);
4727 if ((tpl = transport_punch_location()) == 0) {
4728 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch, get_grid_music_divisions(0));
4729 XMLNode &before = _session->locations()->get_state();
4730 _session->locations()->add (loc, true);
4731 _session->set_auto_punch_location (loc);
4732 XMLNode &after = _session->locations()->get_state();
4733 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4735 XMLNode &before = tpl->get_state();
4736 tpl->set_hidden (false, this);
4737 tpl->set (start, end);
4738 XMLNode &after = tpl->get_state();
4739 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4742 commit_reversible_command ();
4745 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4746 * @param rs List to which found regions are added.
4747 * @param where Time to look at.
4748 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4751 Editor::get_regions_at (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4753 const TrackViewList* tracks;
4756 tracks = &track_views;
4761 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4763 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4766 boost::shared_ptr<Track> tr;
4767 boost::shared_ptr<Playlist> pl;
4769 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4771 boost::shared_ptr<RegionList> regions = pl->regions_at (where);
4773 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4774 RegionView* rv = rtv->view()->find_view (*i);
4785 Editor::get_regions_after (RegionSelection& rs, samplepos_t where, const TrackViewList& ts) const
4787 const TrackViewList* tracks;
4790 tracks = &track_views;
4795 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4796 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_touched (where, max_samplepos);
4805 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4807 RegionView* rv = rtv->view()->find_view (*i);
4818 /** Get regions using the following method:
4820 * Make a region list using:
4821 * (a) any selected regions
4822 * (b) the intersection of any selected tracks and the edit point(*)
4823 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4825 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4827 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4831 Editor::get_regions_from_selection_and_edit_point (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4833 RegionSelection regions;
4835 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4836 regions.add (entered_regionview);
4838 regions = selection->regions;
4841 if ( regions.empty() ) {
4842 TrackViewList tracks = selection->tracks;
4844 if (!tracks.empty()) {
4845 /* no region selected or entered, but some selected tracks:
4846 * act on all regions on the selected tracks at the edit point
4848 samplepos_t const where = get_preferred_edit_position (ignore, from_context_menu, from_outside_canvas);
4849 get_regions_at(regions, where, tracks);
4856 /** Get regions using the following method:
4858 * Make a region list using:
4859 * (a) any selected regions
4860 * (b) the intersection of any selected tracks and the edit point(*)
4861 * (c) if neither exists, then whatever region is under the mouse
4863 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4865 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4868 Editor::get_regions_from_selection_and_mouse (samplepos_t pos)
4870 RegionSelection regions;
4872 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4873 regions.add (entered_regionview);
4875 regions = selection->regions;
4878 if ( regions.empty() ) {
4879 TrackViewList tracks = selection->tracks;
4881 if (!tracks.empty()) {
4882 /* no region selected or entered, but some selected tracks:
4883 * act on all regions on the selected tracks at the edit point
4885 get_regions_at(regions, pos, tracks);
4892 /** Start with regions that are selected, or the entered regionview if none are selected.
4893 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4894 * of the regions that we started with.
4898 Editor::get_regions_from_selection_and_entered () const
4900 RegionSelection regions = selection->regions;
4902 if (regions.empty() && entered_regionview) {
4903 regions.add (entered_regionview);
4910 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4912 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4913 RouteTimeAxisView* rtav;
4915 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4916 boost::shared_ptr<Playlist> pl;
4917 std::vector<boost::shared_ptr<Region> > results;
4918 boost::shared_ptr<Track> tr;
4920 if ((tr = rtav->track()) == 0) {
4925 if ((pl = (tr->playlist())) != 0) {
4926 boost::shared_ptr<Region> r = pl->region_by_id (id);
4928 RegionView* rv = rtav->view()->find_view (r);
4930 regions.push_back (rv);
4939 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Temporal::Beats> > > > > &selection) const
4942 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4943 MidiTimeAxisView* mtav;
4945 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4947 mtav->get_per_region_note_selection (selection);
4954 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4956 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4958 RouteTimeAxisView* tatv;
4960 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4962 boost::shared_ptr<Playlist> pl;
4963 vector<boost::shared_ptr<Region> > results;
4965 boost::shared_ptr<Track> tr;
4967 if ((tr = tatv->track()) == 0) {
4972 if ((pl = (tr->playlist())) != 0) {
4973 if (src_comparison) {
4974 pl->get_source_equivalent_regions (region, results);
4976 pl->get_region_list_equivalent_regions (region, results);
4980 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4981 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4982 regions.push_back (marv);
4991 Editor::regionview_from_region (boost::shared_ptr<Region> region) const
4993 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4994 RouteTimeAxisView* tatv;
4995 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4996 if (!tatv->track()) {
4999 RegionView* marv = tatv->view()->find_view (region);
5009 Editor::rtav_from_route (boost::shared_ptr<Route> route) const
5011 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5012 RouteTimeAxisView* rtav;
5013 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
5014 if (rtav->route() == route) {
5023 Editor::show_rhythm_ferret ()
5025 if (rhythm_ferret == 0) {
5026 rhythm_ferret = new RhythmFerret(*this);
5029 rhythm_ferret->set_session (_session);
5030 rhythm_ferret->show ();
5031 rhythm_ferret->present ();
5035 Editor::first_idle ()
5037 MessageDialog* dialog = 0;
5039 if (track_views.size() > 1) {
5040 Timers::TimerSuspender t;
5041 dialog = new MessageDialog (
5042 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5046 ARDOUR_UI::instance()->flush_pending (60);
5049 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5053 /* now that all regionviews should exist, setup region selection */
5057 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5058 /* this is cumulative: rs is NOT cleared each time */
5059 get_regionviews_by_id (*pr, rs);
5062 selection->set (rs);
5064 // first idle adds route children (automation tracks), so we need to redisplay here
5065 _routes->redisplay ();
5069 if (_session->undo_depth() == 0) {
5070 undo_action->set_sensitive(false);
5072 redo_action->set_sensitive(false);
5073 begin_selection_op_history ();
5079 Editor::_idle_resize (gpointer arg)
5081 return ((Editor*)arg)->idle_resize ();
5085 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5087 if (resize_idle_id < 0) {
5088 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5089 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5090 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5092 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5093 _pending_resize_amount = 0;
5096 /* make a note of the smallest resulting height, so that we can clamp the
5097 lower limit at TimeAxisView::hSmall */
5099 int32_t min_resulting = INT32_MAX;
5101 _pending_resize_amount += h;
5102 _pending_resize_view = view;
5104 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5106 if (selection->tracks.contains (_pending_resize_view)) {
5107 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5108 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5112 if (min_resulting < 0) {
5117 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5118 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5122 /** Handle pending resizing of tracks */
5124 Editor::idle_resize ()
5126 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5128 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5129 selection->tracks.contains (_pending_resize_view)) {
5131 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5132 if (*i != _pending_resize_view) {
5133 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5138 _pending_resize_amount = 0;
5139 _group_tabs->set_dirty ();
5140 resize_idle_id = -1;
5148 ENSURE_GUI_THREAD (*this, &Editor::located);
5151 playhead_cursor->set_position (_session->audible_sample ());
5152 if (_follow_playhead && !_pending_initial_locate) {
5153 reset_x_origin_to_follow_playhead ();
5157 _pending_locate_request = false;
5158 _pending_initial_locate = false;
5159 _last_update_time = 0;
5163 Editor::region_view_added (RegionView * rv)
5165 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5167 list<pair<PBD::ID const, list<Evoral::event_id_t> > >::iterator rnote;
5168 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5169 if (rv->region()->id () == (*rnote).first) {
5170 mrv->select_notes ((*rnote).second);
5171 selection->pending_midi_note_selection.erase(rnote);
5177 _summary->set_background_dirty ();
5179 mark_region_boundary_cache_dirty ();
5183 Editor::region_view_removed ()
5185 _summary->set_background_dirty ();
5187 mark_region_boundary_cache_dirty ();
5191 Editor::axis_view_by_stripable (boost::shared_ptr<Stripable> s) const
5193 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5194 if ((*j)->stripable() == s) {
5203 Editor::axis_view_by_control (boost::shared_ptr<AutomationControl> c) const
5205 for (TrackViewList::const_iterator j = track_views.begin (); j != track_views.end(); ++j) {
5206 if ((*j)->control() == c) {
5210 TimeAxisView::Children kids = (*j)->get_child_list ();
5212 for (TimeAxisView::Children::iterator k = kids.begin(); k != kids.end(); ++k) {
5213 if ((*k)->control() == c) {
5223 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5227 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5228 TimeAxisView* tv = time_axis_view_from_stripable (*i);
5238 Editor::suspend_route_redisplay ()
5241 _routes->suspend_redisplay();
5246 Editor::resume_route_redisplay ()
5249 _routes->redisplay(); // queue redisplay
5250 _routes->resume_redisplay();
5255 Editor::add_vcas (VCAList& vlist)
5259 for (VCAList::iterator v = vlist.begin(); v != vlist.end(); ++v) {
5260 sl.push_back (boost::dynamic_pointer_cast<Stripable> (*v));
5263 add_stripables (sl);
5267 Editor::add_routes (RouteList& rlist)
5271 for (RouteList::iterator r = rlist.begin(); r != rlist.end(); ++r) {
5275 add_stripables (sl);
5279 Editor::add_stripables (StripableList& sl)
5281 list<TimeAxisView*> new_views;
5282 boost::shared_ptr<VCA> v;
5283 boost::shared_ptr<Route> r;
5284 TrackViewList new_selection;
5285 bool from_scratch = (track_views.size() == 0);
5287 sl.sort (Stripable::Sorter());
5289 for (StripableList::iterator s = sl.begin(); s != sl.end(); ++s) {
5291 if ((v = boost::dynamic_pointer_cast<VCA> (*s)) != 0) {
5293 VCATimeAxisView* vtv = new VCATimeAxisView (*this, _session, *_track_canvas);
5295 new_views.push_back (vtv);
5297 } else if ((r = boost::dynamic_pointer_cast<Route> (*s)) != 0) {
5299 if (r->is_auditioner() || r->is_monitor()) {
5303 RouteTimeAxisView* rtv;
5304 DataType dt = r->input()->default_type();
5306 if (dt == ARDOUR::DataType::AUDIO) {
5307 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5309 } else if (dt == ARDOUR::DataType::MIDI) {
5310 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5313 throw unknown_type();
5316 new_views.push_back (rtv);
5317 track_views.push_back (rtv);
5318 new_selection.push_back (rtv);
5320 rtv->effective_gain_display ();
5322 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5323 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5327 if (new_views.size() > 0) {
5328 _routes->time_axis_views_added (new_views);
5329 //_summary->routes_added (new_selection); /* XXX requires RouteTimeAxisViewList */
5332 /* note: !new_selection.empty() means that we got some routes rather
5336 if (!from_scratch && !new_selection.empty()) {
5337 selection->set (new_selection);
5338 begin_selection_op_history();
5341 if (show_editor_mixer_when_tracks_arrive && !new_selection.empty()) {
5342 show_editor_mixer (true);
5345 editor_list_button.set_sensitive (true);
5349 Editor::timeaxisview_deleted (TimeAxisView *tv)
5351 if (tv == entered_track) {
5355 if (_session && _session->deletion_in_progress()) {
5356 /* the situation is under control */
5360 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5362 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5364 _routes->route_removed (tv);
5366 TimeAxisView::Children c = tv->get_child_list ();
5367 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5368 if (entered_track == i->get()) {
5373 /* remove it from the list of track views */
5375 TrackViewList::iterator i;
5377 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5378 i = track_views.erase (i);
5381 /* update whatever the current mixer strip is displaying, if revelant */
5383 boost::shared_ptr<Route> route;
5386 route = rtav->route ();
5389 if (current_mixer_strip && current_mixer_strip->route() == route) {
5391 TimeAxisView* next_tv;
5393 if (track_views.empty()) {
5395 } else if (i == track_views.end()) {
5396 next_tv = track_views.front();
5401 // skip VCAs (cannot be selected, n/a in editor-mixer)
5402 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5403 /* VCAs are sorted last in line -- route_sorter.h, jump to top */
5404 next_tv = track_views.front();
5406 if (dynamic_cast<VCATimeAxisView*> (next_tv)) {
5407 /* just in case: no master, only a VCA remains */
5413 set_selected_mixer_strip (*next_tv);
5415 /* make the editor mixer strip go away setting the
5416 * button to inactive (which also unticks the menu option)
5419 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5425 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5431 DisplaySuspender ds;
5432 PresentationInfo::ChangeSuspender cs;
5434 if (apply_to_selection) {
5435 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5437 TrackSelection::iterator j = i;
5440 hide_track_in_display (*i, false);
5445 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5447 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5448 // this will hide the mixer strip
5449 set_selected_mixer_strip (*tv);
5452 _routes->hide_track_in_display (*tv);
5457 Editor::show_track_in_display (TimeAxisView* tv, bool move_into_view)
5462 _routes->show_track_in_display (*tv);
5463 if (move_into_view) {
5464 ensure_time_axis_view_is_visible (*tv, false);
5469 Editor::sync_track_view_list_and_routes ()
5471 track_views = TrackViewList (_routes->views ());
5473 _summary->set_background_dirty();
5474 _group_tabs->set_dirty ();
5476 return false; // do not call again (until needed)
5480 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5482 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5487 /** Find a StripableTimeAxisView by the ID of its stripable */
5488 StripableTimeAxisView*
5489 Editor::get_stripable_time_axis_by_id (const PBD::ID& id) const
5491 StripableTimeAxisView* v;
5493 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5494 if((v = dynamic_cast<StripableTimeAxisView*>(*i)) != 0) {
5495 if(v->stripable()->id() == id) {
5505 Editor::fit_route_group (RouteGroup *g)
5507 TrackViewList ts = axis_views_from_routes (g->route_list ());
5512 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5514 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5517 _session->cancel_audition ();
5521 if (_session->is_auditioning()) {
5522 _session->cancel_audition ();
5523 if (r == last_audition_region) {
5528 _session->audition_region (r);
5529 last_audition_region = r;
5534 Editor::hide_a_region (boost::shared_ptr<Region> r)
5536 r->set_hidden (true);
5540 Editor::show_a_region (boost::shared_ptr<Region> r)
5542 r->set_hidden (false);
5546 Editor::audition_region_from_region_list ()
5548 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5552 Editor::hide_region_from_region_list ()
5554 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5558 Editor::show_region_in_region_list ()
5560 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5564 Editor::step_edit_status_change (bool yn)
5567 start_step_editing ();
5569 stop_step_editing ();
5574 Editor::start_step_editing ()
5576 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5580 Editor::stop_step_editing ()
5582 step_edit_connection.disconnect ();
5586 Editor::check_step_edit ()
5588 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5589 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5591 mtv->check_step_edit ();
5595 return true; // do it again, till we stop
5599 Editor::scroll_press (Direction dir)
5601 ++_scroll_callbacks;
5603 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5604 /* delay the first auto-repeat */
5610 scroll_backward (1);
5618 scroll_up_one_track ();
5622 scroll_down_one_track ();
5626 /* do hacky auto-repeat */
5627 if (!_scroll_connection.connected ()) {
5629 _scroll_connection = Glib::signal_timeout().connect (
5630 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5633 _scroll_callbacks = 0;
5640 Editor::scroll_release ()
5642 _scroll_connection.disconnect ();
5645 /** Queue a change for the Editor viewport x origin to follow the playhead */
5647 Editor::reset_x_origin_to_follow_playhead ()
5649 samplepos_t const sample = playhead_cursor->current_sample ();
5651 if (sample < _leftmost_sample || sample > _leftmost_sample + current_page_samples()) {
5653 if (_session->transport_speed() < 0) {
5655 if (sample > (current_page_samples() / 2)) {
5656 center_screen (sample-(current_page_samples()/2));
5658 center_screen (current_page_samples()/2);
5665 if (sample < _leftmost_sample) {
5667 if (_session->transport_rolling()) {
5668 /* rolling; end up with the playhead at the right of the page */
5669 l = sample - current_page_samples ();
5671 /* not rolling: end up with the playhead 1/4 of the way along the page */
5672 l = sample - current_page_samples() / 4;
5676 if (_session->transport_rolling()) {
5677 /* rolling: end up with the playhead on the left of the page */
5680 /* not rolling: end up with the playhead 3/4 of the way along the page */
5681 l = sample - 3 * current_page_samples() / 4;
5689 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5695 Editor::super_rapid_screen_update ()
5697 if (!_session || !_session->engine().running()) {
5701 /* METERING / MIXER STRIPS */
5703 /* update track meters, if required */
5704 if (contents().is_mapped() && meters_running) {
5705 RouteTimeAxisView* rtv;
5706 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5707 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5708 rtv->fast_update ();
5713 /* and any current mixer strip */
5714 if (current_mixer_strip) {
5715 current_mixer_strip->fast_update ();
5718 bool latent_locate = false;
5719 samplepos_t sample = _session->audible_sample (&latent_locate);
5720 const int64_t now = g_get_monotonic_time ();
5723 if (_session->exporting ()) {
5724 /* freewheel/export may be faster or slower than transport_speed() / SR.
5725 * Also exporting multiple ranges locates/jumps without a _pending_locate_request.
5727 _last_update_time = 0;
5730 if (_last_update_time > 0) {
5731 /* interpolate and smoothen playhead position */
5732 const double ds = (now - _last_update_time) * _session->transport_speed() * _session->nominal_sample_rate () * 1e-6;
5733 samplepos_t guess = playhead_cursor->current_sample () + rint (ds);
5734 err = sample - guess;
5736 guess += err * .12 + _err_screen_engine; // time-constant based on 25fps (super_rapid_screen_update)
5737 _err_screen_engine += .0144 * (err - _err_screen_engine); // tc^2
5740 printf ("eng: %ld gui:%ld (%+6.1f) diff: %6.1f (err: %7.2f)\n",
5742 err, _err_screen_engine);
5747 _err_screen_engine = 0;
5750 if (err > 8192 || latent_locate) {
5751 // in case of x-runs or freewheeling
5752 _last_update_time = 0;
5753 sample = _session->audible_sample ();
5755 _last_update_time = now;
5758 //snapped cursor stuff ( the snapped_cursor shows where an operation is going to occur )
5760 MusicSample where (sample, 0);
5761 if ( !UIConfiguration::instance().get_show_snapped_cursor() ) {
5762 snapped_cursor->hide ();
5763 } else if ( _edit_point == EditAtPlayhead && !_dragging_playhead) {
5764 snap_to (where); // can't use snap_to_with_modifier?
5765 snapped_cursor->set_position (where.sample);
5766 snapped_cursor->show ();
5767 } else if ( _edit_point == EditAtSelectedMarker ) {
5768 //NOTE: I don't think EditAtSelectedMarker should snap. they are what they are.
5769 //however, the current editing code -does- snap so I'll draw it that way for now.
5770 if ( !selection->markers.empty() ) {
5771 MusicSample ms (selection->markers.front()->position(), 0);
5772 snap_to (ms); // should use snap_to_with_modifier?
5773 snapped_cursor->set_position ( ms.sample );
5774 snapped_cursor->show ();
5776 } else if (mouse_sample (where.sample, ignored)) { //cursor is in the editing canvas. show it.
5777 snapped_cursor->show ();
5778 } else { //mouse is out of the editing canvas. hide the snapped_cursor
5779 snapped_cursor->hide ();
5782 /* There are a few reasons why we might not update the playhead / viewport stuff:
5784 * 1. we don't update things when there's a pending locate request, otherwise
5785 * when the editor requests a locate there is a chance that this method
5786 * will move the playhead before the locate request is processed, causing
5788 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5789 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5791 if (_pending_locate_request) {
5792 _last_update_time = 0;
5796 if (_dragging_playhead) {
5797 _last_update_time = 0;
5801 if (playhead_cursor->current_sample () == sample) {
5805 playhead_cursor->set_position (sample);
5807 if (_session->requested_return_sample() >= 0) {
5808 _last_update_time = 0;
5812 if (!_follow_playhead || pending_visual_change.being_handled) {
5813 /* We only do this if we aren't already
5814 * handling a visual change (ie if
5815 * pending_visual_change.being_handled is
5816 * false) so that these requests don't stack
5817 * up there are too many of them to handle in
5823 if (!_stationary_playhead) {
5824 reset_x_origin_to_follow_playhead ();
5826 samplepos_t const sample = playhead_cursor->current_sample ();
5827 double target = ((double)sample - (double)current_page_samples() / 2.0);
5828 if (target <= 0.0) {
5831 // compare to EditorCursor::set_position()
5832 double const old_pos = sample_to_pixel_unrounded (_leftmost_sample);
5833 double const new_pos = sample_to_pixel_unrounded (target);
5834 if (rint (new_pos) != rint (old_pos)) {
5835 reset_x_origin (pixel_to_sample (new_pos));
5842 Editor::session_going_away ()
5844 _have_idled = false;
5846 _session_connections.drop_connections ();
5848 super_rapid_screen_update_connection.disconnect ();
5850 selection->clear ();
5851 cut_buffer->clear ();
5853 clicked_regionview = 0;
5854 clicked_axisview = 0;
5855 clicked_routeview = 0;
5856 entered_regionview = 0;
5858 _last_update_time = 0;
5861 playhead_cursor->hide ();
5863 /* rip everything out of the list displays */
5867 _route_groups->clear ();
5869 /* do this first so that deleting a track doesn't reset cms to null
5870 and thus cause a leak.
5873 if (current_mixer_strip) {
5874 if (current_mixer_strip->get_parent() != 0) {
5875 global_hpacker.remove (*current_mixer_strip);
5877 delete current_mixer_strip;
5878 current_mixer_strip = 0;
5881 /* delete all trackviews */
5883 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5886 track_views.clear ();
5888 nudge_clock->set_session (0);
5890 editor_list_button.set_active(false);
5891 editor_list_button.set_sensitive(false);
5893 /* clear tempo/meter rulers */
5894 remove_metric_marks ();
5895 clear_marker_display ();
5901 stop_step_editing ();
5905 /* get rid of any existing editor mixer strip */
5907 WindowTitle title(Glib::get_application_name());
5908 title += _("Editor");
5910 own_window()->set_title (title.get_string());
5913 SessionHandlePtr::session_going_away ();
5917 Editor::trigger_script (int i)
5919 LuaInstance::instance()-> call_action (i);
5923 Editor::show_editor_list (bool yn)
5926 _editor_list_vbox.show ();
5928 _editor_list_vbox.hide ();
5933 Editor::change_region_layering_order (bool from_context_menu)
5935 const samplepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5937 if (!clicked_routeview) {
5938 if (layering_order_editor) {
5939 layering_order_editor->hide ();
5944 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5950 boost::shared_ptr<Playlist> pl = track->playlist();
5956 if (layering_order_editor == 0) {
5957 layering_order_editor = new RegionLayeringOrderEditor (*this);
5960 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5961 layering_order_editor->maybe_present ();
5965 Editor::update_region_layering_order_editor ()
5967 if (layering_order_editor && layering_order_editor->is_visible ()) {
5968 change_region_layering_order (true);
5973 Editor::setup_fade_images ()
5975 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5976 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5977 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5978 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5979 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5981 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5982 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5983 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5984 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5985 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5989 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5991 Editor::action_menu_item (std::string const & name)
5993 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5996 return *manage (a->create_menu_item ());
6000 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
6002 EventBox* b = manage (new EventBox);
6003 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
6004 Label* l = manage (new Label (name));
6008 _the_notebook.append_page (widget, *b);
6012 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
6014 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
6015 _the_notebook.set_current_page (_the_notebook.page_num (*page));
6018 if (ev->type == GDK_2BUTTON_PRESS) {
6020 /* double-click on a notebook tab shrinks or expands the notebook */
6022 if (_notebook_shrunk) {
6023 if (pre_notebook_shrink_pane_width) {
6024 edit_pane.set_divider (0, *pre_notebook_shrink_pane_width);
6026 _notebook_shrunk = false;
6028 pre_notebook_shrink_pane_width = edit_pane.get_divider();
6030 /* this expands the LHS of the edit pane to cover the notebook
6031 PAGE but leaves the tabs visible.
6033 edit_pane.set_divider (0, edit_pane.get_divider() + page->get_width());
6034 _notebook_shrunk = true;
6042 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6044 using namespace Menu_Helpers;
6046 MenuList& items = _control_point_context_menu.items ();
6049 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
6050 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
6051 if (!can_remove_control_point (item)) {
6052 items.back().set_sensitive (false);
6055 _control_point_context_menu.popup (event->button.button, event->button.time);
6059 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
6061 using namespace Menu_Helpers;
6063 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
6068 /* We need to get the selection here and pass it to the operations, since
6069 popping up the menu will cause a region leave event which clears
6070 entered_regionview. */
6072 MidiRegionView& mrv = note->region_view();
6073 const RegionSelection rs = get_regions_from_selection_and_entered ();
6074 const uint32_t sel_size = mrv.selection_size ();
6076 MenuList& items = _note_context_menu.items();
6080 items.push_back(MenuElem(_("Delete"),
6081 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
6084 items.push_back(MenuElem(_("Edit..."),
6085 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
6086 if (sel_size != 1) {
6087 items.back().set_sensitive (false);
6090 items.push_back(MenuElem(_("Transpose..."),
6091 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
6094 items.push_back(MenuElem(_("Legatize"),
6095 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
6097 items.back().set_sensitive (false);
6100 items.push_back(MenuElem(_("Quantize..."),
6101 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
6103 items.push_back(MenuElem(_("Remove Overlap"),
6104 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
6106 items.back().set_sensitive (false);
6109 items.push_back(MenuElem(_("Transform..."),
6110 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
6112 _note_context_menu.popup (event->button.button, event->button.time);
6116 Editor::zoom_vertical_modifier_released()
6118 _stepping_axis_view = 0;
6122 Editor::ui_parameter_changed (string parameter)
6124 if (parameter == "icon-set") {
6125 while (!_cursor_stack.empty()) {
6126 _cursor_stack.pop_back();
6128 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
6129 _cursor_stack.push_back(_cursors->grabber);
6130 edit_pane.set_drag_cursor (*_cursors->expand_left_right);
6131 editor_summary_pane.set_drag_cursor (*_cursors->expand_up_down);
6133 } else if (parameter == "draggable-playhead") {
6134 if (_verbose_cursor) {
6135 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
6141 Editor::use_own_window (bool and_fill_it)
6143 bool new_window = !own_window();
6145 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
6147 if (win && new_window) {
6148 win->set_name ("EditorWindow");
6150 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
6152 // win->signal_realize().connect (*this, &Editor::on_realize);
6153 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
6154 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
6155 win->set_data ("ardour-bindings", bindings);
6160 DisplaySuspender ds;
6161 contents().show_all ();
6163 /* XXX: this is a bit unfortunate; it would probably
6164 be nicer if we could just call show () above rather
6165 than needing the show_all ()
6168 /* re-hide stuff if necessary */
6169 editor_list_button_toggled ();
6170 parameter_changed ("show-summary");
6171 parameter_changed ("show-group-tabs");
6172 parameter_changed ("show-zoom-tools");
6174 /* now reset all audio_time_axis heights, because widgets might need
6180 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6181 tv = (static_cast<TimeAxisView*>(*i));
6182 tv->reset_height ();
6185 if (current_mixer_strip) {
6186 current_mixer_strip->hide_things ();
6187 current_mixer_strip->parameter_changed ("mixer-element-visibility");