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/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include <gtkmm2ext/keyboard.h>
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/analysis_graph.h"
69 #include "ardour/audio_track.h"
70 #include "ardour/audioengine.h"
71 #include "ardour/audioregion.h"
72 #include "ardour/lmath.h"
73 #include "ardour/location.h"
74 #include "ardour/profile.h"
75 #include "ardour/route_group.h"
76 #include "ardour/session_playlists.h"
77 #include "ardour/tempo.h"
78 #include "ardour/utils.h"
80 #include "canvas/debug.h"
81 #include "canvas/text.h"
83 #include "control_protocol/control_protocol.h"
86 #include "analysis_window.h"
87 #include "audio_clock.h"
88 #include "audio_region_view.h"
89 #include "audio_streamview.h"
90 #include "audio_time_axis.h"
91 #include "automation_time_axis.h"
92 #include "bundle_manager.h"
93 #include "crossfade_edit.h"
97 #include "editor_cursors.h"
98 #include "editor_drag.h"
99 #include "editor_group_tabs.h"
100 #include "editor_locations.h"
101 #include "editor_regions.h"
102 #include "editor_route_groups.h"
103 #include "editor_routes.h"
104 #include "editor_snapshots.h"
105 #include "editor_summary.h"
106 #include "export_report.h"
107 #include "global_port_matrix.h"
108 #include "gui_object.h"
109 #include "gui_thread.h"
110 #include "keyboard.h"
111 #include "keyeditor.h"
112 #include "luainstance.h"
114 #include "midi_region_view.h"
115 #include "midi_time_axis.h"
116 #include "mixer_strip.h"
117 #include "mixer_ui.h"
118 #include "mouse_cursors.h"
119 #include "note_base.h"
120 #include "playlist_selector.h"
121 #include "public_editor.h"
122 #include "quantize_dialog.h"
123 #include "region_layering_order_editor.h"
124 #include "rgb_macros.h"
125 #include "rhythm_ferret.h"
126 #include "selection.h"
127 #include "simple_progress_dialog.h"
129 #include "tempo_lines.h"
130 #include "time_axis_view.h"
132 #include "tooltips.h"
133 #include "ui_config.h"
135 #include "verbose_cursor.h"
140 using namespace ARDOUR;
141 using namespace ARDOUR_UI_UTILS;
144 using namespace Glib;
145 using namespace Gtkmm2ext;
146 using namespace Editing;
148 using PBD::internationalize;
150 using Gtkmm2ext::Keyboard;
152 double Editor::timebar_height = 15.0;
154 static const gchar *_snap_type_strings[] = {
188 static const gchar *_snap_mode_strings[] = {
195 static const gchar *_edit_point_strings[] = {
202 static const gchar *_edit_mode_strings[] = {
210 static const gchar *_zoom_focus_strings[] = {
220 #ifdef USE_RUBBERBAND
221 static const gchar *_rb_opt_strings[] = {
224 N_("Balanced multitimbral mixture"),
225 N_("Unpitched percussion with stable notes"),
226 N_("Crisp monophonic instrumental"),
227 N_("Unpitched solo percussion"),
228 N_("Resample without preserving pitch"),
233 #define COMBO_TRIANGLE_WIDTH 25 // ArdourButton _diameter (11) + 2 * arrow-padding (2*2) + 2 * text-padding (2*5)
236 pane_size_watcher (Paned* pane)
238 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
242 Quartz: impossible to access
244 so stop that by preventing it from ever getting too narrow. 35
245 pixels is basically a rough guess at the tab width.
250 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
252 gint pos = pane->get_position ();
254 if (pos > max_width_of_lhs) {
255 pane->set_position (max_width_of_lhs);
260 : PublicEditor (global_hpacker)
261 , editor_mixer_strip_width (Wide)
262 , constructed (false)
263 , _playlist_selector (0)
264 , no_save_visual (false)
266 , samples_per_pixel (2048)
267 , zoom_focus (ZoomFocusPlayhead)
268 , mouse_mode (MouseObject)
269 , pre_internal_snap_type (SnapToBeat)
270 , pre_internal_snap_mode (SnapOff)
271 , internal_snap_type (SnapToBeat)
272 , internal_snap_mode (SnapOff)
273 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
274 , _notebook_shrunk (false)
275 , location_marker_color (0)
276 , location_range_color (0)
277 , location_loop_color (0)
278 , location_punch_color (0)
279 , location_cd_marker_color (0)
281 , _show_marker_lines (false)
282 , clicked_axisview (0)
283 , clicked_routeview (0)
284 , clicked_regionview (0)
285 , clicked_selection (0)
286 , clicked_control_point (0)
287 , button_release_can_deselect (true)
288 , _mouse_changed_selection (false)
289 , region_edit_menu_split_item (0)
290 , region_edit_menu_split_multichannel_item (0)
291 , track_region_edit_playlist_menu (0)
292 , track_edit_playlist_submenu (0)
293 , track_selection_edit_playlist_submenu (0)
294 , _popup_region_menu_item (0)
296 , _track_canvas_viewport (0)
297 , within_track_canvas (false)
298 , _verbose_cursor (0)
302 , range_marker_group (0)
303 , transport_marker_group (0)
304 , cd_marker_group (0)
305 , _time_markers_group (0)
306 , hv_scroll_group (0)
308 , cursor_scroll_group (0)
309 , no_scroll_group (0)
310 , _trackview_group (0)
311 , _drag_motion_group (0)
312 , _canvas_drop_zone (0)
313 , no_ruler_shown_update (false)
314 , ruler_grabbed_widget (0)
316 , minsec_mark_interval (0)
317 , minsec_mark_modulo (0)
319 , timecode_mark_modulo (0)
320 , timecode_nmarks (0)
321 , _samples_ruler_interval (0)
324 , bbt_bar_helper_on (0)
325 , bbt_accent_modulo (0)
330 , visible_timebars (0)
331 , editor_ruler_menu (0)
335 , range_marker_bar (0)
336 , transport_marker_bar (0)
338 , minsec_label (_("Mins:Secs"))
339 , bbt_label (_("Bars:Beats"))
340 , timecode_label (_("Timecode"))
341 , samples_label (_("Samples"))
342 , tempo_label (_("Tempo"))
343 , meter_label (_("Meter"))
344 , mark_label (_("Location Markers"))
345 , range_mark_label (_("Range Markers"))
346 , transport_mark_label (_("Loop/Punch Ranges"))
347 , cd_mark_label (_("CD Markers"))
348 , videotl_label (_("Video Timeline"))
350 , playhead_cursor (0)
351 , edit_packer (4, 4, true)
352 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
353 , horizontal_adjustment (0.0, 0.0, 1e16)
354 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
355 , controls_layout (unused_adjustment, vertical_adjustment)
356 , _scroll_callbacks (0)
357 , _visible_canvas_width (0)
358 , _visible_canvas_height (0)
359 , _full_canvas_height (0)
360 , edit_controls_left_menu (0)
361 , edit_controls_right_menu (0)
362 , last_update_frame (0)
363 , cut_buffer_start (0)
364 , cut_buffer_length (0)
365 , button_bindings (0)
369 , current_interthread_info (0)
370 , analysis_window (0)
371 , select_new_marker (false)
373 , scrubbing_direction (0)
374 , scrub_reversals (0)
375 , scrub_reverse_distance (0)
376 , have_pending_keyboard_selection (false)
377 , pending_keyboard_selection_start (0)
378 , _snap_type (SnapToBeat)
379 , _snap_mode (SnapOff)
380 , snap_threshold (5.0)
381 , ignore_gui_changes (false)
382 , _drags (new DragManager (this))
384 /* , last_event_time { 0, 0 } */ /* this initialization style requires C++11 */
385 , _dragging_playhead (false)
386 , _dragging_edit_point (false)
387 , _show_measures (true)
388 , _follow_playhead (true)
389 , _stationary_playhead (false)
392 , global_rect_group (0)
393 , time_line_group (0)
394 , tempo_or_meter_marker_menu (0)
396 , range_marker_menu (0)
397 , transport_marker_menu (0)
398 , new_transport_marker_menu (0)
400 , marker_menu_item (0)
401 , bbt_beat_subdivision (4)
402 , _visible_track_count (-1)
403 , toolbar_selection_clock_table (2,3)
404 , automation_mode_button (_("mode"))
405 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
406 , selection (new Selection (this))
407 , cut_buffer (new Selection (this))
408 , _selection_memento (new SelectionMemento())
409 , _all_region_actions_sensitized (false)
410 , _ignore_region_action (false)
411 , _last_region_menu_was_main (false)
412 , _ignore_follow_edits (false)
413 , cd_marker_bar_drag_rect (0)
414 , range_bar_drag_rect (0)
415 , transport_bar_drag_rect (0)
416 , transport_bar_range_rect (0)
417 , transport_bar_preroll_rect (0)
418 , transport_bar_postroll_rect (0)
419 , transport_loop_range_rect (0)
420 , transport_punch_range_rect (0)
421 , transport_punchin_line (0)
422 , transport_punchout_line (0)
423 , transport_preroll_rect (0)
424 , transport_postroll_rect (0)
426 , rubberband_rect (0)
432 , autoscroll_horizontal_allowed (false)
433 , autoscroll_vertical_allowed (false)
435 , autoscroll_widget (0)
436 , show_gain_after_trim (false)
437 , selection_op_cmd_depth (0)
438 , selection_op_history_it (0)
439 , no_save_instant (false)
441 , current_mixer_strip (0)
442 , show_editor_mixer_when_tracks_arrive (false)
443 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
444 , current_stepping_trackview (0)
445 , last_track_height_step_timestamp (0)
447 , entered_regionview (0)
448 , clear_entered_track (false)
449 , _edit_point (EditAtMouse)
450 , meters_running (false)
452 , _have_idled (false)
453 , resize_idle_id (-1)
454 , _pending_resize_amount (0)
455 , _pending_resize_view (0)
456 , _pending_locate_request (false)
457 , _pending_initial_locate (false)
461 , layering_order_editor (0)
462 , _last_cut_copy_source_track (0)
463 , _region_selection_change_updates_region_list (true)
465 , _following_mixer_selection (false)
466 , _control_point_toggled_on_press (false)
467 , _stepping_axis_view (0)
468 , quantize_dialog (0)
469 , _main_menu_disabler (0)
470 , myactions (X_("editor"))
472 /* we are a singleton */
474 PublicEditor::_instance = this;
478 last_event_time.tv_sec = 0;
479 last_event_time.tv_usec = 0;
481 selection_op_history.clear();
484 snap_type_strings = I18N (_snap_type_strings);
485 snap_mode_strings = I18N (_snap_mode_strings);
486 zoom_focus_strings = I18N (_zoom_focus_strings);
487 edit_mode_strings = I18N (_edit_mode_strings);
488 edit_point_strings = I18N (_edit_point_strings);
489 #ifdef USE_RUBBERBAND
490 rb_opt_strings = I18N (_rb_opt_strings);
494 build_edit_mode_menu();
495 build_zoom_focus_menu();
496 build_track_count_menu();
497 build_snap_mode_menu();
498 build_snap_type_menu();
499 build_edit_point_menu();
501 location_marker_color = UIConfiguration::instance().color ("location marker");
502 location_range_color = UIConfiguration::instance().color ("location range");
503 location_cd_marker_color = UIConfiguration::instance().color ("location cd marker");
504 location_loop_color = UIConfiguration::instance().color ("location loop");
505 location_punch_color = UIConfiguration::instance().color ("location punch");
507 timebar_height = std::max(12., ceil (15. * ARDOUR_UI::ui_scale));
509 TimeAxisView::setup_sizes ();
510 ArdourMarker::setup_sizes (timebar_height);
512 bbt_label.set_name ("EditorRulerLabel");
513 bbt_label.set_size_request (-1, (int)timebar_height);
514 bbt_label.set_alignment (1.0, 0.5);
515 bbt_label.set_padding (5,0);
517 bbt_label.set_no_show_all();
518 minsec_label.set_name ("EditorRulerLabel");
519 minsec_label.set_size_request (-1, (int)timebar_height);
520 minsec_label.set_alignment (1.0, 0.5);
521 minsec_label.set_padding (5,0);
522 minsec_label.hide ();
523 minsec_label.set_no_show_all();
524 timecode_label.set_name ("EditorRulerLabel");
525 timecode_label.set_size_request (-1, (int)timebar_height);
526 timecode_label.set_alignment (1.0, 0.5);
527 timecode_label.set_padding (5,0);
528 timecode_label.hide ();
529 timecode_label.set_no_show_all();
530 samples_label.set_name ("EditorRulerLabel");
531 samples_label.set_size_request (-1, (int)timebar_height);
532 samples_label.set_alignment (1.0, 0.5);
533 samples_label.set_padding (5,0);
534 samples_label.hide ();
535 samples_label.set_no_show_all();
537 tempo_label.set_name ("EditorRulerLabel");
538 tempo_label.set_size_request (-1, (int)timebar_height);
539 tempo_label.set_alignment (1.0, 0.5);
540 tempo_label.set_padding (5,0);
542 tempo_label.set_no_show_all();
544 meter_label.set_name ("EditorRulerLabel");
545 meter_label.set_size_request (-1, (int)timebar_height);
546 meter_label.set_alignment (1.0, 0.5);
547 meter_label.set_padding (5,0);
549 meter_label.set_no_show_all();
551 if (Profile->get_trx()) {
552 mark_label.set_text (_("Markers"));
554 mark_label.set_name ("EditorRulerLabel");
555 mark_label.set_size_request (-1, (int)timebar_height);
556 mark_label.set_alignment (1.0, 0.5);
557 mark_label.set_padding (5,0);
559 mark_label.set_no_show_all();
561 cd_mark_label.set_name ("EditorRulerLabel");
562 cd_mark_label.set_size_request (-1, (int)timebar_height);
563 cd_mark_label.set_alignment (1.0, 0.5);
564 cd_mark_label.set_padding (5,0);
565 cd_mark_label.hide();
566 cd_mark_label.set_no_show_all();
568 videotl_bar_height = 4;
569 videotl_label.set_name ("EditorRulerLabel");
570 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
571 videotl_label.set_alignment (1.0, 0.5);
572 videotl_label.set_padding (5,0);
573 videotl_label.hide();
574 videotl_label.set_no_show_all();
576 range_mark_label.set_name ("EditorRulerLabel");
577 range_mark_label.set_size_request (-1, (int)timebar_height);
578 range_mark_label.set_alignment (1.0, 0.5);
579 range_mark_label.set_padding (5,0);
580 range_mark_label.hide();
581 range_mark_label.set_no_show_all();
583 transport_mark_label.set_name ("EditorRulerLabel");
584 transport_mark_label.set_size_request (-1, (int)timebar_height);
585 transport_mark_label.set_alignment (1.0, 0.5);
586 transport_mark_label.set_padding (5,0);
587 transport_mark_label.hide();
588 transport_mark_label.set_no_show_all();
590 initialize_canvas ();
592 CairoWidget::set_focus_handler (sigc::mem_fun (*this, &Editor::reset_focus));
594 _summary = new EditorSummary (this);
596 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
597 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
599 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
601 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
602 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
604 edit_controls_vbox.set_spacing (0);
605 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
606 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
608 HBox* h = manage (new HBox);
609 _group_tabs = new EditorGroupTabs (this);
610 if (!ARDOUR::Profile->get_trx()) {
611 h->pack_start (*_group_tabs, PACK_SHRINK);
613 h->pack_start (edit_controls_vbox);
614 controls_layout.add (*h);
616 controls_layout.set_name ("EditControlsBase");
617 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
618 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
619 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
621 _cursors = new MouseCursors;
622 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
623 cerr << "Set cursor set to " << UIConfiguration::instance().get_icon_set() << endl;
625 /* Push default cursor to ever-present bottom of cursor stack. */
626 push_canvas_cursor(_cursors->grabber);
628 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
630 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
631 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
632 pad_line_1->set_outline_color (0xFF0000FF);
638 edit_packer.set_col_spacings (0);
639 edit_packer.set_row_spacings (0);
640 edit_packer.set_homogeneous (false);
641 edit_packer.set_border_width (0);
642 edit_packer.set_name ("EditorWindow");
644 time_bars_event_box.add (time_bars_vbox);
645 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
646 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
648 /* labels for the time bars */
649 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
651 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
653 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
655 bottom_hbox.set_border_width (2);
656 bottom_hbox.set_spacing (3);
658 _route_groups = new EditorRouteGroups (this);
659 _routes = new EditorRoutes (this);
660 _regions = new EditorRegions (this);
661 _snapshots = new EditorSnapshots (this);
662 _locations = new EditorLocations (this);
664 /* these are static location signals */
666 Location::start_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
667 Location::end_changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
668 Location::changed.connect (*this, invalidator (*this), boost::bind (&Editor::location_changed, this, _1), gui_context());
670 add_notebook_page (_("Regions"), _regions->widget ());
671 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
672 add_notebook_page (_("Snapshots"), _snapshots->widget ());
673 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
674 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
676 _the_notebook.set_show_tabs (true);
677 _the_notebook.set_scrollable (true);
678 _the_notebook.popup_disable ();
679 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
680 _the_notebook.show_all ();
682 _notebook_shrunk = false;
684 editor_summary_pane.pack1(edit_packer);
686 Button* summary_arrows_left_left = manage (new Button);
687 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
688 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
689 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
691 Button* summary_arrows_left_right = manage (new Button);
692 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
693 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
694 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
696 VBox* summary_arrows_left = manage (new VBox);
697 summary_arrows_left->pack_start (*summary_arrows_left_left);
698 summary_arrows_left->pack_start (*summary_arrows_left_right);
700 Button* summary_arrows_right_up = manage (new Button);
701 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
702 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
703 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
705 Button* summary_arrows_right_down = manage (new Button);
706 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
707 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
708 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
710 VBox* summary_arrows_right = manage (new VBox);
711 summary_arrows_right->pack_start (*summary_arrows_right_up);
712 summary_arrows_right->pack_start (*summary_arrows_right_down);
714 Frame* summary_frame = manage (new Frame);
715 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
717 summary_frame->add (*_summary);
718 summary_frame->show ();
720 _summary_hbox.pack_start (*summary_arrows_left, false, false);
721 _summary_hbox.pack_start (*summary_frame, true, true);
722 _summary_hbox.pack_start (*summary_arrows_right, false, false);
724 if (!ARDOUR::Profile->get_trx()) {
725 editor_summary_pane.pack2 (_summary_hbox);
728 edit_pane.pack1 (editor_summary_pane, true, true);
729 if (!ARDOUR::Profile->get_trx()) {
730 edit_pane.pack2 (_the_notebook, false, true);
733 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
735 /* XXX: editor_summary_pane might need similar to the edit_pane */
737 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
739 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
740 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
742 top_hbox.pack_start (toolbar_frame);
744 HBox *hbox = manage (new HBox);
745 hbox->pack_start (edit_pane, true, true);
747 global_vpacker.pack_start (top_hbox, false, false);
748 global_vpacker.pack_start (*hbox, true, true);
749 global_hpacker.pack_start (global_vpacker, true, true);
751 /* need to show the "contents" widget so that notebook will show if tab is switched to
754 global_hpacker.show ();
756 /* register actions now so that set_state() can find them and set toggles/checks etc */
763 _playlist_selector = new PlaylistSelector();
764 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
766 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
770 nudge_forward_button.set_name ("nudge button");
771 nudge_forward_button.set_icon(ArdourIcon::NudgeRight);
773 nudge_backward_button.set_name ("nudge button");
774 nudge_backward_button.set_icon(ArdourIcon::NudgeLeft);
776 fade_context_menu.set_name ("ArdourContextMenu");
778 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
780 /* allow external control surfaces/protocols to do various things */
782 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
783 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
784 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
785 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
786 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
787 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
788 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
789 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
790 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
791 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
792 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
793 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
794 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
795 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
797 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
798 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
799 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
800 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
801 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
803 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
805 /* problematic: has to return a value and thus cannot be x-thread */
807 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
809 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
810 UIConfiguration::instance().ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
812 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
814 _ignore_region_action = false;
815 _last_region_menu_was_main = false;
816 _popup_region_menu_item = 0;
818 _ignore_follow_edits = false;
820 _show_marker_lines = false;
822 /* Button bindings */
824 button_bindings = new Bindings ("editor-mouse");
826 XMLNode* node = button_settings();
828 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
829 button_bindings->load_operation (**i);
835 /* grab current parameter state */
836 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
837 UIConfiguration::instance().map_parameters (pc);
839 setup_fade_images ();
841 LuaInstance::instance(); // instantiate
842 LuaInstance::instance()->ActionChanged.connect (sigc::mem_fun (*this, &Editor::set_script_action_name));
849 delete button_bindings;
851 delete _route_groups;
852 delete _track_canvas_viewport;
855 delete quantize_dialog;
861 delete _playlist_selector;
863 for (list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
869 Editor::button_settings () const
871 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
872 XMLNode* node = find_named_node (*settings, X_("Buttons"));
875 node = new XMLNode (X_("Buttons"));
882 Editor::get_smart_mode () const
884 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
888 Editor::catch_vanishing_regionview (RegionView *rv)
890 /* note: the selection will take care of the vanishing
891 audioregionview by itself.
894 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
898 if (clicked_regionview == rv) {
899 clicked_regionview = 0;
902 if (entered_regionview == rv) {
903 set_entered_regionview (0);
906 if (!_all_region_actions_sensitized) {
907 sensitize_all_region_actions (true);
912 Editor::set_entered_regionview (RegionView* rv)
914 if (rv == entered_regionview) {
918 if (entered_regionview) {
919 entered_regionview->exited ();
922 entered_regionview = rv;
924 if (entered_regionview != 0) {
925 entered_regionview->entered ();
928 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
929 /* This RegionView entry might have changed what region actions
930 are allowed, so sensitize them all in case a key is pressed.
932 sensitize_all_region_actions (true);
937 Editor::set_entered_track (TimeAxisView* tav)
940 entered_track->exited ();
946 entered_track->entered ();
951 Editor::instant_save ()
953 if (!constructed || !ARDOUR_UI::instance()->session_loaded || no_save_instant) {
958 _session->add_instant_xml(get_state());
960 Config->add_instant_xml(get_state());
965 Editor::control_vertical_zoom_in_all ()
967 tav_zoom_smooth (false, true);
971 Editor::control_vertical_zoom_out_all ()
973 tav_zoom_smooth (true, true);
977 Editor::control_vertical_zoom_in_selected ()
979 tav_zoom_smooth (false, false);
983 Editor::control_vertical_zoom_out_selected ()
985 tav_zoom_smooth (true, false);
989 Editor::control_view (uint32_t view)
991 goto_visual_state (view);
995 Editor::control_unselect ()
997 selection->clear_tracks ();
1001 Editor::control_select (uint32_t rid, Selection::Operation op)
1003 /* handles the (static) signal from the ControlProtocol class that
1004 * requests setting the selected track to a given RID
1011 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
1017 TimeAxisView* tav = axis_view_from_route (r);
1021 case Selection::Add:
1022 selection->add (tav);
1024 case Selection::Toggle:
1025 selection->toggle (tav);
1027 case Selection::Extend:
1029 case Selection::Set:
1030 selection->set (tav);
1034 selection->clear_tracks ();
1039 Editor::control_step_tracks_up ()
1041 scroll_tracks_up_line ();
1045 Editor::control_step_tracks_down ()
1047 scroll_tracks_down_line ();
1051 Editor::control_scroll (float fraction)
1053 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1059 double step = fraction * current_page_samples();
1062 _control_scroll_target is an optional<T>
1064 it acts like a pointer to an framepos_t, with
1065 a operator conversion to boolean to check
1066 that it has a value could possibly use
1067 playhead_cursor->current_frame to store the
1068 value and a boolean in the class to know
1069 when it's out of date
1072 if (!_control_scroll_target) {
1073 _control_scroll_target = _session->transport_frame();
1074 _dragging_playhead = true;
1077 if ((fraction < 0.0f) && (*_control_scroll_target <= (framepos_t) fabs(step))) {
1078 *_control_scroll_target = 0;
1079 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1080 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1082 *_control_scroll_target += (framepos_t) trunc (step);
1085 /* move visuals, we'll catch up with it later */
1087 playhead_cursor->set_position (*_control_scroll_target);
1088 UpdateAllTransportClocks (*_control_scroll_target);
1090 if (*_control_scroll_target > (current_page_samples() / 2)) {
1091 /* try to center PH in window */
1092 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1098 Now we do a timeout to actually bring the session to the right place
1099 according to the playhead. This is to avoid reading disk buffers on every
1100 call to control_scroll, which is driven by ScrollTimeline and therefore
1101 probably by a control surface wheel which can generate lots of events.
1103 /* cancel the existing timeout */
1105 control_scroll_connection.disconnect ();
1107 /* add the next timeout */
1109 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1113 Editor::deferred_control_scroll (framepos_t /*target*/)
1115 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1116 // reset for next stream
1117 _control_scroll_target = boost::none;
1118 _dragging_playhead = false;
1123 Editor::access_action (std::string action_group, std::string action_item)
1129 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1132 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1140 Editor::on_realize ()
1144 if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
1145 start_lock_event_timing ();
1150 Editor::start_lock_event_timing ()
1152 /* check if we should lock the GUI every 30 seconds */
1154 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1158 Editor::generic_event_handler (GdkEvent* ev)
1161 case GDK_BUTTON_PRESS:
1162 case GDK_BUTTON_RELEASE:
1163 case GDK_MOTION_NOTIFY:
1165 case GDK_KEY_RELEASE:
1166 if (contents().is_mapped()) {
1167 gettimeofday (&last_event_time, 0);
1171 case GDK_LEAVE_NOTIFY:
1172 switch (ev->crossing.detail) {
1173 case GDK_NOTIFY_UNKNOWN:
1174 case GDK_NOTIFY_INFERIOR:
1175 case GDK_NOTIFY_ANCESTOR:
1177 case GDK_NOTIFY_VIRTUAL:
1178 case GDK_NOTIFY_NONLINEAR:
1179 case GDK_NOTIFY_NONLINEAR_VIRTUAL:
1180 /* leaving window, so reset focus, thus ending any and
1181 all text entry operations.
1183 reset_focus (&contents());
1196 Editor::lock_timeout_callback ()
1198 struct timeval now, delta;
1200 gettimeofday (&now, 0);
1202 timersub (&now, &last_event_time, &delta);
1204 if (delta.tv_sec > (time_t) UIConfiguration::instance().get_lock_gui_after_seconds()) {
1206 /* don't call again. Returning false will effectively
1207 disconnect us from the timer callback.
1209 unlock() will call start_lock_event_timing() to get things
1219 Editor::map_position_change (framepos_t frame)
1221 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1223 if (_session == 0) {
1227 if (_follow_playhead) {
1228 center_screen (frame);
1231 playhead_cursor->set_position (frame);
1235 Editor::center_screen (framepos_t frame)
1237 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1239 /* if we're off the page, then scroll.
1242 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1243 center_screen_internal (frame, page);
1248 Editor::center_screen_internal (framepos_t frame, float page)
1253 frame -= (framepos_t) page;
1258 reset_x_origin (frame);
1263 Editor::update_title ()
1265 ENSURE_GUI_THREAD (*this, &Editor::update_title);
1267 if (!own_window()) {
1272 bool dirty = _session->dirty();
1274 string session_name;
1276 if (_session->snap_name() != _session->name()) {
1277 session_name = _session->snap_name();
1279 session_name = _session->name();
1283 session_name = "*" + session_name;
1286 WindowTitle title(session_name);
1287 title += S_("Window|Editor");
1288 title += Glib::get_application_name();
1289 own_window()->set_title (title.get_string());
1291 /* ::session_going_away() will have taken care of it */
1296 Editor::set_session (Session *t)
1298 SessionHandlePtr::set_session (t);
1304 _playlist_selector->set_session (_session);
1305 nudge_clock->set_session (_session);
1306 _summary->set_session (_session);
1307 _group_tabs->set_session (_session);
1308 _route_groups->set_session (_session);
1309 _regions->set_session (_session);
1310 _snapshots->set_session (_session);
1311 _routes->set_session (_session);
1312 _locations->set_session (_session);
1314 if (rhythm_ferret) {
1315 rhythm_ferret->set_session (_session);
1318 if (analysis_window) {
1319 analysis_window->set_session (_session);
1323 sfbrowser->set_session (_session);
1326 compute_fixed_ruler_scale ();
1328 /* Make sure we have auto loop and auto punch ranges */
1330 Location* loc = _session->locations()->auto_loop_location();
1332 loc->set_name (_("Loop"));
1335 loc = _session->locations()->auto_punch_location();
1338 loc->set_name (_("Punch"));
1341 refresh_location_display ();
1343 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1344 the selected Marker; this needs the LocationMarker list to be available.
1346 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1347 set_state (*node, Stateful::loading_state_version);
1349 /* catch up with the playhead */
1351 _session->request_locate (playhead_cursor->current_frame ());
1352 _pending_initial_locate = true;
1356 /* These signals can all be emitted by a non-GUI thread. Therefore the
1357 handlers for them must not attempt to directly interact with the GUI,
1358 but use PBD::Signal<T>::connect() which accepts an event loop
1359 ("context") where the handler will be asked to run.
1362 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1363 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1364 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1365 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1366 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1367 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1368 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1369 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1370 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1371 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1372 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1373 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1374 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1376 playhead_cursor->show ();
1378 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1379 Config->map_parameters (pc);
1380 _session->config.map_parameters (pc);
1382 restore_ruler_visibility ();
1383 //tempo_map_changed (PropertyChange (0));
1384 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1386 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1387 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1390 super_rapid_screen_update_connection = Timers::super_rapid_connect (
1391 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1394 switch (_snap_type) {
1395 case SnapToRegionStart:
1396 case SnapToRegionEnd:
1397 case SnapToRegionSync:
1398 case SnapToRegionBoundary:
1399 build_region_boundary_cache ();
1406 /* register for undo history */
1407 _session->register_with_memento_command_factory(id(), this);
1408 _session->register_with_memento_command_factory(_selection_memento->id(), _selection_memento);
1410 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1412 LuaInstance::instance()->set_session(_session);
1414 start_updating_meters ();
1418 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1420 if (a->get_name() == "RegionMenu") {
1421 /* When the main menu's region menu is opened, we setup the actions so that they look right
1422 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1423 so we resensitize all region actions when the entered regionview or the region selection
1424 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1425 happens after the region context menu is opened. So we set a flag here, too.
1429 sensitize_the_right_region_actions ();
1430 _last_region_menu_was_main = true;
1435 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1437 using namespace Menu_Helpers;
1439 void (Editor::*emf)(FadeShape);
1440 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1443 images = &_xfade_in_images;
1444 emf = &Editor::set_fade_in_shape;
1446 images = &_xfade_out_images;
1447 emf = &Editor::set_fade_out_shape;
1452 _("Linear (for highly correlated material)"),
1453 *(*images)[FadeLinear],
1454 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1458 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1462 _("Constant power"),
1463 *(*images)[FadeConstantPower],
1464 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1467 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1472 *(*images)[FadeSymmetric],
1473 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1477 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1482 *(*images)[FadeSlow],
1483 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1486 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1491 *(*images)[FadeFast],
1492 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1495 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1498 /** Pop up a context menu for when the user clicks on a start crossfade */
1500 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1502 using namespace Menu_Helpers;
1503 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1508 MenuList& items (xfade_in_context_menu.items());
1511 if (arv->audio_region()->fade_in_active()) {
1512 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1514 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1517 items.push_back (SeparatorElem());
1518 fill_xfade_menu (items, true);
1520 xfade_in_context_menu.popup (button, time);
1523 /** Pop up a context menu for when the user clicks on an end crossfade */
1525 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1527 using namespace Menu_Helpers;
1528 AudioRegionView* arv = dynamic_cast<AudioRegionView*> ((RegionView*)item->get_data ("regionview"));
1533 MenuList& items (xfade_out_context_menu.items());
1536 if (arv->audio_region()->fade_out_active()) {
1537 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1539 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1542 items.push_back (SeparatorElem());
1543 fill_xfade_menu (items, false);
1545 xfade_out_context_menu.popup (button, time);
1549 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1551 using namespace Menu_Helpers;
1552 Menu* (Editor::*build_menu_function)();
1555 switch (item_type) {
1557 case RegionViewName:
1558 case RegionViewNameHighlight:
1559 case LeftFrameHandle:
1560 case RightFrameHandle:
1561 if (with_selection) {
1562 build_menu_function = &Editor::build_track_selection_context_menu;
1564 build_menu_function = &Editor::build_track_region_context_menu;
1569 if (with_selection) {
1570 build_menu_function = &Editor::build_track_selection_context_menu;
1572 build_menu_function = &Editor::build_track_context_menu;
1577 if (clicked_routeview->track()) {
1578 build_menu_function = &Editor::build_track_context_menu;
1580 build_menu_function = &Editor::build_track_bus_context_menu;
1585 /* probably shouldn't happen but if it does, we don't care */
1589 menu = (this->*build_menu_function)();
1590 menu->set_name ("ArdourContextMenu");
1592 /* now handle specific situations */
1594 switch (item_type) {
1596 case RegionViewName:
1597 case RegionViewNameHighlight:
1598 case LeftFrameHandle:
1599 case RightFrameHandle:
1600 if (!with_selection) {
1601 if (region_edit_menu_split_item) {
1602 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1603 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1605 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1608 if (region_edit_menu_split_multichannel_item) {
1609 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1610 region_edit_menu_split_multichannel_item->set_sensitive (true);
1612 region_edit_menu_split_multichannel_item->set_sensitive (false);
1625 /* probably shouldn't happen but if it does, we don't care */
1629 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1631 /* Bounce to disk */
1633 using namespace Menu_Helpers;
1634 MenuList& edit_items = menu->items();
1636 edit_items.push_back (SeparatorElem());
1638 switch (clicked_routeview->audio_track()->freeze_state()) {
1639 case AudioTrack::NoFreeze:
1640 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1643 case AudioTrack::Frozen:
1644 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1647 case AudioTrack::UnFrozen:
1648 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1654 if (item_type == StreamItem && clicked_routeview) {
1655 clicked_routeview->build_underlay_menu(menu);
1658 /* When the region menu is opened, we setup the actions so that they look right
1661 sensitize_the_right_region_actions ();
1662 _last_region_menu_was_main = false;
1664 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1665 menu->popup (button, time);
1669 Editor::build_track_context_menu ()
1671 using namespace Menu_Helpers;
1673 MenuList& edit_items = track_context_menu.items();
1676 add_dstream_context_items (edit_items);
1677 return &track_context_menu;
1681 Editor::build_track_bus_context_menu ()
1683 using namespace Menu_Helpers;
1685 MenuList& edit_items = track_context_menu.items();
1688 add_bus_context_items (edit_items);
1689 return &track_context_menu;
1693 Editor::build_track_region_context_menu ()
1695 using namespace Menu_Helpers;
1696 MenuList& edit_items = track_region_context_menu.items();
1699 /* we've just cleared the track region context menu, so the menu that these
1700 two items were on will have disappeared; stop them dangling.
1702 region_edit_menu_split_item = 0;
1703 region_edit_menu_split_multichannel_item = 0;
1705 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1708 boost::shared_ptr<Track> tr;
1709 boost::shared_ptr<Playlist> pl;
1711 if ((tr = rtv->track())) {
1712 add_region_context_items (edit_items, tr);
1716 add_dstream_context_items (edit_items);
1718 return &track_region_context_menu;
1722 Editor::loudness_analyze_region_selection ()
1727 Selection& s (PublicEditor::instance ().get_selection ());
1728 RegionSelection ars = s.regions;
1729 ARDOUR::AnalysisGraph ag (_session);
1730 framecnt_t total_work = 0;
1732 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1733 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1737 if (!boost::dynamic_pointer_cast<AudioRegion> (arv->region ())) {
1740 assert (dynamic_cast<RouteTimeAxisView *> (&arv->get_time_axis_view ()));
1741 total_work += arv->region ()->length ();
1744 SimpleProgressDialog spd (_("Region Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1746 ag.set_total_frames (total_work);
1747 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1750 for (RegionSelection::iterator j = ars.begin (); j != ars.end (); ++j) {
1751 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*j);
1755 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (arv->region ());
1759 ag.analyze_region (ar);
1762 if (!ag.canceled ()) {
1763 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1769 Editor::loudness_analyze_range_selection ()
1774 Selection& s (PublicEditor::instance ().get_selection ());
1775 TimeSelection ts = s.time;
1776 ARDOUR::AnalysisGraph ag (_session);
1777 framecnt_t total_work = 0;
1779 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1780 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1784 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1788 for (std::list<AudioRange>::iterator j = ts.begin (); j != ts.end (); ++j) {
1789 total_work += j->length ();
1793 SimpleProgressDialog spd (_("Range Loudness Analysis"), sigc::mem_fun (ag, &AnalysisGraph::cancel));
1795 ag.set_total_frames (total_work);
1796 ag.Progress.connect_same_thread (c, boost::bind (&SimpleProgressDialog::update_progress, &spd, _1, _2));
1799 for (TrackSelection::iterator i = s.tracks.begin (); i != s.tracks.end (); ++i) {
1800 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist> ((*i)->playlist ());
1804 RouteUI *rui = dynamic_cast<RouteUI *> (*i);
1808 ag.analyze_range (rui->route (), pl, ts);
1811 if (!ag.canceled ()) {
1812 ExportReport er (_("Audio Report/Analysis"), ag.results ());
1818 Editor::spectral_analyze_region_selection ()
1820 if (analysis_window == 0) {
1821 analysis_window = new AnalysisWindow();
1824 analysis_window->set_session(_session);
1826 analysis_window->show_all();
1829 analysis_window->set_regionmode();
1830 analysis_window->analyze();
1832 analysis_window->present();
1836 Editor::spectral_analyze_range_selection()
1838 if (analysis_window == 0) {
1839 analysis_window = new AnalysisWindow();
1842 analysis_window->set_session(_session);
1844 analysis_window->show_all();
1847 analysis_window->set_rangemode();
1848 analysis_window->analyze();
1850 analysis_window->present();
1854 Editor::build_track_selection_context_menu ()
1856 using namespace Menu_Helpers;
1857 MenuList& edit_items = track_selection_context_menu.items();
1858 edit_items.clear ();
1860 add_selection_context_items (edit_items);
1861 // edit_items.push_back (SeparatorElem());
1862 // add_dstream_context_items (edit_items);
1864 return &track_selection_context_menu;
1868 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1870 using namespace Menu_Helpers;
1872 /* OK, stick the region submenu at the top of the list, and then add
1876 RegionSelection rs = get_regions_from_selection_and_entered ();
1878 string::size_type pos = 0;
1879 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1881 /* we have to hack up the region name because "_" has a special
1882 meaning for menu titles.
1885 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1886 menu_item_name.replace (pos, 1, "__");
1890 if (_popup_region_menu_item == 0) {
1891 _popup_region_menu_item = new MenuItem (menu_item_name);
1892 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1893 _popup_region_menu_item->show ();
1895 _popup_region_menu_item->set_label (menu_item_name);
1898 /* No latering allowed in later is higher layering model */
1899 RefPtr<Action> act = ActionManager::get_action (X_("EditorMenu"), X_("RegionMenuLayering"));
1900 if (act && Config->get_layer_model() == LaterHigher) {
1901 act->set_sensitive (false);
1903 act->set_sensitive (true);
1906 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, true);
1908 edit_items.push_back (*_popup_region_menu_item);
1909 if (Config->get_layer_model() == Manual && track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1910 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1912 edit_items.push_back (SeparatorElem());
1915 /** Add context menu items relevant to selection ranges.
1916 * @param edit_items List to add the items to.
1919 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1921 using namespace Menu_Helpers;
1923 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1924 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1926 edit_items.push_back (SeparatorElem());
1927 edit_items.push_back (MenuElem (_("Zoom to Range"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Loudness Analysis"), sigc::mem_fun(*this, &Editor::loudness_analyze_range_selection)));
1931 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::spectral_analyze_range_selection)));
1933 edit_items.push_back (SeparatorElem());
1935 edit_items.push_back (
1937 _("Move Range Start to Previous Region Boundary"),
1938 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1942 edit_items.push_back (
1944 _("Move Range Start to Next Region Boundary"),
1945 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1949 edit_items.push_back (
1951 _("Move Range End to Previous Region Boundary"),
1952 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1956 edit_items.push_back (
1958 _("Move Range End to Next Region Boundary"),
1959 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1963 edit_items.push_back (SeparatorElem());
1964 edit_items.push_back (MenuElem (_("Separate"), mem_fun(*this, &Editor::separate_region_from_selection)));
1965 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1967 edit_items.push_back (SeparatorElem());
1968 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1970 edit_items.push_back (SeparatorElem());
1971 edit_items.push_back (MenuElem (_("Set Loop from Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1972 edit_items.push_back (MenuElem (_("Set Punch from Selection"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1973 edit_items.push_back (MenuElem (_("Set Session Start/End from Selection"), sigc::mem_fun(*this, &Editor::set_session_extents_from_selection)));
1975 edit_items.push_back (SeparatorElem());
1976 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1978 edit_items.push_back (SeparatorElem());
1979 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1980 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1984 edit_items.push_back (MenuElem (_("Consolidate Range with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1985 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1986 edit_items.push_back (MenuElem (_("Bounce Range to Region List with Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1987 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1988 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1989 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*(ARDOUR_UI::instance()), &ARDOUR_UI::export_video), true)));
1995 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1997 using namespace Menu_Helpers;
2001 Menu *play_menu = manage (new Menu);
2002 MenuList& play_items = play_menu->items();
2003 play_menu->set_name ("ArdourContextMenu");
2005 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2006 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2007 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
2008 play_items.push_back (SeparatorElem());
2009 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
2011 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2015 Menu *select_menu = manage (new Menu);
2016 MenuList& select_items = select_menu->items();
2017 select_menu->set_name ("ArdourContextMenu");
2019 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2020 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2021 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2022 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2023 select_items.push_back (SeparatorElem());
2024 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
2025 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
2026 select_items.push_back (MenuElem (_("Set Range to Selected Regions"), sigc::mem_fun(*this, &Editor::set_selection_from_region)));
2027 select_items.push_back (SeparatorElem());
2028 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2029 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2030 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2031 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2032 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
2033 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
2034 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
2036 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2040 Menu *cutnpaste_menu = manage (new Menu);
2041 MenuList& cutnpaste_items = cutnpaste_menu->items();
2042 cutnpaste_menu->set_name ("ArdourContextMenu");
2044 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2045 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2046 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2048 cutnpaste_items.push_back (SeparatorElem());
2050 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
2051 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
2053 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
2055 /* Adding new material */
2057 edit_items.push_back (SeparatorElem());
2058 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2059 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2063 Menu *nudge_menu = manage (new Menu());
2064 MenuList& nudge_items = nudge_menu->items();
2065 nudge_menu->set_name ("ArdourContextMenu");
2067 edit_items.push_back (SeparatorElem());
2068 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2069 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2070 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2071 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2073 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2077 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2079 using namespace Menu_Helpers;
2083 Menu *play_menu = manage (new Menu);
2084 MenuList& play_items = play_menu->items();
2085 play_menu->set_name ("ArdourContextMenu");
2087 play_items.push_back (MenuElem (_("Play from Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2088 play_items.push_back (MenuElem (_("Play from Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2089 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2093 Menu *select_menu = manage (new Menu);
2094 MenuList& select_items = select_menu->items();
2095 select_menu->set_name ("ArdourContextMenu");
2097 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2098 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
2099 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2100 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2101 select_items.push_back (SeparatorElem());
2102 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true, true)));
2103 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false, true)));
2104 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2105 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2107 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2111 Menu *cutnpaste_menu = manage (new Menu);
2112 MenuList& cutnpaste_items = cutnpaste_menu->items();
2113 cutnpaste_menu->set_name ("ArdourContextMenu");
2115 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2116 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2117 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2119 Menu *nudge_menu = manage (new Menu());
2120 MenuList& nudge_items = nudge_menu->items();
2121 nudge_menu->set_name ("ArdourContextMenu");
2123 edit_items.push_back (SeparatorElem());
2124 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2125 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2126 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2127 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2129 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2133 Editor::snap_type() const
2139 Editor::snap_mode() const
2145 Editor::set_snap_to (SnapType st)
2147 unsigned int snap_ind = (unsigned int)st;
2149 if (internal_editing()) {
2150 internal_snap_type = st;
2152 pre_internal_snap_type = st;
2157 if (snap_ind > snap_type_strings.size() - 1) {
2159 _snap_type = (SnapType)snap_ind;
2162 string str = snap_type_strings[snap_ind];
2164 if (str != snap_type_selector.get_text()) {
2165 snap_type_selector.set_text (str);
2170 switch (_snap_type) {
2171 case SnapToBeatDiv128:
2172 case SnapToBeatDiv64:
2173 case SnapToBeatDiv32:
2174 case SnapToBeatDiv28:
2175 case SnapToBeatDiv24:
2176 case SnapToBeatDiv20:
2177 case SnapToBeatDiv16:
2178 case SnapToBeatDiv14:
2179 case SnapToBeatDiv12:
2180 case SnapToBeatDiv10:
2181 case SnapToBeatDiv8:
2182 case SnapToBeatDiv7:
2183 case SnapToBeatDiv6:
2184 case SnapToBeatDiv5:
2185 case SnapToBeatDiv4:
2186 case SnapToBeatDiv3:
2187 case SnapToBeatDiv2: {
2188 std::vector<TempoMap::BBTPoint> grid;
2189 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
2190 compute_bbt_ruler_scale (grid, leftmost_frame, leftmost_frame + current_page_samples());
2191 update_tempo_based_rulers (grid);
2195 case SnapToRegionStart:
2196 case SnapToRegionEnd:
2197 case SnapToRegionSync:
2198 case SnapToRegionBoundary:
2199 build_region_boundary_cache ();
2207 redisplay_tempo (false);
2209 SnapChanged (); /* EMIT SIGNAL */
2213 Editor::set_snap_mode (SnapMode mode)
2215 string str = snap_mode_strings[(int)mode];
2217 if (internal_editing()) {
2218 internal_snap_mode = mode;
2220 pre_internal_snap_mode = mode;
2225 if (str != snap_mode_selector.get_text ()) {
2226 snap_mode_selector.set_text (str);
2233 Editor::set_edit_point_preference (EditPoint ep, bool force)
2235 bool changed = (_edit_point != ep);
2238 if (Profile->get_mixbus())
2239 if (ep == EditAtSelectedMarker)
2240 ep = EditAtPlayhead;
2242 string str = edit_point_strings[(int)ep];
2243 if (str != edit_point_selector.get_text ()) {
2244 edit_point_selector.set_text (str);
2247 update_all_enter_cursors();
2249 if (!force && !changed) {
2253 const char* action=NULL;
2255 switch (_edit_point) {
2256 case EditAtPlayhead:
2257 action = "edit-at-playhead";
2259 case EditAtSelectedMarker:
2260 action = "edit-at-marker";
2263 action = "edit-at-mouse";
2267 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2269 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2273 bool in_track_canvas;
2275 if (!mouse_frame (foo, in_track_canvas)) {
2276 in_track_canvas = false;
2279 reset_canvas_action_sensitivity (in_track_canvas);
2285 Editor::set_state (const XMLNode& node, int version)
2287 XMLProperty const * prop;
2289 PBD::Unwinder<bool> nsi (no_save_instant, true);
2291 Tabbable::set_state (node, version);
2293 if (_session && (prop = node.property ("playhead"))) {
2295 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2297 playhead_cursor->set_position (pos);
2299 warning << _("Playhead position stored with a negative value - ignored (use zero instead)") << endmsg;
2300 playhead_cursor->set_position (0);
2303 playhead_cursor->set_position (0);
2306 if ((prop = node.property ("mixer-width"))) {
2307 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2310 if ((prop = node.property ("zoom-focus"))) {
2311 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2314 if ((prop = node.property ("zoom"))) {
2315 /* older versions of ardour used floating point samples_per_pixel */
2316 double f = PBD::atof (prop->value());
2317 reset_zoom (llrintf (f));
2319 reset_zoom (samples_per_pixel);
2322 if ((prop = node.property ("visible-track-count"))) {
2323 set_visible_track_count (PBD::atoi (prop->value()));
2326 if ((prop = node.property ("snap-to"))) {
2327 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2328 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2331 if ((prop = node.property ("snap-mode"))) {
2332 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2333 /* set text of Dropdown. in case _snap_mode == SnapOff (default)
2334 * snap_mode_selection_done() will only mark an already active item as active
2335 * which does not trigger set_text().
2337 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2340 if ((prop = node.property ("internal-snap-to"))) {
2341 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2344 if ((prop = node.property ("internal-snap-mode"))) {
2345 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2348 if ((prop = node.property ("pre-internal-snap-to"))) {
2349 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2352 if ((prop = node.property ("pre-internal-snap-mode"))) {
2353 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2356 if ((prop = node.property ("mouse-mode"))) {
2357 MouseMode m = str2mousemode(prop->value());
2358 set_mouse_mode (m, true);
2360 set_mouse_mode (MouseObject, true);
2363 if ((prop = node.property ("left-frame")) != 0) {
2365 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2369 reset_x_origin (pos);
2373 if ((prop = node.property ("y-origin")) != 0) {
2374 reset_y_origin (atof (prop->value ()));
2377 if ((prop = node.property ("join-object-range"))) {
2378 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2379 bool yn = string_is_affirmative (prop->value());
2381 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2382 tact->set_active (!yn);
2383 tact->set_active (yn);
2385 set_mouse_mode(mouse_mode, true);
2388 if ((prop = node.property ("edit-point"))) {
2389 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2392 if ((prop = node.property ("show-measures"))) {
2393 bool yn = string_is_affirmative (prop->value());
2394 _show_measures = yn;
2397 if ((prop = node.property ("follow-playhead"))) {
2398 bool yn = string_is_affirmative (prop->value());
2399 set_follow_playhead (yn);
2402 if ((prop = node.property ("stationary-playhead"))) {
2403 bool yn = string_is_affirmative (prop->value());
2404 set_stationary_playhead (yn);
2407 if ((prop = node.property ("region-list-sort-type"))) {
2408 RegionListSortType st;
2409 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2412 if ((prop = node.property ("show-editor-mixer"))) {
2414 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2417 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2418 bool yn = string_is_affirmative (prop->value());
2420 /* do it twice to force the change */
2422 tact->set_active (!yn);
2423 tact->set_active (yn);
2426 if ((prop = node.property ("show-editor-list"))) {
2428 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2431 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2432 bool yn = string_is_affirmative (prop->value());
2434 /* do it twice to force the change */
2436 tact->set_active (!yn);
2437 tact->set_active (yn);
2440 if ((prop = node.property (X_("editor-list-page")))) {
2441 _the_notebook.set_current_page (atoi (prop->value ()));
2444 if ((prop = node.property (X_("show-marker-lines")))) {
2445 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2447 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2448 bool yn = string_is_affirmative (prop->value ());
2450 tact->set_active (!yn);
2451 tact->set_active (yn);
2454 XMLNodeList children = node.children ();
2455 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2456 selection->set_state (**i, Stateful::current_state_version);
2457 _regions->set_state (**i);
2460 if ((prop = node.property ("maximised"))) {
2461 bool yn = string_is_affirmative (prop->value());
2462 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2464 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2465 bool fs = tact && tact->get_active();
2467 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2471 if ((prop = node.property ("nudge-clock-value"))) {
2473 sscanf (prop->value().c_str(), "%" PRId64, &f);
2474 nudge_clock->set (f);
2476 nudge_clock->set_mode (AudioClock::Timecode);
2477 nudge_clock->set (_session->frame_rate() * 5, true);
2482 * Not all properties may have been in XML, but
2483 * those that are linked to a private variable may need changing
2488 act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2490 yn = _show_measures;
2491 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2492 /* do it twice to force the change */
2493 tact->set_active (!yn);
2494 tact->set_active (yn);
2497 act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2498 yn = _follow_playhead;
2500 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2501 if (tact->get_active() != yn) {
2502 tact->set_active (yn);
2506 act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2507 yn = _stationary_playhead;
2509 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2510 if (tact->get_active() != yn) {
2511 tact->set_active (yn);
2516 return LuaInstance::instance()->set_state(node);
2520 Editor::get_state ()
2522 XMLNode* node = new XMLNode (X_("Editor"));
2525 id().print (buf, sizeof (buf));
2526 node->add_property ("id", buf);
2528 node->add_child_nocopy (Tabbable::get_state());
2530 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2531 node->add_property("edit-horizontal-pane-pos", string(buf));
2532 node->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2533 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2534 node->add_property("edit-vertical-pane-pos", string(buf));
2536 maybe_add_mixer_strip_width (*node);
2538 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2540 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2541 node->add_property ("zoom", buf);
2542 node->add_property ("snap-to", enum_2_string (_snap_type));
2543 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2544 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2545 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2546 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2547 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2548 node->add_property ("edit-point", enum_2_string (_edit_point));
2549 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2550 node->add_property ("visible-track-count", buf);
2552 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2553 node->add_property ("playhead", buf);
2554 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2555 node->add_property ("left-frame", buf);
2556 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2557 node->add_property ("y-origin", buf);
2559 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2560 node->add_property ("maximised", _maximised ? "yes" : "no");
2561 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2562 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2563 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2564 node->add_property ("mouse-mode", enum2str(mouse_mode));
2565 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2567 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2569 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2570 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2573 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2575 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2576 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2579 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2580 node->add_property (X_("editor-list-page"), buf);
2582 if (button_bindings) {
2583 XMLNode* bb = new XMLNode (X_("Buttons"));
2584 button_bindings->save (*bb);
2585 node->add_child_nocopy (*bb);
2588 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2590 node->add_child_nocopy (selection->get_state ());
2591 node->add_child_nocopy (_regions->get_state ());
2593 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2594 node->add_property ("nudge-clock-value", buf);
2596 node->add_child_nocopy (LuaInstance::instance()->get_action_state());
2597 node->add_child_nocopy (LuaInstance::instance()->get_hook_state());
2602 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2603 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2605 * @return pair: TimeAxisView that y is over, layer index.
2607 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2608 * in stacked or expanded region display mode, otherwise 0.
2610 std::pair<TimeAxisView *, double>
2611 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2613 if (!trackview_relative_offset) {
2614 y -= _trackview_group->canvas_origin().y;
2618 return std::make_pair ( (TimeAxisView *) 0, 0);
2621 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2623 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2630 return std::make_pair ( (TimeAxisView *) 0, 0);
2633 /** Snap a position to the grid, if appropriate, taking into account current
2634 * grid settings and also the state of any snap modifier keys that may be pressed.
2635 * @param start Position to snap.
2636 * @param event Event to get current key modifier information from, or 0.
2639 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, RoundMode direction, bool for_mark)
2641 if (!_session || !event) {
2645 if (ArdourKeyboard::indicates_snap (event->button.state)) {
2646 if (_snap_mode == SnapOff) {
2647 snap_to_internal (start, direction, for_mark);
2650 if (_snap_mode != SnapOff) {
2651 snap_to_internal (start, direction, for_mark);
2652 } else if (ArdourKeyboard::indicates_snap_delta (event->button.state)) {
2653 /* SnapOff, but we pressed the snap_delta modifier */
2654 snap_to_internal (start, direction, for_mark);
2660 Editor::snap_to (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2662 if (!_session || (_snap_mode == SnapOff && !ensure_snap)) {
2666 snap_to_internal (start, direction, for_mark, ensure_snap);
2670 Editor::timecode_snap_to_internal (framepos_t& start, RoundMode direction, bool /*for_mark*/)
2672 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2673 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2675 switch (_snap_type) {
2676 case SnapToTimecodeFrame:
2677 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2678 fmod((double)start, (double)_session->frames_per_timecode_frame()) == 0) {
2679 /* start is already on a whole timecode frame, do nothing */
2680 } else if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2681 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2683 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2687 case SnapToTimecodeSeconds:
2688 if (_session->config.get_timecode_offset_negative()) {
2689 start += _session->config.get_timecode_offset ();
2691 start -= _session->config.get_timecode_offset ();
2693 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2694 (start % one_timecode_second == 0)) {
2695 /* start is already on a whole second, do nothing */
2696 } else if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2697 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2699 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2702 if (_session->config.get_timecode_offset_negative()) {
2703 start -= _session->config.get_timecode_offset ();
2705 start += _session->config.get_timecode_offset ();
2709 case SnapToTimecodeMinutes:
2710 if (_session->config.get_timecode_offset_negative()) {
2711 start += _session->config.get_timecode_offset ();
2713 start -= _session->config.get_timecode_offset ();
2715 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2716 (start % one_timecode_minute == 0)) {
2717 /* start is already on a whole minute, do nothing */
2718 } else if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2719 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2721 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2723 if (_session->config.get_timecode_offset_negative()) {
2724 start -= _session->config.get_timecode_offset ();
2726 start += _session->config.get_timecode_offset ();
2730 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2731 abort(); /*NOTREACHED*/
2736 Editor::snap_to_internal (framepos_t& start, RoundMode direction, bool for_mark, bool ensure_snap)
2738 const framepos_t one_second = _session->frame_rate();
2739 const framepos_t one_minute = _session->frame_rate() * 60;
2740 framepos_t presnap = start;
2744 switch (_snap_type) {
2745 case SnapToTimecodeFrame:
2746 case SnapToTimecodeSeconds:
2747 case SnapToTimecodeMinutes:
2748 return timecode_snap_to_internal (start, direction, for_mark);
2751 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2752 start % (one_second/75) == 0) {
2753 /* start is already on a whole CD frame, do nothing */
2754 } else if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2755 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2757 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2762 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2763 start % one_second == 0) {
2764 /* start is already on a whole second, do nothing */
2765 } else if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2766 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2768 start = (framepos_t) floor ((double) start / one_second) * one_second;
2773 if ((direction == RoundUpMaybe || direction == RoundDownMaybe) &&
2774 start % one_minute == 0) {
2775 /* start is already on a whole minute, do nothing */
2776 } else if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2777 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2779 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2784 start = _session->tempo_map().round_to_bar (start, direction);
2788 start = _session->tempo_map().round_to_beat (start, direction);
2791 case SnapToBeatDiv128:
2792 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2794 case SnapToBeatDiv64:
2795 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2797 case SnapToBeatDiv32:
2798 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2800 case SnapToBeatDiv28:
2801 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2803 case SnapToBeatDiv24:
2804 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2806 case SnapToBeatDiv20:
2807 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2809 case SnapToBeatDiv16:
2810 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2812 case SnapToBeatDiv14:
2813 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2815 case SnapToBeatDiv12:
2816 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2818 case SnapToBeatDiv10:
2819 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2821 case SnapToBeatDiv8:
2822 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2824 case SnapToBeatDiv7:
2825 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2827 case SnapToBeatDiv6:
2828 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2830 case SnapToBeatDiv5:
2831 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2833 case SnapToBeatDiv4:
2834 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2836 case SnapToBeatDiv3:
2837 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2839 case SnapToBeatDiv2:
2840 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2848 _session->locations()->marks_either_side (start, before, after);
2850 if (before == max_framepos && after == max_framepos) {
2851 /* No marks to snap to, so just don't snap */
2853 } else if (before == max_framepos) {
2855 } else if (after == max_framepos) {
2857 } else if (before != max_framepos && after != max_framepos) {
2858 /* have before and after */
2859 if ((start - before) < (after - start)) {
2868 case SnapToRegionStart:
2869 case SnapToRegionEnd:
2870 case SnapToRegionSync:
2871 case SnapToRegionBoundary:
2872 if (!region_boundary_cache.empty()) {
2874 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2875 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2877 if (direction > 0) {
2878 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2880 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2883 if (next != region_boundary_cache.begin ()) {
2888 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2889 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2891 if (start > (p + n) / 2) {
2900 switch (_snap_mode) {
2910 if (presnap > start) {
2911 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2915 } else if (presnap < start) {
2916 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2922 /* handled at entry */
2930 Editor::setup_toolbar ()
2932 HBox* mode_box = manage(new HBox);
2933 mode_box->set_border_width (2);
2934 mode_box->set_spacing(2);
2936 HBox* mouse_mode_box = manage (new HBox);
2937 HBox* mouse_mode_hbox = manage (new HBox);
2938 VBox* mouse_mode_vbox = manage (new VBox);
2939 Alignment* mouse_mode_align = manage (new Alignment);
2941 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_VERTICAL);
2942 mouse_mode_size_group->add_widget (smart_mode_button);
2943 mouse_mode_size_group->add_widget (mouse_move_button);
2944 mouse_mode_size_group->add_widget (mouse_cut_button);
2945 mouse_mode_size_group->add_widget (mouse_select_button);
2946 mouse_mode_size_group->add_widget (mouse_timefx_button);
2947 mouse_mode_size_group->add_widget (mouse_audition_button);
2948 mouse_mode_size_group->add_widget (mouse_draw_button);
2949 mouse_mode_size_group->add_widget (mouse_content_button);
2951 mouse_mode_size_group->add_widget (zoom_in_button);
2952 mouse_mode_size_group->add_widget (zoom_out_button);
2953 mouse_mode_size_group->add_widget (zoom_preset_selector);
2954 mouse_mode_size_group->add_widget (zoom_out_full_button);
2955 mouse_mode_size_group->add_widget (zoom_focus_selector);
2957 mouse_mode_size_group->add_widget (tav_shrink_button);
2958 mouse_mode_size_group->add_widget (tav_expand_button);
2959 mouse_mode_size_group->add_widget (visible_tracks_selector);
2961 mouse_mode_size_group->add_widget (snap_type_selector);
2962 mouse_mode_size_group->add_widget (snap_mode_selector);
2964 mouse_mode_size_group->add_widget (edit_point_selector);
2965 mouse_mode_size_group->add_widget (edit_mode_selector);
2967 mouse_mode_size_group->add_widget (*nudge_clock);
2968 mouse_mode_size_group->add_widget (nudge_forward_button);
2969 mouse_mode_size_group->add_widget (nudge_backward_button);
2971 mouse_mode_hbox->set_spacing (2);
2973 if (!ARDOUR::Profile->get_trx()) {
2974 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2977 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2978 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2980 if (!ARDOUR::Profile->get_mixbus()) {
2981 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2984 if (!ARDOUR::Profile->get_trx()) {
2985 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2986 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2987 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2988 mouse_mode_hbox->pack_start (mouse_content_button, false, false);
2991 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2993 mouse_mode_align->add (*mouse_mode_vbox);
2994 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2996 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2998 edit_mode_selector.set_name ("mouse mode button");
3000 if (!ARDOUR::Profile->get_trx()) {
3001 mode_box->pack_start (edit_mode_selector, false, false);
3004 mode_box->pack_start (*mouse_mode_box, false, false);
3008 _zoom_box.set_spacing (2);
3009 _zoom_box.set_border_width (2);
3013 zoom_preset_selector.set_name ("zoom button");
3014 zoom_preset_selector.set_image(::get_icon ("time_exp"));
3015 zoom_preset_selector.set_size_request (42, -1);
3017 zoom_in_button.set_name ("zoom button");
3018 zoom_in_button.set_icon (ArdourIcon::ZoomIn);
3019 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
3020 zoom_in_button.set_related_action (act);
3022 zoom_out_button.set_name ("zoom button");
3023 zoom_out_button.set_icon (ArdourIcon::ZoomOut);
3024 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
3025 zoom_out_button.set_related_action (act);
3027 zoom_out_full_button.set_name ("zoom button");
3028 zoom_out_full_button.set_icon (ArdourIcon::ZoomFull);
3029 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
3030 zoom_out_full_button.set_related_action (act);
3032 zoom_focus_selector.set_name ("zoom button");
3034 if (ARDOUR::Profile->get_mixbus()) {
3035 _zoom_box.pack_start (zoom_preset_selector, false, false);
3036 } else if (ARDOUR::Profile->get_trx()) {
3037 mode_box->pack_start (zoom_out_button, false, false);
3038 mode_box->pack_start (zoom_in_button, false, false);
3040 _zoom_box.pack_start (zoom_out_button, false, false);
3041 _zoom_box.pack_start (zoom_in_button, false, false);
3042 _zoom_box.pack_start (zoom_out_full_button, false, false);
3043 _zoom_box.pack_start (zoom_focus_selector, false, false);
3046 /* Track zoom buttons */
3047 visible_tracks_selector.set_name ("zoom button");
3048 if (Profile->get_mixbus()) {
3049 visible_tracks_selector.set_image(::get_icon ("tav_exp"));
3050 visible_tracks_selector.set_size_request (42, -1);
3052 set_size_request_to_display_given_text (visible_tracks_selector, _("All"), 30, 2);
3055 tav_expand_button.set_name ("zoom button");
3056 tav_expand_button.set_icon (ArdourIcon::TimeAxisExpand);
3057 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
3058 tav_expand_button.set_related_action (act);
3060 tav_shrink_button.set_name ("zoom button");
3061 tav_shrink_button.set_icon (ArdourIcon::TimeAxisShrink);
3062 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
3063 tav_shrink_button.set_related_action (act);
3065 if (ARDOUR::Profile->get_mixbus()) {
3066 _zoom_box.pack_start (visible_tracks_selector);
3067 } else if (ARDOUR::Profile->get_trx()) {
3068 _zoom_box.pack_start (tav_shrink_button);
3069 _zoom_box.pack_start (tav_expand_button);
3071 _zoom_box.pack_start (visible_tracks_selector);
3072 _zoom_box.pack_start (tav_shrink_button);
3073 _zoom_box.pack_start (tav_expand_button);
3076 snap_box.set_spacing (2);
3077 snap_box.set_border_width (2);
3079 snap_type_selector.set_name ("mouse mode button");
3081 snap_mode_selector.set_name ("mouse mode button");
3083 edit_point_selector.set_name ("mouse mode button");
3085 snap_box.pack_start (snap_mode_selector, false, false);
3086 snap_box.pack_start (snap_type_selector, false, false);
3087 snap_box.pack_start (edit_point_selector, false, false);
3091 HBox *nudge_box = manage (new HBox);
3092 nudge_box->set_spacing (2);
3093 nudge_box->set_border_width (2);
3095 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3096 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3098 nudge_box->pack_start (nudge_backward_button, false, false);
3099 nudge_box->pack_start (nudge_forward_button, false, false);
3100 nudge_box->pack_start (*nudge_clock, false, false);
3103 /* Pack everything in... */
3105 HBox* hbox = manage (new HBox);
3106 hbox->set_spacing(2);
3108 toolbar_hbox.set_spacing (2);
3109 toolbar_hbox.set_border_width (1);
3111 toolbar_hbox.pack_start (*mode_box, false, false);
3112 if (!ARDOUR::Profile->get_trx()) {
3113 toolbar_hbox.pack_start (_zoom_box, false, false);
3114 toolbar_hbox.pack_start (*hbox, false, false);
3117 if (!ARDOUR::Profile->get_trx()) {
3118 hbox->pack_start (snap_box, false, false);
3119 hbox->pack_start (*nudge_box, false, false);
3124 toolbar_base.set_name ("ToolBarBase");
3125 toolbar_base.add (toolbar_hbox);
3127 _toolbar_viewport.add (toolbar_base);
3128 /* stick to the required height but allow width to vary if there's not enough room */
3129 _toolbar_viewport.set_size_request (1, -1);
3131 toolbar_frame.set_shadow_type (SHADOW_OUT);
3132 toolbar_frame.set_name ("BaseFrame");
3133 toolbar_frame.add (_toolbar_viewport);
3137 Editor::build_edit_point_menu ()
3139 using namespace Menu_Helpers;
3141 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3142 if(!Profile->get_mixbus())
3143 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3144 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3146 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_TRIANGLE_WIDTH, 2);
3150 Editor::build_edit_mode_menu ()
3152 using namespace Menu_Helpers;
3154 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3155 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3156 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3157 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3159 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3163 Editor::build_snap_mode_menu ()
3165 using namespace Menu_Helpers;
3167 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3168 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3169 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3171 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_TRIANGLE_WIDTH, 2);
3175 Editor::build_snap_type_menu ()
3177 using namespace Menu_Helpers;
3179 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3180 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3181 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3182 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3183 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3184 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3185 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3186 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3187 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3188 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3189 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3190 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3191 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3192 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3193 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3194 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3195 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3196 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3197 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3198 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3199 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3200 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3201 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3202 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3203 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3204 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3205 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3206 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3207 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3208 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3210 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_TRIANGLE_WIDTH, 2);
3215 Editor::setup_tooltips ()
3217 set_tooltip (smart_mode_button, _("Smart Mode (add range functions to Grab Mode)"));
3218 set_tooltip (mouse_move_button, _("Grab Mode (select/move objects)"));
3219 set_tooltip (mouse_cut_button, _("Cut Mode (split regions)"));
3220 set_tooltip (mouse_select_button, _("Range Mode (select time ranges)"));
3221 set_tooltip (mouse_draw_button, _("Draw Mode (draw and edit gain/notes/automation)"));
3222 set_tooltip (mouse_timefx_button, _("Stretch Mode (time-stretch audio and midi regions, preserving pitch)"));
3223 set_tooltip (mouse_audition_button, _("Audition Mode (listen to regions)"));
3224 set_tooltip (mouse_content_button, _("Internal Edit Mode (edit notes and automation points)"));
3225 set_tooltip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3226 set_tooltip (nudge_forward_button, _("Nudge Region/Selection Later"));
3227 set_tooltip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3228 set_tooltip (zoom_in_button, _("Zoom In"));
3229 set_tooltip (zoom_out_button, _("Zoom Out"));
3230 set_tooltip (zoom_preset_selector, _("Zoom to Time Scale"));
3231 set_tooltip (zoom_out_full_button, _("Zoom to Session"));
3232 set_tooltip (zoom_focus_selector, _("Zoom Focus"));
3233 set_tooltip (tav_expand_button, _("Expand Tracks"));
3234 set_tooltip (tav_shrink_button, _("Shrink Tracks"));
3235 set_tooltip (visible_tracks_selector, _("Number of visible tracks"));
3236 set_tooltip (snap_type_selector, _("Snap/Grid Units"));
3237 set_tooltip (snap_mode_selector, _("Snap/Grid Mode"));
3238 set_tooltip (edit_point_selector, _("Edit Point"));
3239 set_tooltip (edit_mode_selector, _("Edit Mode"));
3240 set_tooltip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3244 Editor::convert_drop_to_paths (
3245 vector<string>& paths,
3246 const RefPtr<Gdk::DragContext>& /*context*/,
3249 const SelectionData& data,
3253 if (_session == 0) {
3257 vector<string> uris = data.get_uris();
3261 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3262 are actually URI lists. So do it by hand.
3265 if (data.get_target() != "text/plain") {
3269 /* Parse the "uri-list" format that Nautilus provides,
3270 where each pathname is delimited by \r\n.
3272 THERE MAY BE NO NULL TERMINATING CHAR!!!
3275 string txt = data.get_text();
3279 p = (char *) malloc (txt.length() + 1);
3280 txt.copy (p, txt.length(), 0);
3281 p[txt.length()] = '\0';
3287 while (g_ascii_isspace (*p))
3291 while (*q && (*q != '\n') && (*q != '\r')) {
3298 while (q > p && g_ascii_isspace (*q))
3303 uris.push_back (string (p, q - p + 1));
3307 p = strchr (p, '\n');
3319 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3320 if ((*i).substr (0,7) == "file://") {
3321 paths.push_back (Glib::filename_from_uri (*i));
3329 Editor::new_tempo_section ()
3334 Editor::map_transport_state ()
3336 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3338 if (_session && _session->transport_stopped()) {
3339 have_pending_keyboard_selection = false;
3342 update_loop_range_view ();
3348 Editor::begin_selection_op_history ()
3350 selection_op_cmd_depth = 0;
3351 selection_op_history_it = 0;
3353 while(!selection_op_history.empty()) {
3354 delete selection_op_history.front();
3355 selection_op_history.pop_front();
3358 selection_undo_action->set_sensitive (false);
3359 selection_redo_action->set_sensitive (false);
3360 selection_op_history.push_front (&_selection_memento->get_state ());
3364 Editor::begin_reversible_selection_op (string name)
3367 //cerr << name << endl;
3368 /* begin/commit pairs can be nested */
3369 selection_op_cmd_depth++;
3374 Editor::commit_reversible_selection_op ()
3377 if (selection_op_cmd_depth == 1) {
3379 if (selection_op_history_it > 0 && selection_op_history_it < selection_op_history.size()) {
3381 The user has undone some selection ops and then made a new one,
3382 making anything earlier in the list invalid.
3385 list<XMLNode *>::iterator it = selection_op_history.begin();
3386 list<XMLNode *>::iterator e_it = it;
3387 advance (e_it, selection_op_history_it);
3389 for ( ; it != e_it; ++it) {
3392 selection_op_history.erase (selection_op_history.begin(), e_it);
3395 selection_op_history.push_front (&_selection_memento->get_state ());
3396 selection_op_history_it = 0;
3398 selection_undo_action->set_sensitive (true);
3399 selection_redo_action->set_sensitive (false);
3402 if (selection_op_cmd_depth > 0) {
3403 selection_op_cmd_depth--;
3409 Editor::undo_selection_op ()
3412 selection_op_history_it++;
3414 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3415 if (n == selection_op_history_it) {
3416 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3417 selection_redo_action->set_sensitive (true);
3421 /* is there an earlier entry? */
3422 if ((selection_op_history_it + 1) >= selection_op_history.size()) {
3423 selection_undo_action->set_sensitive (false);
3429 Editor::redo_selection_op ()
3432 if (selection_op_history_it > 0) {
3433 selection_op_history_it--;
3436 for (std::list<XMLNode *>::iterator i = selection_op_history.begin(); i != selection_op_history.end(); ++i) {
3437 if (n == selection_op_history_it) {
3438 _selection_memento->set_state (*(*i), Stateful::current_state_version);
3439 selection_undo_action->set_sensitive (true);
3444 if (selection_op_history_it == 0) {
3445 selection_redo_action->set_sensitive (false);
3451 Editor::begin_reversible_command (string name)
3454 before.push_back (&_selection_memento->get_state ());
3455 _session->begin_reversible_command (name);
3460 Editor::begin_reversible_command (GQuark q)
3463 before.push_back (&_selection_memento->get_state ());
3464 _session->begin_reversible_command (q);
3469 Editor::abort_reversible_command ()
3472 while(!before.empty()) {
3473 delete before.front();
3476 _session->abort_reversible_command ();
3481 Editor::commit_reversible_command ()
3484 if (before.size() == 1) {
3485 _session->add_command (new MementoCommand<SelectionMemento>(*(_selection_memento), before.front(), &_selection_memento->get_state ()));
3486 redo_action->set_sensitive(false);
3487 undo_action->set_sensitive(true);
3488 begin_selection_op_history ();
3491 if (before.empty()) {
3492 cerr << "Please call begin_reversible_command() before commit_reversible_command()." << endl;
3497 _session->commit_reversible_command ();
3502 Editor::history_changed ()
3506 if (undo_action && _session) {
3507 if (_session->undo_depth() == 0) {
3508 label = S_("Command|Undo");
3510 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3512 undo_action->property_label() = label;
3515 if (redo_action && _session) {
3516 if (_session->redo_depth() == 0) {
3518 redo_action->set_sensitive (false);
3520 label = string_compose(_("Redo (%1)"), _session->next_redo());
3521 redo_action->set_sensitive (true);
3523 redo_action->property_label() = label;
3528 Editor::duplicate_range (bool with_dialog)
3532 RegionSelection rs = get_regions_from_selection_and_entered ();
3534 if ( selection->time.length() == 0 && rs.empty()) {
3540 ArdourDialog win (_("Duplicate"));
3541 Label label (_("Number of duplications:"));
3542 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3543 SpinButton spinner (adjustment, 0.0, 1);
3546 win.get_vbox()->set_spacing (12);
3547 win.get_vbox()->pack_start (hbox);
3548 hbox.set_border_width (6);
3549 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3551 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3552 place, visually. so do this by hand.
3555 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3556 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3557 spinner.grab_focus();
3563 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3564 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3565 win.set_default_response (RESPONSE_ACCEPT);
3567 spinner.grab_focus ();
3569 switch (win.run ()) {
3570 case RESPONSE_ACCEPT:
3576 times = adjustment.get_value();
3579 if ((current_mouse_mode() == Editing::MouseRange)) {
3580 if (selection->time.length()) {
3581 duplicate_selection (times);
3583 } else if (get_smart_mode()) {
3584 if (selection->time.length()) {
3585 duplicate_selection (times);
3587 duplicate_some_regions (rs, times);
3589 duplicate_some_regions (rs, times);
3594 Editor::set_edit_mode (EditMode m)
3596 Config->set_edit_mode (m);
3600 Editor::cycle_edit_mode ()
3602 switch (Config->get_edit_mode()) {
3604 Config->set_edit_mode (Ripple);
3608 Config->set_edit_mode (Lock);
3611 Config->set_edit_mode (Slide);
3617 Editor::edit_mode_selection_done ( EditMode m )
3619 Config->set_edit_mode ( m );
3623 Editor::snap_type_selection_done (SnapType snaptype)
3625 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3627 ract->set_active ();
3632 Editor::snap_mode_selection_done (SnapMode mode)
3634 RefPtr<RadioAction> ract = snap_mode_action (mode);
3637 ract->set_active (true);
3642 Editor::cycle_edit_point (bool with_marker)
3644 if(Profile->get_mixbus())
3645 with_marker = false;
3647 switch (_edit_point) {
3649 set_edit_point_preference (EditAtPlayhead);
3651 case EditAtPlayhead:
3653 set_edit_point_preference (EditAtSelectedMarker);
3655 set_edit_point_preference (EditAtMouse);
3658 case EditAtSelectedMarker:
3659 set_edit_point_preference (EditAtMouse);
3665 Editor::edit_point_selection_done (EditPoint ep)
3667 set_edit_point_preference ( ep );
3671 Editor::build_zoom_focus_menu ()
3673 using namespace Menu_Helpers;
3675 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3676 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3677 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3678 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3679 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3680 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3682 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_TRIANGLE_WIDTH, 2);
3686 Editor::zoom_focus_selection_done ( ZoomFocus f )
3688 RefPtr<RadioAction> ract = zoom_focus_action (f);
3690 ract->set_active ();
3695 Editor::build_track_count_menu ()
3697 using namespace Menu_Helpers;
3699 if (!Profile->get_mixbus()) {
3700 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3701 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3702 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3703 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3704 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3705 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3706 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3707 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3708 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3709 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3710 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3711 visible_tracks_selector.AddMenuElem (MenuElem (_("Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3712 visible_tracks_selector.AddMenuElem (MenuElem (_("All"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3714 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 1 track"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3715 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 2 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3716 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 4 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3717 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 8 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3718 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 16 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3719 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 24 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3720 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 32 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3721 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit 48 tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 48)));
3722 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit All tracks"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3723 visible_tracks_selector.AddMenuElem (MenuElem (_("Fit Selection"), sigc::mem_fun(*this, &Editor::fit_selection)));
3725 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10)));
3726 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 100 ms"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 100)));
3727 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 1 * 1000)));
3728 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 sec"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 1000)));
3729 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 1000)));
3730 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 10 min"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 10 * 60 * 1000)));
3731 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 1 hour"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 60 * 60 * 1000)));
3732 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 8 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 8 * 60 * 60 * 1000)));
3733 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to 24 hours"), sigc::bind (sigc::mem_fun(*this, &Editor::set_zoom_preset), 24 * 60 * 60 * 1000)));
3734 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Session"), sigc::mem_fun(*this, &Editor::temporal_zoom_session)));
3735 zoom_preset_selector.AddMenuElem (MenuElem (_("Zoom to Range/Region Selection"), sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_selection), false)));
3740 Editor::set_zoom_preset (int64_t ms)
3743 temporal_zoom_session();
3747 ARDOUR::framecnt_t const sample_rate = ARDOUR::AudioEngine::instance()->sample_rate();
3748 temporal_zoom( (sample_rate * ms / 1000) / _visible_canvas_width );
3752 Editor::set_visible_track_count (int32_t n)
3754 _visible_track_count = n;
3756 /* if the canvas hasn't really been allocated any size yet, just
3757 record the desired number of visible tracks and return. when canvas
3758 allocation happens, we will get called again and then we can do the
3762 if (_visible_canvas_height <= 1) {
3768 DisplaySuspender ds;
3770 if (_visible_track_count > 0) {
3771 h = trackviews_height() / _visible_track_count;
3772 std::ostringstream s;
3773 s << _visible_track_count;
3775 } else if (_visible_track_count == 0) {
3777 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3778 if ((*i)->marked_for_display()) {
3782 h = trackviews_height() / n;
3785 /* negative value means that the visible track count has
3786 been overridden by explicit track height changes.
3788 visible_tracks_selector.set_text (X_("*"));
3792 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3793 (*i)->set_height (h, TimeAxisView::HeightPerLane);
3796 if (str != visible_tracks_selector.get_text()) {
3797 visible_tracks_selector.set_text (str);
3802 Editor::override_visible_track_count ()
3804 _visible_track_count = -1;
3805 visible_tracks_selector.set_text ( _("*") );
3809 Editor::edit_controls_button_release (GdkEventButton* ev)
3811 if (Keyboard::is_context_menu_event (ev)) {
3812 ARDOUR_UI::instance()->add_route ();
3813 } else if (ev->button == 1) {
3814 selection->clear_tracks ();
3821 Editor::mouse_select_button_release (GdkEventButton* ev)
3823 /* this handles just right-clicks */
3825 if (ev->button != 3) {
3833 Editor::set_zoom_focus (ZoomFocus f)
3835 string str = zoom_focus_strings[(int)f];
3837 if (str != zoom_focus_selector.get_text()) {
3838 zoom_focus_selector.set_text (str);
3841 if (zoom_focus != f) {
3848 Editor::cycle_zoom_focus ()
3850 switch (zoom_focus) {
3852 set_zoom_focus (ZoomFocusRight);
3854 case ZoomFocusRight:
3855 set_zoom_focus (ZoomFocusCenter);
3857 case ZoomFocusCenter:
3858 set_zoom_focus (ZoomFocusPlayhead);
3860 case ZoomFocusPlayhead:
3861 set_zoom_focus (ZoomFocusMouse);
3863 case ZoomFocusMouse:
3864 set_zoom_focus (ZoomFocusEdit);
3867 set_zoom_focus (ZoomFocusLeft);
3873 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3875 /* recover or initialize pane positions. do this here rather than earlier because
3876 we don't want the positions to change the child allocations, which they seem to do.
3880 XMLProperty const * prop;
3882 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3891 XMLNode* geometry = find_named_node (*node, "geometry");
3893 if (which == static_cast<Paned*> (&edit_pane)) {
3895 if (done & Horizontal) {
3899 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3900 _notebook_shrunk = string_is_affirmative (prop->value ());
3903 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3904 /* initial allocation is 90% to canvas, 10% to notebook */
3905 pos = (int) floor (alloc.get_width() * 0.90f);
3906 snprintf (buf, sizeof(buf), "%d", pos);
3908 pos = atoi (prop->value());
3911 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3912 edit_pane.set_position (pos);
3915 done = (Pane) (done | Horizontal);
3917 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3919 if (done & Vertical) {
3923 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3924 /* initial allocation is 90% to canvas, 10% to summary */
3925 pos = (int) floor (alloc.get_height() * 0.90f);
3926 snprintf (buf, sizeof(buf), "%d", pos);
3929 pos = atoi (prop->value());
3932 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3933 editor_summary_pane.set_position (pos);
3936 done = (Pane) (done | Vertical);
3941 Editor::set_show_measures (bool yn)
3943 if (_show_measures != yn) {
3946 if ((_show_measures = yn) == true) {
3948 tempo_lines->show();
3951 std::vector<TempoMap::BBTPoint> grid;
3952 compute_current_bbt_points (grid, leftmost_frame, leftmost_frame + current_page_samples());
3953 draw_measures (grid);
3961 Editor::toggle_follow_playhead ()
3963 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3965 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3966 set_follow_playhead (tact->get_active());
3970 /** @param yn true to follow playhead, otherwise false.
3971 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3974 Editor::set_follow_playhead (bool yn, bool catch_up)
3976 if (_follow_playhead != yn) {
3977 if ((_follow_playhead = yn) == true && catch_up) {
3979 reset_x_origin_to_follow_playhead ();
3986 Editor::toggle_stationary_playhead ()
3988 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3990 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3991 set_stationary_playhead (tact->get_active());
3996 Editor::set_stationary_playhead (bool yn)
3998 if (_stationary_playhead != yn) {
3999 if ((_stationary_playhead = yn) == true) {
4001 // FIXME need a 3.0 equivalent of this 2.X call
4002 // update_current_screen ();
4009 Editor::playlist_selector () const
4011 return *_playlist_selector;
4015 Editor::get_paste_offset (framepos_t pos, unsigned paste_count, framecnt_t duration)
4017 if (paste_count == 0) {
4018 /* don't bother calculating an offset that will be zero anyway */
4022 /* calculate basic unsnapped multi-paste offset */
4023 framecnt_t offset = paste_count * duration;
4025 /* snap offset so pos + offset is aligned to the grid */
4026 framepos_t offset_pos = pos + offset;
4027 snap_to(offset_pos, RoundUpMaybe);
4028 offset = offset_pos - pos;
4034 Editor::get_grid_beat_divisions(framepos_t position)
4036 switch (_snap_type) {
4037 case SnapToBeatDiv128: return 128;
4038 case SnapToBeatDiv64: return 64;
4039 case SnapToBeatDiv32: return 32;
4040 case SnapToBeatDiv28: return 28;
4041 case SnapToBeatDiv24: return 24;
4042 case SnapToBeatDiv20: return 20;
4043 case SnapToBeatDiv16: return 16;
4044 case SnapToBeatDiv14: return 14;
4045 case SnapToBeatDiv12: return 12;
4046 case SnapToBeatDiv10: return 10;
4047 case SnapToBeatDiv8: return 8;
4048 case SnapToBeatDiv7: return 7;
4049 case SnapToBeatDiv6: return 6;
4050 case SnapToBeatDiv5: return 5;
4051 case SnapToBeatDiv4: return 4;
4052 case SnapToBeatDiv3: return 3;
4053 case SnapToBeatDiv2: return 2;
4060 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
4064 const unsigned divisions = get_grid_beat_divisions(position);
4066 return Evoral::Beats(1.0 / (double)get_grid_beat_divisions(position));
4069 switch (_snap_type) {
4071 return Evoral::Beats(1.0);
4074 return Evoral::Beats(_session->tempo_map().meter_at (position).divisions_per_bar());
4082 return Evoral::Beats();
4086 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
4090 ret = nudge_clock->current_duration (pos);
4091 next = ret + 1; /* XXXX fix me */
4097 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
4099 ArdourDialog dialog (_("Playlist Deletion"));
4100 Label label (string_compose (_("Playlist %1 is currently unused.\n"
4101 "If it is kept, its audio files will not be cleaned.\n"
4102 "If it is deleted, audio files used by it alone will be cleaned."),
4105 dialog.set_position (WIN_POS_CENTER);
4106 dialog.get_vbox()->pack_start (label);
4110 dialog.add_button (_("Delete All Unused"), RESPONSE_YES); // needs clarification. this and all remaining ones
4111 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
4112 Button* keep = dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
4113 dialog.add_button (_("Keep Remaining"), RESPONSE_NO); // ditto
4114 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
4116 // by default gtk uses the left most button
4117 keep->grab_focus ();
4119 switch (dialog.run ()) {
4121 /* keep this and all remaining ones */
4126 /* delete this and all others */
4130 case RESPONSE_ACCEPT:
4131 /* delete the playlist */
4135 case RESPONSE_REJECT:
4136 /* keep the playlist */
4148 Editor::audio_region_selection_covers (framepos_t where)
4150 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
4151 if ((*a)->region()->covers (where)) {
4160 Editor::prepare_for_cleanup ()
4162 cut_buffer->clear_regions ();
4163 cut_buffer->clear_playlists ();
4165 selection->clear_regions ();
4166 selection->clear_playlists ();
4168 _regions->suspend_redisplay ();
4172 Editor::finish_cleanup ()
4174 _regions->resume_redisplay ();
4178 Editor::transport_loop_location()
4181 return _session->locations()->auto_loop_location();
4188 Editor::transport_punch_location()
4191 return _session->locations()->auto_punch_location();
4198 Editor::control_layout_scroll (GdkEventScroll* ev)
4200 /* Just forward to the normal canvas scroll method. The coordinate
4201 systems are different but since the canvas is always larger than the
4202 track headers, and aligned with the trackview area, this will work.
4204 In the not too distant future this layout is going away anyway and
4205 headers will be on the canvas.
4207 return canvas_scroll_event (ev, false);
4211 Editor::session_state_saved (string)
4214 _snapshots->redisplay ();
4218 Editor::maximise_editing_space ()
4224 Gtk::Window* toplevel = current_toplevel();
4227 toplevel->fullscreen ();
4233 Editor::restore_editing_space ()
4239 Gtk::Window* toplevel = current_toplevel();
4242 toplevel->unfullscreen();
4248 * Make new playlists for a given track and also any others that belong
4249 * to the same active route group with the `select' property.
4254 Editor::new_playlists (TimeAxisView* v)
4256 begin_reversible_command (_("new playlists"));
4257 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4258 _session->playlists->get (playlists);
4259 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4260 commit_reversible_command ();
4264 * Use a copy of the current playlist for a given track and also any others that belong
4265 * to the same active route group with the `select' property.
4270 Editor::copy_playlists (TimeAxisView* v)
4272 begin_reversible_command (_("copy playlists"));
4273 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4274 _session->playlists->get (playlists);
4275 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4276 commit_reversible_command ();
4279 /** Clear the current playlist for a given track and also any others that belong
4280 * to the same active route group with the `select' property.
4285 Editor::clear_playlists (TimeAxisView* v)
4287 begin_reversible_command (_("clear playlists"));
4288 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4289 _session->playlists->get (playlists);
4290 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4291 commit_reversible_command ();
4295 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4297 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4301 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4303 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4307 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4309 atv.clear_playlist ();
4313 Editor::get_y_origin () const
4315 return vertical_adjustment.get_value ();
4318 /** Queue up a change to the viewport x origin.
4319 * @param frame New x origin.
4322 Editor::reset_x_origin (framepos_t frame)
4324 pending_visual_change.add (VisualChange::TimeOrigin);
4325 pending_visual_change.time_origin = frame;
4326 ensure_visual_change_idle_handler ();
4330 Editor::reset_y_origin (double y)
4332 pending_visual_change.add (VisualChange::YOrigin);
4333 pending_visual_change.y_origin = y;
4334 ensure_visual_change_idle_handler ();
4338 Editor::reset_zoom (framecnt_t spp)
4340 if (spp == samples_per_pixel) {
4344 pending_visual_change.add (VisualChange::ZoomLevel);
4345 pending_visual_change.samples_per_pixel = spp;
4346 ensure_visual_change_idle_handler ();
4350 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4352 reset_x_origin (frame);
4355 if (!no_save_visual) {
4356 undo_visual_stack.push_back (current_visual_state(false));
4360 Editor::VisualState::VisualState (bool with_tracks)
4361 : gui_state (with_tracks ? new GUIObjectState : 0)
4365 Editor::VisualState::~VisualState ()
4370 Editor::VisualState*
4371 Editor::current_visual_state (bool with_tracks)
4373 VisualState* vs = new VisualState (with_tracks);
4374 vs->y_position = vertical_adjustment.get_value();
4375 vs->samples_per_pixel = samples_per_pixel;
4376 vs->leftmost_frame = leftmost_frame;
4377 vs->zoom_focus = zoom_focus;
4380 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4387 Editor::undo_visual_state ()
4389 if (undo_visual_stack.empty()) {
4393 VisualState* vs = undo_visual_stack.back();
4394 undo_visual_stack.pop_back();
4397 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4400 use_visual_state (*vs);
4405 Editor::redo_visual_state ()
4407 if (redo_visual_stack.empty()) {
4411 VisualState* vs = redo_visual_stack.back();
4412 redo_visual_stack.pop_back();
4414 // can 'vs' really be 0? Is there a place that puts NULL pointers onto the stack?
4415 // why do we check here?
4416 undo_visual_stack.push_back (current_visual_state (vs ? (vs->gui_state != 0) : false));
4419 use_visual_state (*vs);
4424 Editor::swap_visual_state ()
4426 if (undo_visual_stack.empty()) {
4427 redo_visual_state ();
4429 undo_visual_state ();
4434 Editor::use_visual_state (VisualState& vs)
4436 PBD::Unwinder<bool> nsv (no_save_visual, true);
4437 DisplaySuspender ds;
4439 vertical_adjustment.set_value (vs.y_position);
4441 set_zoom_focus (vs.zoom_focus);
4442 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4445 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4447 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4448 (*i)->clear_property_cache();
4449 (*i)->reset_visual_state ();
4453 _routes->update_visibility ();
4456 /** This is the core function that controls the zoom level of the canvas. It is called
4457 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4458 * @param spp new number of samples per pixel
4461 Editor::set_samples_per_pixel (framecnt_t spp)
4467 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4468 const framecnt_t lots_of_pixels = 4000;
4470 /* if the zoom level is greater than what you'd get trying to display 3
4471 * days of audio on a really big screen, then it's too big.
4474 if (spp * lots_of_pixels > three_days) {
4478 samples_per_pixel = spp;
4481 tempo_lines->tempo_map_changed();
4484 bool const showing_time_selection = selection->time.length() > 0;
4486 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4487 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4488 (*i)->reshow_selection (selection->time);
4492 ZoomChanged (); /* EMIT_SIGNAL */
4494 ArdourCanvas::GtkCanvasViewport* c;
4496 c = get_track_canvas();
4498 c->canvas()->zoomed ();
4501 if (playhead_cursor) {
4502 playhead_cursor->set_position (playhead_cursor->current_frame ());
4505 refresh_location_display();
4506 _summary->set_overlays_dirty ();
4508 update_marker_labels ();
4514 Editor::queue_visual_videotimeline_update ()
4517 * pending_visual_change.add (VisualChange::VideoTimeline);
4518 * or maybe even more specific: which videotimeline-image
4519 * currently it calls update_video_timeline() to update
4520 * _all outdated_ images on the video-timeline.
4521 * see 'exposeimg()' in video_image_frame.cc
4523 ensure_visual_change_idle_handler ();
4527 Editor::ensure_visual_change_idle_handler ()
4529 if (pending_visual_change.idle_handler_id < 0) {
4530 // see comment in add_to_idle_resize above.
4531 pending_visual_change.idle_handler_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_visual_changer, this, NULL);
4532 pending_visual_change.being_handled = false;
4537 Editor::_idle_visual_changer (void* arg)
4539 return static_cast<Editor*>(arg)->idle_visual_changer ();
4543 Editor::idle_visual_changer ()
4545 /* set_horizontal_position() below (and maybe other calls) call
4546 gtk_main_iteration(), so it's possible that a signal will be handled
4547 half-way through this method. If this signal wants an
4548 idle_visual_changer we must schedule another one after this one, so
4549 mark the idle_handler_id as -1 here to allow that. Also make a note
4550 that we are doing the visual change, so that changes in response to
4551 super-rapid-screen-update can be dropped if we are still processing
4555 pending_visual_change.idle_handler_id = -1;
4556 pending_visual_change.being_handled = true;
4558 VisualChange vc = pending_visual_change;
4560 pending_visual_change.pending = (VisualChange::Type) 0;
4562 visual_changer (vc);
4564 pending_visual_change.being_handled = false;
4566 return 0; /* this is always a one-shot call */
4570 Editor::visual_changer (const VisualChange& vc)
4572 double const last_time_origin = horizontal_position ();
4574 if (vc.pending & VisualChange::ZoomLevel) {
4575 set_samples_per_pixel (vc.samples_per_pixel);
4577 compute_fixed_ruler_scale ();
4579 std::vector<TempoMap::BBTPoint> grid;
4580 compute_current_bbt_points (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4581 compute_bbt_ruler_scale (grid, vc.time_origin, pending_visual_change.time_origin + current_page_samples());
4582 update_tempo_based_rulers (grid);
4584 update_video_timeline();
4587 if (vc.pending & VisualChange::TimeOrigin) {
4588 set_horizontal_position (vc.time_origin / samples_per_pixel);
4591 if (vc.pending & VisualChange::YOrigin) {
4592 vertical_adjustment.set_value (vc.y_origin);
4595 if (last_time_origin == horizontal_position ()) {
4596 /* changed signal not emitted */
4597 update_fixed_rulers ();
4598 redisplay_tempo (true);
4601 if (!(vc.pending & VisualChange::ZoomLevel)) {
4602 update_video_timeline();
4605 _summary->set_overlays_dirty ();
4608 struct EditorOrderTimeAxisSorter {
4609 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4610 return a->order () < b->order ();
4615 Editor::sort_track_selection (TrackViewList& sel)
4617 EditorOrderTimeAxisSorter cmp;
4622 Editor::get_preferred_edit_position (EditIgnoreOption ignore, bool from_context_menu, bool from_outside_canvas)
4625 framepos_t where = 0;
4626 EditPoint ep = _edit_point;
4628 if (Profile->get_mixbus())
4629 if (ep == EditAtSelectedMarker)
4630 ep = EditAtPlayhead;
4632 if (from_outside_canvas && (ep == EditAtMouse)) {
4633 ep = EditAtPlayhead;
4634 } else if (from_context_menu && (ep == EditAtMouse)) {
4635 return canvas_event_sample (&context_click_event, 0, 0);
4638 if (entered_marker) {
4639 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4640 return entered_marker->position();
4643 if ( (ignore==EDIT_IGNORE_PHEAD) && ep == EditAtPlayhead) {
4644 ep = EditAtSelectedMarker;
4647 if ( (ignore==EDIT_IGNORE_MOUSE) && ep == EditAtMouse) {
4648 ep = EditAtPlayhead;
4652 case EditAtPlayhead:
4653 if (_dragging_playhead) {
4654 where = *_control_scroll_target;
4656 where = _session->audible_frame();
4658 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4661 case EditAtSelectedMarker:
4662 if (!selection->markers.empty()) {
4664 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4667 where = loc->start();
4671 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4679 if (!mouse_frame (where, ignored)) {
4680 /* XXX not right but what can we do ? */
4684 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4692 Editor::set_loop_range (framepos_t start, framepos_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);
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 (framepos_t start, framepos_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);
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, framepos_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 (
4772 (framepos_t) floor ( (double) where * tr->speed()));
4774 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4775 RegionView* rv = rtv->view()->find_view (*i);
4786 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4788 const TrackViewList* tracks;
4791 tracks = &track_views;
4796 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4797 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4799 boost::shared_ptr<Track> tr;
4800 boost::shared_ptr<Playlist> pl;
4802 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4804 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4805 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4807 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4809 RegionView* rv = rtv->view()->find_view (*i);
4820 /** Get regions using the following method:
4822 * Make a region list using:
4823 * (a) any selected regions
4824 * (b) the intersection of any selected tracks and the edit point(*)
4825 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4827 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4829 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4833 Editor::get_regions_from_selection_and_edit_point ()
4835 RegionSelection regions;
4837 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4838 regions.add (entered_regionview);
4840 regions = selection->regions;
4843 if ( regions.empty() ) {
4844 TrackViewList tracks = selection->tracks;
4846 if (!tracks.empty()) {
4847 /* no region selected or entered, but some selected tracks:
4848 * act on all regions on the selected tracks at the edit point
4850 framepos_t const where = get_preferred_edit_position ();
4851 get_regions_at(regions, where, tracks);
4858 /** Get regions using the following method:
4860 * Make a region list using:
4861 * (a) any selected regions
4862 * (b) the intersection of any selected tracks and the edit point(*)
4863 * (c) if neither exists, then whatever region is under the mouse
4865 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4867 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4870 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4872 RegionSelection regions;
4874 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4875 regions.add (entered_regionview);
4877 regions = selection->regions;
4880 if ( regions.empty() ) {
4881 TrackViewList tracks = selection->tracks;
4883 if (!tracks.empty()) {
4884 /* no region selected or entered, but some selected tracks:
4885 * act on all regions on the selected tracks at the edit point
4887 get_regions_at(regions, pos, tracks);
4894 /** Start with regions that are selected, or the entered regionview if none are selected.
4895 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4896 * of the regions that we started with.
4900 Editor::get_regions_from_selection_and_entered () const
4902 RegionSelection regions = selection->regions;
4904 if (regions.empty() && entered_regionview) {
4905 regions.add (entered_regionview);
4912 Editor::get_regionviews_by_id (PBD::ID const id, RegionSelection & regions) const
4914 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4915 RouteTimeAxisView* rtav;
4917 if ((rtav = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4918 boost::shared_ptr<Playlist> pl;
4919 std::vector<boost::shared_ptr<Region> > results;
4920 boost::shared_ptr<Track> tr;
4922 if ((tr = rtav->track()) == 0) {
4927 if ((pl = (tr->playlist())) != 0) {
4928 boost::shared_ptr<Region> r = pl->region_by_id (id);
4930 RegionView* rv = rtav->view()->find_view (r);
4932 regions.push_back (rv);
4941 Editor::get_per_region_note_selection (list<pair<PBD::ID, set<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > > &selection) const
4944 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4945 MidiTimeAxisView* mtav;
4947 if ((mtav = dynamic_cast<MidiTimeAxisView*> (*i)) != 0) {
4949 mtav->get_per_region_note_selection (selection);
4956 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4958 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4960 RouteTimeAxisView* tatv;
4962 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4964 boost::shared_ptr<Playlist> pl;
4965 vector<boost::shared_ptr<Region> > results;
4967 boost::shared_ptr<Track> tr;
4969 if ((tr = tatv->track()) == 0) {
4974 if ((pl = (tr->playlist())) != 0) {
4975 if (src_comparison) {
4976 pl->get_source_equivalent_regions (region, results);
4978 pl->get_region_list_equivalent_regions (region, results);
4982 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4983 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4984 regions.push_back (marv);
4993 Editor::show_rhythm_ferret ()
4995 if (rhythm_ferret == 0) {
4996 rhythm_ferret = new RhythmFerret(*this);
4999 rhythm_ferret->set_session (_session);
5000 rhythm_ferret->show ();
5001 rhythm_ferret->present ();
5005 Editor::first_idle ()
5007 MessageDialog* dialog = 0;
5009 if (track_views.size() > 1) {
5010 Timers::TimerSuspender t;
5011 dialog = new MessageDialog (
5012 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
5016 ARDOUR_UI::instance()->flush_pending ();
5019 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
5023 // first idle adds route children (automation tracks), so we need to redisplay here
5024 _routes->redisplay ();
5028 if (_session->undo_depth() == 0) {
5029 undo_action->set_sensitive(false);
5031 redo_action->set_sensitive(false);
5032 begin_selection_op_history ();
5038 Editor::_idle_resize (gpointer arg)
5040 return ((Editor*)arg)->idle_resize ();
5044 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
5046 if (resize_idle_id < 0) {
5047 /* https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html#G-PRIORITY-HIGH-IDLE:CAPS
5048 * GTK+ uses G_PRIORITY_HIGH_IDLE + 10 for resizing operations, and G_PRIORITY_HIGH_IDLE + 20 for redrawing operations.
5049 * (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)
5051 resize_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE + 10, _idle_resize, this, NULL);
5052 _pending_resize_amount = 0;
5055 /* make a note of the smallest resulting height, so that we can clamp the
5056 lower limit at TimeAxisView::hSmall */
5058 int32_t min_resulting = INT32_MAX;
5060 _pending_resize_amount += h;
5061 _pending_resize_view = view;
5063 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
5065 if (selection->tracks.contains (_pending_resize_view)) {
5066 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5067 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
5071 if (min_resulting < 0) {
5076 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
5077 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
5081 /** Handle pending resizing of tracks */
5083 Editor::idle_resize ()
5085 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
5087 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
5088 selection->tracks.contains (_pending_resize_view)) {
5090 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5091 if (*i != _pending_resize_view) {
5092 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
5097 _pending_resize_amount = 0;
5098 _group_tabs->set_dirty ();
5099 resize_idle_id = -1;
5107 ENSURE_GUI_THREAD (*this, &Editor::located);
5110 playhead_cursor->set_position (_session->audible_frame ());
5111 if (_follow_playhead && !_pending_initial_locate) {
5112 reset_x_origin_to_follow_playhead ();
5116 _pending_locate_request = false;
5117 _pending_initial_locate = false;
5121 Editor::region_view_added (RegionView * rv)
5123 for (list<PBD::ID>::iterator pr = selection->regions.pending.begin (); pr != selection->regions.pending.end (); ++pr) {
5124 if (rv->region ()->id () == (*pr)) {
5125 selection->add (rv);
5126 selection->regions.pending.erase (pr);
5131 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (rv);
5133 list<pair<PBD::ID const, list<boost::shared_ptr<Evoral::Note<Evoral::Beats> > > > >::iterator rnote;
5134 for (rnote = selection->pending_midi_note_selection.begin(); rnote != selection->pending_midi_note_selection.end(); ++rnote) {
5135 if (rv->region()->id () == (*rnote).first) {
5136 mrv->select_notes ((*rnote).second);
5137 selection->pending_midi_note_selection.erase(rnote);
5143 _summary->set_background_dirty ();
5147 Editor::region_view_removed ()
5149 _summary->set_background_dirty ();
5153 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
5155 TrackViewList::const_iterator j = track_views.begin ();
5156 while (j != track_views.end()) {
5157 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
5158 if (rtv && rtv->route() == r) {
5169 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
5173 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
5174 TimeAxisView* tv = axis_view_from_route (*i);
5184 Editor::suspend_route_redisplay ()
5187 _routes->suspend_redisplay();
5192 Editor::resume_route_redisplay ()
5195 _routes->redisplay(); // queue redisplay
5196 _routes->resume_redisplay();
5201 Editor::add_routes (RouteList& routes)
5203 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
5205 RouteTimeAxisView *rtv;
5206 list<RouteTimeAxisView*> new_views;
5207 TrackViewList new_selection;
5208 bool from_scratch = (track_views.size() == 0);
5210 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
5211 boost::shared_ptr<Route> route = (*x);
5213 if (route->is_auditioner() || route->is_monitor()) {
5217 DataType dt = route->input()->default_type();
5219 if (dt == ARDOUR::DataType::AUDIO) {
5220 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
5221 rtv->set_route (route);
5222 } else if (dt == ARDOUR::DataType::MIDI) {
5223 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
5224 rtv->set_route (route);
5226 throw unknown_type();
5229 new_views.push_back (rtv);
5230 track_views.push_back (rtv);
5231 new_selection.push_back (rtv);
5233 rtv->effective_gain_display ();
5235 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
5236 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
5239 if (new_views.size() > 0) {
5240 _routes->routes_added (new_views);
5241 _summary->routes_added (new_views);
5244 if (!from_scratch) {
5245 selection->tracks.clear();
5246 selection->add (new_selection);
5247 begin_selection_op_history();
5250 if (show_editor_mixer_when_tracks_arrive) {
5251 show_editor_mixer (true);
5254 editor_list_button.set_sensitive (true);
5258 Editor::timeaxisview_deleted (TimeAxisView *tv)
5260 if (tv == entered_track) {
5264 if (_session && _session->deletion_in_progress()) {
5265 /* the situation is under control */
5269 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
5271 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
5273 _routes->route_removed (tv);
5275 TimeAxisView::Children c = tv->get_child_list ();
5276 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
5277 if (entered_track == i->get()) {
5282 /* remove it from the list of track views */
5284 TrackViewList::iterator i;
5286 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5287 i = track_views.erase (i);
5290 /* update whatever the current mixer strip is displaying, if revelant */
5292 boost::shared_ptr<Route> route;
5295 route = rtav->route ();
5298 if (current_mixer_strip && current_mixer_strip->route() == route) {
5300 TimeAxisView* next_tv;
5302 if (track_views.empty()) {
5304 } else if (i == track_views.end()) {
5305 next_tv = track_views.front();
5312 set_selected_mixer_strip (*next_tv);
5314 /* make the editor mixer strip go away setting the
5315 * button to inactive (which also unticks the menu option)
5318 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5324 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5326 if (apply_to_selection) {
5327 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5329 TrackSelection::iterator j = i;
5332 hide_track_in_display (*i, false);
5337 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5339 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5340 // this will hide the mixer strip
5341 set_selected_mixer_strip (*tv);
5344 _routes->hide_track_in_display (*tv);
5349 Editor::sync_track_view_list_and_routes ()
5351 track_views = TrackViewList (_routes->views ());
5353 _summary->set_background_dirty();
5354 _group_tabs->set_dirty ();
5356 return false; // do not call again (until needed)
5360 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5362 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5367 /** Find a RouteTimeAxisView by the ID of its route */
5369 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5371 RouteTimeAxisView* v;
5373 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5374 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5375 if(v->route()->id() == id) {
5385 Editor::fit_route_group (RouteGroup *g)
5387 TrackViewList ts = axis_views_from_routes (g->route_list ());
5392 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5394 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5397 _session->cancel_audition ();
5401 if (_session->is_auditioning()) {
5402 _session->cancel_audition ();
5403 if (r == last_audition_region) {
5408 _session->audition_region (r);
5409 last_audition_region = r;
5414 Editor::hide_a_region (boost::shared_ptr<Region> r)
5416 r->set_hidden (true);
5420 Editor::show_a_region (boost::shared_ptr<Region> r)
5422 r->set_hidden (false);
5426 Editor::audition_region_from_region_list ()
5428 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5432 Editor::hide_region_from_region_list ()
5434 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5438 Editor::show_region_in_region_list ()
5440 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5444 Editor::step_edit_status_change (bool yn)
5447 start_step_editing ();
5449 stop_step_editing ();
5454 Editor::start_step_editing ()
5456 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5460 Editor::stop_step_editing ()
5462 step_edit_connection.disconnect ();
5466 Editor::check_step_edit ()
5468 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5469 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5471 mtv->check_step_edit ();
5475 return true; // do it again, till we stop
5479 Editor::scroll_press (Direction dir)
5481 ++_scroll_callbacks;
5483 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5484 /* delay the first auto-repeat */
5490 scroll_backward (1);
5498 scroll_up_one_track ();
5502 scroll_down_one_track ();
5506 /* do hacky auto-repeat */
5507 if (!_scroll_connection.connected ()) {
5509 _scroll_connection = Glib::signal_timeout().connect (
5510 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5513 _scroll_callbacks = 0;
5520 Editor::scroll_release ()
5522 _scroll_connection.disconnect ();
5525 /** Queue a change for the Editor viewport x origin to follow the playhead */
5527 Editor::reset_x_origin_to_follow_playhead ()
5529 framepos_t const frame = playhead_cursor->current_frame ();
5531 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5533 if (_session->transport_speed() < 0) {
5535 if (frame > (current_page_samples() / 2)) {
5536 center_screen (frame-(current_page_samples()/2));
5538 center_screen (current_page_samples()/2);
5545 if (frame < leftmost_frame) {
5547 if (_session->transport_rolling()) {
5548 /* rolling; end up with the playhead at the right of the page */
5549 l = frame - current_page_samples ();
5551 /* not rolling: end up with the playhead 1/4 of the way along the page */
5552 l = frame - current_page_samples() / 4;
5556 if (_session->transport_rolling()) {
5557 /* rolling: end up with the playhead on the left of the page */
5560 /* not rolling: end up with the playhead 3/4 of the way along the page */
5561 l = frame - 3 * current_page_samples() / 4;
5569 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5575 Editor::super_rapid_screen_update ()
5577 if (!_session || !_session->engine().running()) {
5581 /* METERING / MIXER STRIPS */
5583 /* update track meters, if required */
5584 if (contents().is_mapped() && meters_running) {
5585 RouteTimeAxisView* rtv;
5586 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5587 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5588 rtv->fast_update ();
5593 /* and any current mixer strip */
5594 if (current_mixer_strip) {
5595 current_mixer_strip->fast_update ();
5598 /* PLAYHEAD AND VIEWPORT */
5600 framepos_t const frame = _session->audible_frame();
5602 /* There are a few reasons why we might not update the playhead / viewport stuff:
5604 * 1. we don't update things when there's a pending locate request, otherwise
5605 * when the editor requests a locate there is a chance that this method
5606 * will move the playhead before the locate request is processed, causing
5608 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5609 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5612 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5614 last_update_frame = frame;
5616 if (!_dragging_playhead) {
5617 playhead_cursor->set_position (frame);
5620 if (!_stationary_playhead) {
5622 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5623 /* We only do this if we aren't already
5624 handling a visual change (ie if
5625 pending_visual_change.being_handled is
5626 false) so that these requests don't stack
5627 up there are too many of them to handle in
5630 reset_x_origin_to_follow_playhead ();
5635 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5636 framepos_t const frame = playhead_cursor->current_frame ();
5637 double target = ((double)frame - (double)current_page_samples()/2.0);
5638 if (target <= 0.0) {
5641 // compare to EditorCursor::set_position()
5642 double const old_pos = sample_to_pixel_unrounded (leftmost_frame);
5643 double const new_pos = sample_to_pixel_unrounded (target);
5644 if (rint (new_pos) != rint (old_pos)) {
5645 reset_x_origin (pixel_to_sample (floor (new_pos)));
5656 Editor::session_going_away ()
5658 _have_idled = false;
5660 _session_connections.drop_connections ();
5662 super_rapid_screen_update_connection.disconnect ();
5664 selection->clear ();
5665 cut_buffer->clear ();
5667 clicked_regionview = 0;
5668 clicked_axisview = 0;
5669 clicked_routeview = 0;
5670 entered_regionview = 0;
5672 last_update_frame = 0;
5675 playhead_cursor->hide ();
5677 /* rip everything out of the list displays */
5681 _route_groups->clear ();
5683 /* do this first so that deleting a track doesn't reset cms to null
5684 and thus cause a leak.
5687 if (current_mixer_strip) {
5688 if (current_mixer_strip->get_parent() != 0) {
5689 global_hpacker.remove (*current_mixer_strip);
5691 delete current_mixer_strip;
5692 current_mixer_strip = 0;
5695 /* delete all trackviews */
5697 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5700 track_views.clear ();
5702 nudge_clock->set_session (0);
5704 editor_list_button.set_active(false);
5705 editor_list_button.set_sensitive(false);
5707 /* clear tempo/meter rulers */
5708 remove_metric_marks ();
5710 clear_marker_display ();
5712 stop_step_editing ();
5716 /* get rid of any existing editor mixer strip */
5718 WindowTitle title(Glib::get_application_name());
5719 title += _("Editor");
5721 own_window()->set_title (title.get_string());
5724 SessionHandlePtr::session_going_away ();
5728 Editor::trigger_script (int i)
5730 LuaInstance::instance()-> call_action (i);
5734 Editor::set_script_action_name (int i, const std::string& n)
5736 string const a = string_compose (X_("script-action-%1"), i + 1);
5737 Glib::RefPtr<Action> act = ActionManager::get_action(X_("Editor"), a.c_str());
5740 act->set_label (string_compose (_("Unset #%1"), i + 1));
5741 act->set_tooltip (_("no action bound"));
5742 act->set_sensitive (false);
5745 act->set_tooltip (n);
5746 act->set_sensitive (true);
5748 KeyEditor::UpdateBindings ();
5752 Editor::show_editor_list (bool yn)
5755 _the_notebook.show ();
5757 _the_notebook.hide ();
5762 Editor::change_region_layering_order (bool from_context_menu)
5764 const framepos_t position = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context_menu);
5766 if (!clicked_routeview) {
5767 if (layering_order_editor) {
5768 layering_order_editor->hide ();
5773 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5779 boost::shared_ptr<Playlist> pl = track->playlist();
5785 if (layering_order_editor == 0) {
5786 layering_order_editor = new RegionLayeringOrderEditor (*this);
5789 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5790 layering_order_editor->maybe_present ();
5794 Editor::update_region_layering_order_editor ()
5796 if (layering_order_editor && layering_order_editor->is_visible ()) {
5797 change_region_layering_order (true);
5802 Editor::setup_fade_images ()
5804 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5805 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5806 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5807 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5808 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5810 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5811 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5812 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5813 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5814 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5816 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5817 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5818 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5819 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5820 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5822 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5823 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5824 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5825 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5826 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5830 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5832 Editor::action_menu_item (std::string const & name)
5834 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5837 return *manage (a->create_menu_item ());
5841 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5843 EventBox* b = manage (new EventBox);
5844 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5845 Label* l = manage (new Label (name));
5849 _the_notebook.append_page (widget, *b);
5853 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5855 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5856 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5859 if (ev->type == GDK_2BUTTON_PRESS) {
5861 /* double-click on a notebook tab shrinks or expands the notebook */
5863 if (_notebook_shrunk) {
5864 if (pre_notebook_shrink_pane_width) {
5865 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5867 _notebook_shrunk = false;
5869 pre_notebook_shrink_pane_width = edit_pane.get_position();
5871 /* this expands the LHS of the edit pane to cover the notebook
5872 PAGE but leaves the tabs visible.
5874 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5875 _notebook_shrunk = true;
5883 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5885 using namespace Menu_Helpers;
5887 MenuList& items = _control_point_context_menu.items ();
5890 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5891 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5892 if (!can_remove_control_point (item)) {
5893 items.back().set_sensitive (false);
5896 _control_point_context_menu.popup (event->button.button, event->button.time);
5900 Editor::popup_note_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5902 using namespace Menu_Helpers;
5904 NoteBase* note = reinterpret_cast<NoteBase*>(item->get_data("notebase"));
5909 /* We need to get the selection here and pass it to the operations, since
5910 popping up the menu will cause a region leave event which clears
5911 entered_regionview. */
5913 MidiRegionView& mrv = note->region_view();
5914 const RegionSelection rs = get_regions_from_selection_and_entered ();
5915 const uint32_t sel_size = mrv.selection_size ();
5917 MenuList& items = _note_context_menu.items();
5921 items.push_back(MenuElem(_("Delete"),
5922 sigc::mem_fun(mrv, &MidiRegionView::delete_selection)));
5925 items.push_back(MenuElem(_("Edit..."),
5926 sigc::bind(sigc::mem_fun(*this, &Editor::edit_notes), &mrv)));
5927 if (sel_size != 1) {
5928 items.back().set_sensitive (false);
5931 items.push_back(MenuElem(_("Transpose..."),
5932 sigc::bind(sigc::mem_fun(*this, &Editor::transpose_regions), rs)));
5935 items.push_back(MenuElem(_("Legatize"),
5936 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, false)));
5938 items.back().set_sensitive (false);
5941 items.push_back(MenuElem(_("Quantize..."),
5942 sigc::bind(sigc::mem_fun(*this, &Editor::quantize_regions), rs)));
5944 items.push_back(MenuElem(_("Remove Overlap"),
5945 sigc::bind(sigc::mem_fun(*this, &Editor::legatize_regions), rs, true)));
5947 items.back().set_sensitive (false);
5950 items.push_back(MenuElem(_("Transform..."),
5951 sigc::bind(sigc::mem_fun(*this, &Editor::transform_regions), rs)));
5953 _note_context_menu.popup (event->button.button, event->button.time);
5957 Editor::zoom_vertical_modifier_released()
5959 _stepping_axis_view = 0;
5963 Editor::ui_parameter_changed (string parameter)
5965 if (parameter == "icon-set") {
5966 while (!_cursor_stack.empty()) {
5967 _cursor_stack.pop_back();
5969 _cursors->set_cursor_set (UIConfiguration::instance().get_icon_set());
5970 _cursor_stack.push_back(_cursors->grabber);
5971 } else if (parameter == "draggable-playhead") {
5972 if (_verbose_cursor) {
5973 playhead_cursor->set_sensitive (UIConfiguration::instance().get_draggable_playhead());
5979 Editor::use_own_window (bool and_fill_it)
5981 bool new_window = !own_window();
5983 Gtk::Window* win = Tabbable::use_own_window (and_fill_it);
5985 if (win && new_window) {
5986 win->set_name ("EditorWindow");
5988 ARDOUR_UI::instance()->setup_toplevel_window (*win, _("Editor"), this);
5990 // win->signal_realize().connect (*this, &Editor::on_realize);
5991 win->signal_event().connect (sigc::bind (sigc::ptr_fun (&Keyboard::catch_user_event_for_pre_dialog_focus), win));
5992 win->signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
5993 win->set_data ("ardour-bindings", bindings);
5998 DisplaySuspender ds;
5999 contents().show_all ();
6001 /* XXX: this is a bit unfortunate; it would probably
6002 be nicer if we could just call show () above rather
6003 than needing the show_all ()
6006 /* re-hide stuff if necessary */
6007 editor_list_button_toggled ();
6008 parameter_changed ("show-summary");
6009 parameter_changed ("show-group-tabs");
6010 parameter_changed ("show-zoom-tools");
6012 /* now reset all audio_time_axis heights, because widgets might need
6018 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6019 tv = (static_cast<TimeAxisView*>(*i));
6020 tv->reset_height ();
6023 if (current_mixer_strip) {
6024 current_mixer_strip->hide_things ();
6025 current_mixer_strip->parameter_changed ("mixer-element-visibility");