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"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "canvas/debug.h"
74 #include "canvas/text.h"
76 #include "control_protocol/control_protocol.h"
80 #include "analysis_window.h"
81 #include "audio_clock.h"
82 #include "audio_region_view.h"
83 #include "audio_streamview.h"
84 #include "audio_time_axis.h"
85 #include "automation_time_axis.h"
86 #include "bundle_manager.h"
87 #include "crossfade_edit.h"
91 #include "editor_cursors.h"
92 #include "editor_drag.h"
93 #include "editor_group_tabs.h"
94 #include "editor_locations.h"
95 #include "editor_regions.h"
96 #include "editor_route_groups.h"
97 #include "editor_routes.h"
98 #include "editor_snapshots.h"
99 #include "editor_summary.h"
100 #include "global_port_matrix.h"
101 #include "gui_object.h"
102 #include "gui_thread.h"
103 #include "keyboard.h"
105 #include "midi_time_axis.h"
106 #include "mixer_strip.h"
107 #include "mixer_ui.h"
108 #include "mouse_cursors.h"
109 #include "playlist_selector.h"
110 #include "public_editor.h"
111 #include "region_layering_order_editor.h"
112 #include "rgb_macros.h"
113 #include "rhythm_ferret.h"
114 #include "selection.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 using namespace ARDOUR;
126 using namespace Glib;
127 using namespace Gtkmm2ext;
128 using namespace Editing;
130 using PBD::internationalize;
132 using Gtkmm2ext::Keyboard;
134 const double Editor::timebar_height = 15.0;
136 static const gchar *_snap_type_strings[] = {
138 N_("Timecode Frames"),
139 N_("Timecode Seconds"),
140 N_("Timecode Minutes"),
170 static const gchar *_snap_mode_strings[] = {
177 static const gchar *_edit_point_strings[] = {
184 static const gchar *_zoom_focus_strings[] = {
194 #ifdef USE_RUBBERBAND
195 static const gchar *_rb_opt_strings[] = {
198 N_("Balanced multitimbral mixture"),
199 N_("Unpitched percussion with stable notes"),
200 N_("Crisp monophonic instrumental"),
201 N_("Unpitched solo percussion"),
202 N_("Resample without preserving pitch"),
208 pane_size_watcher (Paned* pane)
210 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
214 Quartz: impossible to access
216 so stop that by preventing it from ever getting too narrow. 35
217 pixels is basically a rough guess at the tab width.
222 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
224 gint pos = pane->get_position ();
226 if (pos > max_width_of_lhs) {
227 pane->set_position (max_width_of_lhs);
232 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
234 /* time display buttons */
235 , minsec_label (_("Mins:Secs"))
236 , bbt_label (_("Bars:Beats"))
237 , timecode_label (_("Timecode"))
238 , samples_label (_("Samples"))
239 , tempo_label (_("Tempo"))
240 , meter_label (_("Meter"))
241 , mark_label (_("Location Markers"))
242 , range_mark_label (_("Range Markers"))
243 , transport_mark_label (_("Loop/Punch Ranges"))
244 , cd_mark_label (_("CD Markers"))
245 , videotl_label (_("Video Timeline"))
246 , edit_packer (4, 4, true)
248 /* the values here don't matter: layout widgets
249 reset them as needed.
252 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
253 , horizontal_adjustment (0.0, 0.0, 1e16)
254 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
256 , controls_layout (unused_adjustment, vertical_adjustment)
258 /* tool bar related */
260 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
262 , toolbar_selection_clock_table (2,3)
264 , automation_mode_button (_("mode"))
266 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
270 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
271 , meters_running(false)
272 , _pending_locate_request (false)
273 , _pending_initial_locate (false)
274 , _last_cut_copy_source_track (0)
276 , _region_selection_change_updates_region_list (true)
277 , _following_mixer_selection (false)
278 , _control_point_toggled_on_press (false)
279 , _stepping_axis_view (0)
283 /* we are a singleton */
285 PublicEditor::_instance = this;
289 selection = new Selection (this);
290 cut_buffer = new Selection (this);
292 clicked_regionview = 0;
293 clicked_axisview = 0;
294 clicked_routeview = 0;
295 clicked_control_point = 0;
296 last_update_frame = 0;
297 pre_press_cursor = 0;
298 _drags = new DragManager (this);
299 current_mixer_strip = 0;
302 snap_type_strings = I18N (_snap_type_strings);
303 snap_mode_strings = I18N (_snap_mode_strings);
304 zoom_focus_strings = I18N (_zoom_focus_strings);
305 edit_point_strings = I18N (_edit_point_strings);
306 #ifdef USE_RUBBERBAND
307 rb_opt_strings = I18N (_rb_opt_strings);
311 snap_threshold = 5.0;
312 bbt_beat_subdivision = 4;
313 _visible_canvas_width = 0;
314 _visible_canvas_height = 0;
315 last_autoscroll_x = 0;
316 last_autoscroll_y = 0;
317 autoscroll_active = false;
318 autoscroll_timeout_tag = -1;
323 current_interthread_info = 0;
324 _show_measures = true;
326 show_gain_after_trim = false;
328 have_pending_keyboard_selection = false;
329 _follow_playhead = true;
330 _stationary_playhead = false;
331 editor_ruler_menu = 0;
332 no_ruler_shown_update = false;
334 range_marker_menu = 0;
335 marker_menu_item = 0;
336 tempo_or_meter_marker_menu = 0;
337 transport_marker_menu = 0;
338 new_transport_marker_menu = 0;
339 editor_mixer_strip_width = Wide;
340 show_editor_mixer_when_tracks_arrive = false;
341 region_edit_menu_split_multichannel_item = 0;
342 region_edit_menu_split_item = 0;
345 current_stepping_trackview = 0;
347 entered_regionview = 0;
349 clear_entered_track = false;
352 button_release_can_deselect = true;
353 _dragging_playhead = false;
354 _dragging_edit_point = false;
355 select_new_marker = false;
357 layering_order_editor = 0;
358 no_save_visual = false;
360 within_track_canvas = false;
362 scrubbing_direction = 0;
366 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
367 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
368 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
369 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
370 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
372 _edit_point = EditAtMouse;
373 _internal_editing = false;
374 current_canvas_cursor = 0;
376 samples_per_pixel = 2048; /* too early to use reset_zoom () */
378 _scroll_callbacks = 0;
380 zoom_focus = ZoomFocusLeft;
381 set_zoom_focus (ZoomFocusLeft);
382 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
384 bbt_label.set_name ("EditorRulerLabel");
385 bbt_label.set_size_request (-1, (int)timebar_height);
386 bbt_label.set_alignment (1.0, 0.5);
387 bbt_label.set_padding (5,0);
389 bbt_label.set_no_show_all();
390 minsec_label.set_name ("EditorRulerLabel");
391 minsec_label.set_size_request (-1, (int)timebar_height);
392 minsec_label.set_alignment (1.0, 0.5);
393 minsec_label.set_padding (5,0);
394 minsec_label.hide ();
395 minsec_label.set_no_show_all();
396 timecode_label.set_name ("EditorRulerLabel");
397 timecode_label.set_size_request (-1, (int)timebar_height);
398 timecode_label.set_alignment (1.0, 0.5);
399 timecode_label.set_padding (5,0);
400 timecode_label.hide ();
401 timecode_label.set_no_show_all();
402 samples_label.set_name ("EditorRulerLabel");
403 samples_label.set_size_request (-1, (int)timebar_height);
404 samples_label.set_alignment (1.0, 0.5);
405 samples_label.set_padding (5,0);
406 samples_label.hide ();
407 samples_label.set_no_show_all();
409 tempo_label.set_name ("EditorRulerLabel");
410 tempo_label.set_size_request (-1, (int)timebar_height);
411 tempo_label.set_alignment (1.0, 0.5);
412 tempo_label.set_padding (5,0);
414 tempo_label.set_no_show_all();
416 meter_label.set_name ("EditorRulerLabel");
417 meter_label.set_size_request (-1, (int)timebar_height);
418 meter_label.set_alignment (1.0, 0.5);
419 meter_label.set_padding (5,0);
421 meter_label.set_no_show_all();
423 mark_label.set_name ("EditorRulerLabel");
424 mark_label.set_size_request (-1, (int)timebar_height);
425 mark_label.set_alignment (1.0, 0.5);
426 mark_label.set_padding (5,0);
428 mark_label.set_no_show_all();
430 cd_mark_label.set_name ("EditorRulerLabel");
431 cd_mark_label.set_size_request (-1, (int)timebar_height);
432 cd_mark_label.set_alignment (1.0, 0.5);
433 cd_mark_label.set_padding (5,0);
434 cd_mark_label.hide();
435 cd_mark_label.set_no_show_all();
437 videotl_bar_height = 4;
438 videotl_label.set_name ("EditorRulerLabel");
439 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
440 videotl_label.set_alignment (1.0, 0.5);
441 videotl_label.set_padding (5,0);
442 videotl_label.hide();
443 videotl_label.set_no_show_all();
445 range_mark_label.set_name ("EditorRulerLabel");
446 range_mark_label.set_size_request (-1, (int)timebar_height);
447 range_mark_label.set_alignment (1.0, 0.5);
448 range_mark_label.set_padding (5,0);
449 range_mark_label.hide();
450 range_mark_label.set_no_show_all();
452 transport_mark_label.set_name ("EditorRulerLabel");
453 transport_mark_label.set_size_request (-1, (int)timebar_height);
454 transport_mark_label.set_alignment (1.0, 0.5);
455 transport_mark_label.set_padding (5,0);
456 transport_mark_label.hide();
457 transport_mark_label.set_no_show_all();
459 initialize_rulers ();
460 initialize_canvas ();
462 _summary = new EditorSummary (this);
464 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
465 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
467 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
469 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
470 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
472 edit_controls_vbox.set_spacing (0);
473 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
474 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
476 HBox* h = manage (new HBox);
477 _group_tabs = new EditorGroupTabs (this);
478 h->pack_start (*_group_tabs, PACK_SHRINK);
479 h->pack_start (edit_controls_vbox);
480 controls_layout.add (*h);
482 controls_layout.set_name ("EditControlsBase");
483 controls_layout.add_events (Gdk::SCROLL_MASK);
484 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
486 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
487 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
489 _cursors = new MouseCursors;
491 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
493 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
494 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
495 pad_line_1->set_outline_color (0xFF0000FF);
501 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
502 time_canvas_vbox.set_size_request (-1, -1);
504 ruler_label_event_box.add (ruler_label_vbox);
505 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
506 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
508 time_bars_event_box.add (time_bars_vbox);
509 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 time_canvas_event_box.add (time_canvas_vbox);
513 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
515 edit_packer.set_col_spacings (0);
516 edit_packer.set_row_spacings (0);
517 edit_packer.set_homogeneous (false);
518 edit_packer.set_border_width (0);
519 edit_packer.set_name ("EditorWindow");
521 /* labels for the rulers */
522 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
523 /* labels for the marker "tracks" (time bars) */
524 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
526 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
528 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
529 /* time bars canvas */
530 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
532 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
534 bottom_hbox.set_border_width (2);
535 bottom_hbox.set_spacing (3);
537 _route_groups = new EditorRouteGroups (this);
538 _routes = new EditorRoutes (this);
539 _regions = new EditorRegions (this);
540 _snapshots = new EditorSnapshots (this);
541 _locations = new EditorLocations (this);
543 add_notebook_page (_("Regions"), _regions->widget ());
544 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
545 add_notebook_page (_("Snapshots"), _snapshots->widget ());
546 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
547 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
549 _the_notebook.set_show_tabs (true);
550 _the_notebook.set_scrollable (true);
551 _the_notebook.popup_disable ();
552 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
553 _the_notebook.show_all ();
555 _notebook_shrunk = false;
557 editor_summary_pane.pack1(edit_packer);
559 Button* summary_arrows_left_left = manage (new Button);
560 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
561 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
562 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
564 Button* summary_arrows_left_right = manage (new Button);
565 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
566 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
567 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 VBox* summary_arrows_left = manage (new VBox);
570 summary_arrows_left->pack_start (*summary_arrows_left_left);
571 summary_arrows_left->pack_start (*summary_arrows_left_right);
573 Button* summary_arrows_right_up = manage (new Button);
574 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
575 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
576 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 Button* summary_arrows_right_down = manage (new Button);
579 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
580 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
581 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 VBox* summary_arrows_right = manage (new VBox);
584 summary_arrows_right->pack_start (*summary_arrows_right_up);
585 summary_arrows_right->pack_start (*summary_arrows_right_down);
587 Frame* summary_frame = manage (new Frame);
588 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
590 summary_frame->add (*_summary);
591 summary_frame->show ();
593 _summary_hbox.pack_start (*summary_arrows_left, false, false);
594 _summary_hbox.pack_start (*summary_frame, true, true);
595 _summary_hbox.pack_start (*summary_arrows_right, false, false);
597 editor_summary_pane.pack2 (_summary_hbox);
599 edit_pane.pack1 (editor_summary_pane, true, true);
600 edit_pane.pack2 (_the_notebook, false, true);
602 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
604 /* XXX: editor_summary_pane might need similar to the edit_pane */
606 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
608 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
609 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
611 top_hbox.pack_start (toolbar_frame);
613 HBox *hbox = manage (new HBox);
614 hbox->pack_start (edit_pane, true, true);
616 global_vpacker.pack_start (top_hbox, false, false);
617 global_vpacker.pack_start (*hbox, true, true);
619 global_hpacker.pack_start (global_vpacker, true, true);
621 set_name ("EditorWindow");
622 add_accel_group (ActionManager::ui_manager->get_accel_group());
624 status_bar_hpacker.show ();
626 vpacker.pack_end (status_bar_hpacker, false, false);
627 vpacker.pack_end (global_hpacker, true, true);
629 /* register actions now so that set_state() can find them and set toggles/checks etc */
632 /* when we start using our own keybinding system for the editor, this
633 * will be uncommented
639 _snap_type = SnapToBeat;
640 set_snap_to (_snap_type);
641 _snap_mode = SnapOff;
642 set_snap_mode (_snap_mode);
643 set_mouse_mode (MouseObject, true);
644 pre_internal_mouse_mode = MouseObject;
645 pre_internal_snap_type = _snap_type;
646 pre_internal_snap_mode = _snap_mode;
647 internal_snap_type = _snap_type;
648 internal_snap_mode = _snap_mode;
649 set_edit_point_preference (EditAtMouse, true);
651 _playlist_selector = new PlaylistSelector();
652 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
654 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
658 nudge_forward_button.set_name ("zoom button");
659 nudge_forward_button.add_elements (ArdourButton::FlatFace);
660 nudge_forward_button.set_image(::get_icon("nudge_right"));
662 nudge_backward_button.set_name ("zoom button");
663 nudge_backward_button.add_elements (ArdourButton::FlatFace);
664 nudge_backward_button.set_image(::get_icon("nudge_left"));
666 fade_context_menu.set_name ("ArdourContextMenu");
668 /* icons, titles, WM stuff */
670 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
671 Glib::RefPtr<Gdk::Pixbuf> icon;
673 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
683 window_icons.push_back (icon);
685 if (!window_icons.empty()) {
686 // set_icon_list (window_icons);
687 set_default_icon_list (window_icons);
690 WindowTitle title(Glib::get_application_name());
691 title += _("Editor");
692 set_title (title.get_string());
693 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
696 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
698 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
699 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
701 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
703 /* allow external control surfaces/protocols to do various things */
705 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
706 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
707 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
708 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
709 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
710 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
711 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
712 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
713 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
714 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
715 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
716 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
717 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
718 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
720 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
721 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
722 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
723 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
724 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
726 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
728 /* problematic: has to return a value and thus cannot be x-thread */
730 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
732 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
734 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
736 _ignore_region_action = false;
737 _last_region_menu_was_main = false;
738 _popup_region_menu_item = 0;
740 _show_marker_lines = false;
741 _over_region_trim_target = false;
743 /* Button bindings */
745 button_bindings = new Bindings;
747 XMLNode* node = button_settings();
749 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
750 button_bindings->load (**i);
757 setup_fade_images ();
762 delete button_bindings;
764 delete _route_groups;
765 delete _time_bars_canvas_viewport;
766 delete _track_canvas_viewport;
771 Editor::button_settings () const
773 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
774 XMLNode* node = find_named_node (*settings, X_("Buttons"));
777 node = new XMLNode (X_("Buttons"));
784 Editor::add_toplevel_controls (Container& cont)
786 vpacker.pack_start (cont, false, false);
791 Editor::get_smart_mode () const
793 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
797 Editor::catch_vanishing_regionview (RegionView *rv)
799 /* note: the selection will take care of the vanishing
800 audioregionview by itself.
803 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
807 if (clicked_regionview == rv) {
808 clicked_regionview = 0;
811 if (entered_regionview == rv) {
812 set_entered_regionview (0);
815 if (!_all_region_actions_sensitized) {
816 sensitize_all_region_actions (true);
819 _over_region_trim_target = false;
823 Editor::set_entered_regionview (RegionView* rv)
825 if (rv == entered_regionview) {
829 if (entered_regionview) {
830 entered_regionview->exited ();
833 if ((entered_regionview = rv) != 0) {
834 entered_regionview->entered (internal_editing ());
837 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
838 /* This RegionView entry might have changed what region actions
839 are allowed, so sensitize them all in case a key is pressed.
841 sensitize_all_region_actions (true);
846 Editor::set_entered_track (TimeAxisView* tav)
849 entered_track->exited ();
852 if ((entered_track = tav) != 0) {
853 entered_track->entered ();
858 Editor::show_window ()
860 if (!is_visible ()) {
863 /* XXX: this is a bit unfortunate; it would probably
864 be nicer if we could just call show () above rather
865 than needing the show_all ()
868 /* re-hide stuff if necessary */
869 editor_list_button_toggled ();
870 parameter_changed ("show-summary");
871 parameter_changed ("show-group-tabs");
872 parameter_changed ("show-zoom-tools");
874 /* now reset all audio_time_axis heights, because widgets might need
880 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
881 tv = (static_cast<TimeAxisView*>(*i));
885 if (current_mixer_strip) {
886 current_mixer_strip->hide_things ();
887 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
895 Editor::instant_save ()
897 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
902 _session->add_instant_xml(get_state());
904 Config->add_instant_xml(get_state());
909 Editor::zoom_adjustment_changed ()
915 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
916 bool clamped = clamp_samples_per_pixel (fpu);
919 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
926 Editor::control_vertical_zoom_in_all ()
928 tav_zoom_smooth (false, true);
932 Editor::control_vertical_zoom_out_all ()
934 tav_zoom_smooth (true, true);
938 Editor::control_vertical_zoom_in_selected ()
940 tav_zoom_smooth (false, false);
944 Editor::control_vertical_zoom_out_selected ()
946 tav_zoom_smooth (true, false);
950 Editor::control_view (uint32_t view)
952 goto_visual_state (view);
956 Editor::control_unselect ()
958 selection->clear_tracks ();
962 Editor::control_select (uint32_t rid, Selection::Operation op)
964 /* handles the (static) signal from the ControlProtocol class that
965 * requests setting the selected track to a given RID
972 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
978 TimeAxisView* tav = axis_view_from_route (r);
983 selection->add (tav);
985 case Selection::Toggle:
986 selection->toggle (tav);
988 case Selection::Extend:
991 selection->set (tav);
995 selection->clear_tracks ();
1000 Editor::control_step_tracks_up ()
1002 scroll_tracks_up_line ();
1006 Editor::control_step_tracks_down ()
1008 scroll_tracks_down_line ();
1012 Editor::control_scroll (float fraction)
1014 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1020 double step = fraction * current_page_samples();
1023 _control_scroll_target is an optional<T>
1025 it acts like a pointer to an framepos_t, with
1026 a operator conversion to boolean to check
1027 that it has a value could possibly use
1028 playhead_cursor->current_frame to store the
1029 value and a boolean in the class to know
1030 when it's out of date
1033 if (!_control_scroll_target) {
1034 _control_scroll_target = _session->transport_frame();
1035 _dragging_playhead = true;
1038 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1039 *_control_scroll_target = 0;
1040 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1041 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1043 *_control_scroll_target += (framepos_t) floor (step);
1046 /* move visuals, we'll catch up with it later */
1048 playhead_cursor->set_position (*_control_scroll_target);
1049 UpdateAllTransportClocks (*_control_scroll_target);
1051 if (*_control_scroll_target > (current_page_samples() / 2)) {
1052 /* try to center PH in window */
1053 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1059 Now we do a timeout to actually bring the session to the right place
1060 according to the playhead. This is to avoid reading disk buffers on every
1061 call to control_scroll, which is driven by ScrollTimeline and therefore
1062 probably by a control surface wheel which can generate lots of events.
1064 /* cancel the existing timeout */
1066 control_scroll_connection.disconnect ();
1068 /* add the next timeout */
1070 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1074 Editor::deferred_control_scroll (framepos_t /*target*/)
1076 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1077 // reset for next stream
1078 _control_scroll_target = boost::none;
1079 _dragging_playhead = false;
1084 Editor::access_action (std::string action_group, std::string action_item)
1090 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1093 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1101 Editor::on_realize ()
1103 Window::on_realize ();
1108 Editor::map_position_change (framepos_t frame)
1110 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1112 if (_session == 0) {
1116 if (_follow_playhead) {
1117 center_screen (frame);
1120 playhead_cursor->set_position (frame);
1124 Editor::center_screen (framepos_t frame)
1126 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1128 /* if we're off the page, then scroll.
1131 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1132 center_screen_internal (frame, page);
1137 Editor::center_screen_internal (framepos_t frame, float page)
1142 frame -= (framepos_t) page;
1147 reset_x_origin (frame);
1152 Editor::update_title ()
1154 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1157 bool dirty = _session->dirty();
1159 string session_name;
1161 if (_session->snap_name() != _session->name()) {
1162 session_name = _session->snap_name();
1164 session_name = _session->name();
1168 session_name = "*" + session_name;
1171 WindowTitle title(session_name);
1172 title += Glib::get_application_name();
1173 set_title (title.get_string());
1175 /* ::session_going_away() will have taken care of it */
1180 Editor::set_session (Session *t)
1182 SessionHandlePtr::set_session (t);
1188 zoom_range_clock->set_session (_session);
1189 _playlist_selector->set_session (_session);
1190 nudge_clock->set_session (_session);
1191 _summary->set_session (_session);
1192 _group_tabs->set_session (_session);
1193 _route_groups->set_session (_session);
1194 _regions->set_session (_session);
1195 _snapshots->set_session (_session);
1196 _routes->set_session (_session);
1197 _locations->set_session (_session);
1199 if (rhythm_ferret) {
1200 rhythm_ferret->set_session (_session);
1203 if (analysis_window) {
1204 analysis_window->set_session (_session);
1208 sfbrowser->set_session (_session);
1211 compute_fixed_ruler_scale ();
1213 /* Make sure we have auto loop and auto punch ranges */
1215 Location* loc = _session->locations()->auto_loop_location();
1217 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1219 if (loc->start() == loc->end()) {
1220 loc->set_end (loc->start() + 1);
1223 _session->locations()->add (loc, false);
1224 _session->set_auto_loop_location (loc);
1227 loc->set_name (_("Loop"));
1230 loc = _session->locations()->auto_punch_location();
1233 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1235 if (loc->start() == loc->end()) {
1236 loc->set_end (loc->start() + 1);
1239 _session->locations()->add (loc, false);
1240 _session->set_auto_punch_location (loc);
1243 loc->set_name (_("Punch"));
1246 refresh_location_display ();
1248 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1249 the selected Marker; this needs the LocationMarker list to be available.
1251 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1252 set_state (*node, Stateful::loading_state_version);
1254 /* catch up with the playhead */
1256 _session->request_locate (playhead_cursor->current_frame ());
1257 _pending_initial_locate = true;
1261 /* These signals can all be emitted by a non-GUI thread. Therefore the
1262 handlers for them must not attempt to directly interact with the GUI,
1263 but use Gtkmm2ext::UI::instance()->call_slot();
1266 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1267 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1268 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1269 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1270 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1271 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1272 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1273 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1274 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1275 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1276 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1277 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1278 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1279 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1281 playhead_cursor->show ();
1283 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1284 Config->map_parameters (pc);
1285 _session->config.map_parameters (pc);
1287 restore_ruler_visibility ();
1288 //tempo_map_changed (PropertyChange (0));
1289 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1291 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1292 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1295 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1296 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1299 switch (_snap_type) {
1300 case SnapToRegionStart:
1301 case SnapToRegionEnd:
1302 case SnapToRegionSync:
1303 case SnapToRegionBoundary:
1304 build_region_boundary_cache ();
1311 /* register for undo history */
1312 _session->register_with_memento_command_factory(id(), this);
1314 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1316 start_updating_meters ();
1320 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1322 if (a->get_name() == "RegionMenu") {
1323 /* When the main menu's region menu is opened, we setup the actions so that they look right
1324 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1325 so we resensitize all region actions when the entered regionview or the region selection
1326 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1327 happens after the region context menu is opened. So we set a flag here, too.
1331 sensitize_the_right_region_actions ();
1332 _last_region_menu_was_main = true;
1337 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1339 using namespace Menu_Helpers;
1341 void (Editor::*emf)(FadeShape);
1342 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1345 images = &_xfade_in_images;
1346 emf = &Editor::set_fade_in_shape;
1348 images = &_xfade_out_images;
1349 emf = &Editor::set_fade_out_shape;
1354 _("Linear (for highly correlated material)"),
1355 *(*images)[FadeLinear],
1356 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1360 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1364 _("Constant power"),
1365 *(*images)[FadeConstantPower],
1366 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1369 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1374 *(*images)[FadeSymmetric],
1375 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1379 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1384 *(*images)[FadeSlow],
1385 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1388 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1393 *(*images)[FadeFast],
1394 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1397 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 /** Pop up a context menu for when the user clicks on a start crossfade */
1402 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1404 using namespace Menu_Helpers;
1406 MenuList& items (xfade_in_context_menu.items());
1408 if (items.empty()) {
1409 fill_xfade_menu (items, true);
1412 xfade_in_context_menu.popup (button, time);
1415 /** Pop up a context menu for when the user clicks on an end crossfade */
1417 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1419 using namespace Menu_Helpers;
1421 MenuList& items (xfade_out_context_menu.items());
1423 if (items.empty()) {
1424 fill_xfade_menu (items, false);
1427 xfade_out_context_menu.popup (button, time);
1431 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1433 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1435 using namespace Menu_Helpers;
1436 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1439 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1443 MenuList& items (fade_context_menu.items());
1446 switch (item_type) {
1448 case FadeInHandleItem:
1449 if (arv->audio_region()->fade_in_active()) {
1450 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1452 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1455 items.push_back (SeparatorElem());
1457 if (Profile->get_sae()) {
1459 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1460 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1467 *_fade_in_images[FadeLinear],
1468 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 *_fade_in_images[FadeSlow],
1478 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 *_fade_in_images[FadeFast],
1487 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 *_fade_in_images[FadeSymmetric],
1496 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1501 _("Constant power"),
1502 *_fade_in_images[FadeConstantPower],
1503 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 case FadeOutHandleItem:
1513 if (arv->audio_region()->fade_out_active()) {
1514 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1516 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1519 items.push_back (SeparatorElem());
1521 if (Profile->get_sae()) {
1522 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1523 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1529 *_fade_out_images[FadeLinear],
1530 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1534 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1539 *_fade_out_images[FadeSlow],
1540 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1543 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1548 *_fade_out_images[FadeFast],
1549 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1552 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1557 *_fade_out_images[FadeSymmetric],
1558 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1563 _("Constant power"),
1564 *_fade_out_images[FadeConstantPower],
1565 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1568 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1574 fatal << _("programming error: ")
1575 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1580 fade_context_menu.popup (button, time);
1584 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1586 using namespace Menu_Helpers;
1587 Menu* (Editor::*build_menu_function)();
1590 switch (item_type) {
1592 case RegionViewName:
1593 case RegionViewNameHighlight:
1594 case LeftFrameHandle:
1595 case RightFrameHandle:
1596 if (with_selection) {
1597 build_menu_function = &Editor::build_track_selection_context_menu;
1599 build_menu_function = &Editor::build_track_region_context_menu;
1604 if (with_selection) {
1605 build_menu_function = &Editor::build_track_selection_context_menu;
1607 build_menu_function = &Editor::build_track_context_menu;
1612 if (clicked_routeview->track()) {
1613 build_menu_function = &Editor::build_track_context_menu;
1615 build_menu_function = &Editor::build_track_bus_context_menu;
1620 /* probably shouldn't happen but if it does, we don't care */
1624 menu = (this->*build_menu_function)();
1625 menu->set_name ("ArdourContextMenu");
1627 /* now handle specific situations */
1629 switch (item_type) {
1631 case RegionViewName:
1632 case RegionViewNameHighlight:
1633 case LeftFrameHandle:
1634 case RightFrameHandle:
1635 if (!with_selection) {
1636 if (region_edit_menu_split_item) {
1637 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1638 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1640 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1643 if (region_edit_menu_split_multichannel_item) {
1644 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1645 region_edit_menu_split_multichannel_item->set_sensitive (true);
1647 region_edit_menu_split_multichannel_item->set_sensitive (false);
1660 /* probably shouldn't happen but if it does, we don't care */
1664 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1666 /* Bounce to disk */
1668 using namespace Menu_Helpers;
1669 MenuList& edit_items = menu->items();
1671 edit_items.push_back (SeparatorElem());
1673 switch (clicked_routeview->audio_track()->freeze_state()) {
1674 case AudioTrack::NoFreeze:
1675 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1678 case AudioTrack::Frozen:
1679 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1682 case AudioTrack::UnFrozen:
1683 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1689 if (item_type == StreamItem && clicked_routeview) {
1690 clicked_routeview->build_underlay_menu(menu);
1693 /* When the region menu is opened, we setup the actions so that they look right
1696 sensitize_the_right_region_actions ();
1697 _last_region_menu_was_main = false;
1699 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1700 menu->popup (button, time);
1704 Editor::build_track_context_menu ()
1706 using namespace Menu_Helpers;
1708 MenuList& edit_items = track_context_menu.items();
1711 add_dstream_context_items (edit_items);
1712 return &track_context_menu;
1716 Editor::build_track_bus_context_menu ()
1718 using namespace Menu_Helpers;
1720 MenuList& edit_items = track_context_menu.items();
1723 add_bus_context_items (edit_items);
1724 return &track_context_menu;
1728 Editor::build_track_region_context_menu ()
1730 using namespace Menu_Helpers;
1731 MenuList& edit_items = track_region_context_menu.items();
1734 /* we've just cleared the track region context menu, so the menu that these
1735 two items were on will have disappeared; stop them dangling.
1737 region_edit_menu_split_item = 0;
1738 region_edit_menu_split_multichannel_item = 0;
1740 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1743 boost::shared_ptr<Track> tr;
1744 boost::shared_ptr<Playlist> pl;
1746 if ((tr = rtv->track())) {
1747 add_region_context_items (edit_items, tr);
1751 add_dstream_context_items (edit_items);
1753 return &track_region_context_menu;
1757 Editor::analyze_region_selection ()
1759 if (analysis_window == 0) {
1760 analysis_window = new AnalysisWindow();
1763 analysis_window->set_session(_session);
1765 analysis_window->show_all();
1768 analysis_window->set_regionmode();
1769 analysis_window->analyze();
1771 analysis_window->present();
1775 Editor::analyze_range_selection()
1777 if (analysis_window == 0) {
1778 analysis_window = new AnalysisWindow();
1781 analysis_window->set_session(_session);
1783 analysis_window->show_all();
1786 analysis_window->set_rangemode();
1787 analysis_window->analyze();
1789 analysis_window->present();
1793 Editor::build_track_selection_context_menu ()
1795 using namespace Menu_Helpers;
1796 MenuList& edit_items = track_selection_context_menu.items();
1797 edit_items.clear ();
1799 add_selection_context_items (edit_items);
1800 // edit_items.push_back (SeparatorElem());
1801 // add_dstream_context_items (edit_items);
1803 return &track_selection_context_menu;
1807 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1809 using namespace Menu_Helpers;
1811 /* OK, stick the region submenu at the top of the list, and then add
1815 RegionSelection rs = get_regions_from_selection_and_entered ();
1817 string::size_type pos = 0;
1818 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1820 /* we have to hack up the region name because "_" has a special
1821 meaning for menu titles.
1824 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1825 menu_item_name.replace (pos, 1, "__");
1829 if (_popup_region_menu_item == 0) {
1830 _popup_region_menu_item = new MenuItem (menu_item_name);
1831 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1832 _popup_region_menu_item->show ();
1834 _popup_region_menu_item->set_label (menu_item_name);
1837 const framepos_t position = get_preferred_edit_position (false, true);
1839 edit_items.push_back (*_popup_region_menu_item);
1840 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1841 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1843 edit_items.push_back (SeparatorElem());
1846 /** Add context menu items relevant to selection ranges.
1847 * @param edit_items List to add the items to.
1850 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1852 using namespace Menu_Helpers;
1854 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1855 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1857 edit_items.push_back (SeparatorElem());
1858 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1860 edit_items.push_back (SeparatorElem());
1862 edit_items.push_back (
1864 _("Move Range Start to Previous Region Boundary"),
1865 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1869 edit_items.push_back (
1871 _("Move Range Start to Next Region Boundary"),
1872 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1876 edit_items.push_back (
1878 _("Move Range End to Previous Region Boundary"),
1879 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1883 edit_items.push_back (
1885 _("Move Range End to Next Region Boundary"),
1886 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1890 edit_items.push_back (SeparatorElem());
1891 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1892 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1894 edit_items.push_back (SeparatorElem());
1895 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1897 edit_items.push_back (SeparatorElem());
1898 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1899 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1901 edit_items.push_back (SeparatorElem());
1902 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1904 edit_items.push_back (SeparatorElem());
1905 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1906 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1907 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1909 edit_items.push_back (SeparatorElem());
1910 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1911 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1912 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1913 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1914 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1919 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1921 using namespace Menu_Helpers;
1925 Menu *play_menu = manage (new Menu);
1926 MenuList& play_items = play_menu->items();
1927 play_menu->set_name ("ArdourContextMenu");
1929 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1930 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1931 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1932 play_items.push_back (SeparatorElem());
1933 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1935 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1939 Menu *select_menu = manage (new Menu);
1940 MenuList& select_items = select_menu->items();
1941 select_menu->set_name ("ArdourContextMenu");
1943 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1944 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1945 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1946 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1947 select_items.push_back (SeparatorElem());
1948 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1949 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1950 select_items.push_back (SeparatorElem());
1951 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1952 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1953 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1954 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1955 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1956 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1957 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1959 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1963 Menu *cutnpaste_menu = manage (new Menu);
1964 MenuList& cutnpaste_items = cutnpaste_menu->items();
1965 cutnpaste_menu->set_name ("ArdourContextMenu");
1967 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1968 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1969 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1971 cutnpaste_items.push_back (SeparatorElem());
1973 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1974 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1976 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1978 /* Adding new material */
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1982 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1986 Menu *nudge_menu = manage (new Menu());
1987 MenuList& nudge_items = nudge_menu->items();
1988 nudge_menu->set_name ("ArdourContextMenu");
1990 edit_items.push_back (SeparatorElem());
1991 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1992 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1993 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1994 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1996 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2000 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2002 using namespace Menu_Helpers;
2006 Menu *play_menu = manage (new Menu);
2007 MenuList& play_items = play_menu->items();
2008 play_menu->set_name ("ArdourContextMenu");
2010 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2011 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2012 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2016 Menu *select_menu = manage (new Menu);
2017 MenuList& select_items = select_menu->items();
2018 select_menu->set_name ("ArdourContextMenu");
2020 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2021 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2022 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2023 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2024 select_items.push_back (SeparatorElem());
2025 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2026 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2027 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2028 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2030 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2034 Menu *cutnpaste_menu = manage (new Menu);
2035 MenuList& cutnpaste_items = cutnpaste_menu->items();
2036 cutnpaste_menu->set_name ("ArdourContextMenu");
2038 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2039 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2040 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2042 Menu *nudge_menu = manage (new Menu());
2043 MenuList& nudge_items = nudge_menu->items();
2044 nudge_menu->set_name ("ArdourContextMenu");
2046 edit_items.push_back (SeparatorElem());
2047 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2048 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2049 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2050 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2052 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2056 Editor::snap_type() const
2062 Editor::snap_mode() const
2068 Editor::set_snap_to (SnapType st)
2070 unsigned int snap_ind = (unsigned int)st;
2074 if (snap_ind > snap_type_strings.size() - 1) {
2076 _snap_type = (SnapType)snap_ind;
2079 string str = snap_type_strings[snap_ind];
2081 if (str != snap_type_selector.get_active_text()) {
2082 snap_type_selector.set_active_text (str);
2087 switch (_snap_type) {
2088 case SnapToBeatDiv128:
2089 case SnapToBeatDiv64:
2090 case SnapToBeatDiv32:
2091 case SnapToBeatDiv28:
2092 case SnapToBeatDiv24:
2093 case SnapToBeatDiv20:
2094 case SnapToBeatDiv16:
2095 case SnapToBeatDiv14:
2096 case SnapToBeatDiv12:
2097 case SnapToBeatDiv10:
2098 case SnapToBeatDiv8:
2099 case SnapToBeatDiv7:
2100 case SnapToBeatDiv6:
2101 case SnapToBeatDiv5:
2102 case SnapToBeatDiv4:
2103 case SnapToBeatDiv3:
2104 case SnapToBeatDiv2: {
2105 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2106 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2108 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2109 current_bbt_points_begin, current_bbt_points_end);
2110 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2111 current_bbt_points_begin, current_bbt_points_end);
2112 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2116 case SnapToRegionStart:
2117 case SnapToRegionEnd:
2118 case SnapToRegionSync:
2119 case SnapToRegionBoundary:
2120 build_region_boundary_cache ();
2128 SnapChanged (); /* EMIT SIGNAL */
2132 Editor::set_snap_mode (SnapMode mode)
2134 string str = snap_mode_strings[(int)mode];
2136 if (_internal_editing) {
2137 internal_snap_mode = mode;
2139 pre_internal_snap_mode = mode;
2144 if (str != snap_mode_selector.get_active_text ()) {
2145 snap_mode_selector.set_active_text (str);
2151 Editor::set_edit_point_preference (EditPoint ep, bool force)
2153 bool changed = (_edit_point != ep);
2156 string str = edit_point_strings[(int)ep];
2158 if (str != edit_point_selector.get_active_text ()) {
2159 edit_point_selector.set_active_text (str);
2162 set_canvas_cursor ();
2164 if (!force && !changed) {
2168 const char* action=NULL;
2170 switch (_edit_point) {
2171 case EditAtPlayhead:
2172 action = "edit-at-playhead";
2174 case EditAtSelectedMarker:
2175 action = "edit-at-marker";
2178 action = "edit-at-mouse";
2182 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2184 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2188 bool in_track_canvas;
2190 if (!mouse_frame (foo, in_track_canvas)) {
2191 in_track_canvas = false;
2194 reset_canvas_action_sensitivity (in_track_canvas);
2200 Editor::set_state (const XMLNode& node, int /*version*/)
2202 const XMLProperty* prop;
2209 g.base_width = default_width;
2210 g.base_height = default_height;
2214 if ((geometry = find_named_node (node, "geometry")) != 0) {
2218 if ((prop = geometry->property("x_size")) == 0) {
2219 prop = geometry->property ("x-size");
2222 g.base_width = atoi(prop->value());
2224 if ((prop = geometry->property("y_size")) == 0) {
2225 prop = geometry->property ("y-size");
2228 g.base_height = atoi(prop->value());
2231 if ((prop = geometry->property ("x_pos")) == 0) {
2232 prop = geometry->property ("x-pos");
2235 x = atoi (prop->value());
2238 if ((prop = geometry->property ("y_pos")) == 0) {
2239 prop = geometry->property ("y-pos");
2242 y = atoi (prop->value());
2246 set_default_size (g.base_width, g.base_height);
2249 if (_session && (prop = node.property ("playhead"))) {
2251 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2252 playhead_cursor->set_position (pos);
2254 playhead_cursor->set_position (0);
2257 if ((prop = node.property ("mixer-width"))) {
2258 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2261 if ((prop = node.property ("zoom-focus"))) {
2262 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2265 if ((prop = node.property ("zoom"))) {
2266 /* older versions of ardour used floating point samples_per_pixel */
2267 double f = PBD::atof (prop->value());
2268 cerr << "LOADED ZOOM from " << prop->value() << " as " << f << endl;
2269 reset_zoom (llrintf (f));
2271 reset_zoom (samples_per_pixel);
2274 if ((prop = node.property ("snap-to"))) {
2275 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2278 if ((prop = node.property ("snap-mode"))) {
2279 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2282 if ((prop = node.property ("internal-snap-to"))) {
2283 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2286 if ((prop = node.property ("internal-snap-mode"))) {
2287 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2290 if ((prop = node.property ("pre-internal-snap-to"))) {
2291 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2295 if ((prop = node.property ("pre-internal-snap-mode"))) {
2296 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2299 if ((prop = node.property ("mouse-mode"))) {
2300 MouseMode m = str2mousemode(prop->value());
2301 set_mouse_mode (m, true);
2303 set_mouse_mode (MouseObject, true);
2306 if ((prop = node.property ("left-frame")) != 0) {
2308 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2312 reset_x_origin (pos);
2316 if ((prop = node.property ("y-origin")) != 0) {
2317 reset_y_origin (atof (prop->value ()));
2320 if ((prop = node.property ("internal-edit"))) {
2321 bool yn = string_is_affirmative (prop->value());
2322 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2324 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2325 tact->set_active (!yn);
2326 tact->set_active (yn);
2330 if ((prop = node.property ("join-object-range"))) {
2331 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2332 bool yn = string_is_affirmative (prop->value());
2334 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2335 tact->set_active (!yn);
2336 tact->set_active (yn);
2338 set_mouse_mode(mouse_mode, true);
2341 if ((prop = node.property ("edit-point"))) {
2342 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2345 if ((prop = node.property ("show-measures"))) {
2346 bool yn = string_is_affirmative (prop->value());
2347 _show_measures = yn;
2348 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2350 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2351 /* do it twice to force the change */
2352 tact->set_active (!yn);
2353 tact->set_active (yn);
2357 if ((prop = node.property ("follow-playhead"))) {
2358 bool yn = string_is_affirmative (prop->value());
2359 set_follow_playhead (yn);
2360 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2362 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2363 if (tact->get_active() != yn) {
2364 tact->set_active (yn);
2369 if ((prop = node.property ("stationary-playhead"))) {
2370 bool yn = string_is_affirmative (prop->value());
2371 set_stationary_playhead (yn);
2372 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2374 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2375 if (tact->get_active() != yn) {
2376 tact->set_active (yn);
2381 if ((prop = node.property ("region-list-sort-type"))) {
2382 RegionListSortType st;
2383 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2386 if ((prop = node.property ("show-editor-mixer"))) {
2388 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2391 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2392 bool yn = string_is_affirmative (prop->value());
2394 /* do it twice to force the change */
2396 tact->set_active (!yn);
2397 tact->set_active (yn);
2400 if ((prop = node.property ("show-editor-list"))) {
2402 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2405 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2406 bool yn = string_is_affirmative (prop->value());
2408 /* do it twice to force the change */
2410 tact->set_active (!yn);
2411 tact->set_active (yn);
2414 if ((prop = node.property (X_("editor-list-page")))) {
2415 _the_notebook.set_current_page (atoi (prop->value ()));
2418 if ((prop = node.property (X_("show-marker-lines")))) {
2419 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2421 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2422 bool yn = string_is_affirmative (prop->value ());
2424 tact->set_active (!yn);
2425 tact->set_active (yn);
2428 XMLNodeList children = node.children ();
2429 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2430 selection->set_state (**i, Stateful::current_state_version);
2431 _regions->set_state (**i);
2434 if ((prop = node.property ("maximised"))) {
2435 bool yn = string_is_affirmative (prop->value());
2437 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2441 if ((prop = node.property ("nudge-clock-value"))) {
2443 sscanf (prop->value().c_str(), "%" PRId64, &f);
2444 nudge_clock->set (f);
2446 nudge_clock->set_mode (AudioClock::Timecode);
2447 nudge_clock->set (_session->frame_rate() * 5, true);
2454 Editor::get_state ()
2456 XMLNode* node = new XMLNode ("Editor");
2459 id().print (buf, sizeof (buf));
2460 node->add_property ("id", buf);
2462 if (is_realized()) {
2463 Glib::RefPtr<Gdk::Window> win = get_window();
2465 int x, y, width, height;
2466 win->get_root_origin(x, y);
2467 win->get_size(width, height);
2469 XMLNode* geometry = new XMLNode ("geometry");
2471 snprintf(buf, sizeof(buf), "%d", width);
2472 geometry->add_property("x-size", string(buf));
2473 snprintf(buf, sizeof(buf), "%d", height);
2474 geometry->add_property("y-size", string(buf));
2475 snprintf(buf, sizeof(buf), "%d", x);
2476 geometry->add_property("x-pos", string(buf));
2477 snprintf(buf, sizeof(buf), "%d", y);
2478 geometry->add_property("y-pos", string(buf));
2479 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2480 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2481 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2482 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2483 geometry->add_property("edit-vertical-pane-pos", string(buf));
2485 node->add_child_nocopy (*geometry);
2488 maybe_add_mixer_strip_width (*node);
2490 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2492 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2493 node->add_property ("zoom", buf);
2494 node->add_property ("snap-to", enum_2_string (_snap_type));
2495 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2496 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2497 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2498 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2499 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2500 node->add_property ("edit-point", enum_2_string (_edit_point));
2502 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2503 node->add_property ("playhead", buf);
2504 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2505 node->add_property ("left-frame", buf);
2506 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2507 node->add_property ("y-origin", buf);
2509 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2510 node->add_property ("maximised", _maximised ? "yes" : "no");
2511 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2512 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2513 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2514 node->add_property ("mouse-mode", enum2str(mouse_mode));
2515 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2516 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2518 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2520 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2521 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2524 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2526 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2527 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2530 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2531 node->add_property (X_("editor-list-page"), buf);
2533 if (button_bindings) {
2534 XMLNode* bb = new XMLNode (X_("Buttons"));
2535 button_bindings->save (*bb);
2536 node->add_child_nocopy (*bb);
2539 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2541 node->add_child_nocopy (selection->get_state ());
2542 node->add_child_nocopy (_regions->get_state ());
2544 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2545 node->add_property ("nudge-clock-value", buf);
2552 /** @param y y offset from the top of all trackviews.
2553 * @return pair: TimeAxisView that y is over, layer index.
2554 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2555 * in stacked or expanded region display mode, otherwise 0.
2557 std::pair<TimeAxisView *, double>
2558 Editor::trackview_by_y_position (double y)
2560 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2562 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2568 return std::make_pair ( (TimeAxisView *) 0, 0);
2571 /** Snap a position to the grid, if appropriate, taking into account current
2572 * grid settings and also the state of any snap modifier keys that may be pressed.
2573 * @param start Position to snap.
2574 * @param event Event to get current key modifier information from, or 0.
2577 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2579 if (!_session || !event) {
2583 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2584 if (_snap_mode == SnapOff) {
2585 snap_to_internal (start, direction, for_mark);
2588 if (_snap_mode != SnapOff) {
2589 snap_to_internal (start, direction, for_mark);
2595 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2597 if (!_session || _snap_mode == SnapOff) {
2601 snap_to_internal (start, direction, for_mark);
2605 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2607 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2608 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2610 switch (_snap_type) {
2611 case SnapToTimecodeFrame:
2612 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2613 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2615 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2619 case SnapToTimecodeSeconds:
2620 if (_session->config.get_timecode_offset_negative()) {
2621 start += _session->config.get_timecode_offset ();
2623 start -= _session->config.get_timecode_offset ();
2625 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2626 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2628 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2631 if (_session->config.get_timecode_offset_negative()) {
2632 start -= _session->config.get_timecode_offset ();
2634 start += _session->config.get_timecode_offset ();
2638 case SnapToTimecodeMinutes:
2639 if (_session->config.get_timecode_offset_negative()) {
2640 start += _session->config.get_timecode_offset ();
2642 start -= _session->config.get_timecode_offset ();
2644 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2645 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2647 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2649 if (_session->config.get_timecode_offset_negative()) {
2650 start -= _session->config.get_timecode_offset ();
2652 start += _session->config.get_timecode_offset ();
2656 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2662 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2664 const framepos_t one_second = _session->frame_rate();
2665 const framepos_t one_minute = _session->frame_rate() * 60;
2666 framepos_t presnap = start;
2670 switch (_snap_type) {
2671 case SnapToTimecodeFrame:
2672 case SnapToTimecodeSeconds:
2673 case SnapToTimecodeMinutes:
2674 return timecode_snap_to_internal (start, direction, for_mark);
2677 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2678 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2680 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2685 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2686 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2688 start = (framepos_t) floor ((double) start / one_second) * one_second;
2693 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2694 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2696 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2701 start = _session->tempo_map().round_to_bar (start, direction);
2705 start = _session->tempo_map().round_to_beat (start, direction);
2708 case SnapToBeatDiv128:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2711 case SnapToBeatDiv64:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2714 case SnapToBeatDiv32:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2717 case SnapToBeatDiv28:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2720 case SnapToBeatDiv24:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2723 case SnapToBeatDiv20:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2726 case SnapToBeatDiv16:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2729 case SnapToBeatDiv14:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2732 case SnapToBeatDiv12:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2735 case SnapToBeatDiv10:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2738 case SnapToBeatDiv8:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2741 case SnapToBeatDiv7:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2744 case SnapToBeatDiv6:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2747 case SnapToBeatDiv5:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2750 case SnapToBeatDiv4:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2753 case SnapToBeatDiv3:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2756 case SnapToBeatDiv2:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2765 _session->locations()->marks_either_side (start, before, after);
2767 if (before == max_framepos && after == max_framepos) {
2768 /* No marks to snap to, so just don't snap */
2770 } else if (before == max_framepos) {
2772 } else if (after == max_framepos) {
2774 } else if (before != max_framepos && after != max_framepos) {
2775 /* have before and after */
2776 if ((start - before) < (after - start)) {
2785 case SnapToRegionStart:
2786 case SnapToRegionEnd:
2787 case SnapToRegionSync:
2788 case SnapToRegionBoundary:
2789 if (!region_boundary_cache.empty()) {
2791 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2792 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2794 if (direction > 0) {
2795 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2797 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2800 if (next != region_boundary_cache.begin ()) {
2805 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2806 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2808 if (start > (p + n) / 2) {
2817 switch (_snap_mode) {
2823 if (presnap > start) {
2824 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2828 } else if (presnap < start) {
2829 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2835 /* handled at entry */
2843 Editor::setup_toolbar ()
2845 HBox* mode_box = manage(new HBox);
2846 mode_box->set_border_width (2);
2847 mode_box->set_spacing(4);
2849 HBox* mouse_mode_box = manage (new HBox);
2850 HBox* mouse_mode_hbox = manage (new HBox);
2851 VBox* mouse_mode_vbox = manage (new VBox);
2852 Alignment* mouse_mode_align = manage (new Alignment);
2854 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2855 // mouse_mode_size_group->add_widget (smart_mode_button);
2856 mouse_mode_size_group->add_widget (mouse_move_button);
2857 mouse_mode_size_group->add_widget (mouse_select_button);
2858 mouse_mode_size_group->add_widget (mouse_zoom_button);
2859 mouse_mode_size_group->add_widget (mouse_gain_button);
2860 mouse_mode_size_group->add_widget (mouse_timefx_button);
2861 mouse_mode_size_group->add_widget (mouse_audition_button);
2862 mouse_mode_size_group->add_widget (mouse_draw_button);
2863 mouse_mode_size_group->add_widget (internal_edit_button);
2865 /* make them just a bit bigger */
2866 mouse_move_button.set_size_request (-1, 30);
2868 mouse_mode_hbox->set_spacing (2);
2870 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2874 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2875 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2876 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2877 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2878 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2880 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2882 mouse_mode_align->add (*mouse_mode_vbox);
2883 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2885 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2887 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2888 if (!Profile->get_sae()) {
2889 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2891 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2893 edit_mode_selector.set_name ("EditModeSelector");
2894 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2895 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2897 mode_box->pack_start (edit_mode_selector, false, false);
2898 mode_box->pack_start (*mouse_mode_box, false, false);
2900 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2901 _mouse_mode_tearoff->set_name ("MouseModeBase");
2902 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2904 if (Profile->get_sae()) {
2905 _mouse_mode_tearoff->set_can_be_torn_off (false);
2908 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2909 &_mouse_mode_tearoff->tearoff_window()));
2910 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2911 &_mouse_mode_tearoff->tearoff_window(), 1));
2912 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2913 &_mouse_mode_tearoff->tearoff_window()));
2914 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2915 &_mouse_mode_tearoff->tearoff_window(), 1));
2919 _zoom_box.set_spacing (2);
2920 _zoom_box.set_border_width (2);
2924 zoom_in_button.set_name ("zoom button");
2925 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2926 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2927 zoom_in_button.set_image(::get_icon ("zoom_in"));
2928 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2929 zoom_in_button.set_related_action (act);
2931 zoom_out_button.set_name ("zoom button");
2932 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2933 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2934 zoom_out_button.set_image(::get_icon ("zoom_out"));
2935 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2936 zoom_out_button.set_related_action (act);
2938 zoom_out_full_button.set_name ("zoom button");
2939 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2940 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2941 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2942 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2943 zoom_out_full_button.set_related_action (act);
2945 zoom_focus_selector.set_name ("ZoomFocusSelector");
2946 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2947 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2949 _zoom_box.pack_start (zoom_out_button, false, false);
2950 _zoom_box.pack_start (zoom_in_button, false, false);
2951 _zoom_box.pack_start (zoom_out_full_button, false, false);
2953 _zoom_box.pack_start (zoom_focus_selector, false, false);
2955 /* Track zoom buttons */
2956 tav_expand_button.set_name ("zoom button");
2957 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2958 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2959 tav_expand_button.set_size_request (-1, 20);
2960 tav_expand_button.set_image(::get_icon ("tav_exp"));
2961 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2962 tav_expand_button.set_related_action (act);
2964 tav_shrink_button.set_name ("zoom button");
2965 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2966 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2967 tav_shrink_button.set_size_request (-1, 20);
2968 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2969 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2970 tav_shrink_button.set_related_action (act);
2972 _zoom_box.pack_start (tav_shrink_button);
2973 _zoom_box.pack_start (tav_expand_button);
2975 _zoom_tearoff = manage (new TearOff (_zoom_box));
2977 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2978 &_zoom_tearoff->tearoff_window()));
2979 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2980 &_zoom_tearoff->tearoff_window(), 0));
2981 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2982 &_zoom_tearoff->tearoff_window()));
2983 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2984 &_zoom_tearoff->tearoff_window(), 0));
2986 snap_box.set_spacing (2);
2987 snap_box.set_border_width (2);
2989 snap_type_selector.set_name ("SnapTypeSelector");
2990 set_popdown_strings (snap_type_selector, snap_type_strings);
2991 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2993 snap_mode_selector.set_name ("SnapModeSelector");
2994 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2995 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2997 edit_point_selector.set_name ("EditPointSelector");
2998 set_popdown_strings (edit_point_selector, edit_point_strings);
2999 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3001 snap_box.pack_start (snap_mode_selector, false, false);
3002 snap_box.pack_start (snap_type_selector, false, false);
3003 snap_box.pack_start (edit_point_selector, false, false);
3007 HBox *nudge_box = manage (new HBox);
3008 nudge_box->set_spacing (2);
3009 nudge_box->set_border_width (2);
3011 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3012 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3014 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3015 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3017 nudge_box->pack_start (nudge_backward_button, false, false);
3018 nudge_box->pack_start (nudge_forward_button, false, false);
3019 nudge_box->pack_start (*nudge_clock, false, false);
3022 /* Pack everything in... */
3024 HBox* hbox = manage (new HBox);
3025 hbox->set_spacing(10);
3027 _tools_tearoff = manage (new TearOff (*hbox));
3028 _tools_tearoff->set_name ("MouseModeBase");
3029 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3031 if (Profile->get_sae()) {
3032 _tools_tearoff->set_can_be_torn_off (false);
3035 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3036 &_tools_tearoff->tearoff_window()));
3037 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3038 &_tools_tearoff->tearoff_window(), 0));
3039 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3040 &_tools_tearoff->tearoff_window()));
3041 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3042 &_tools_tearoff->tearoff_window(), 0));
3044 toolbar_hbox.set_spacing (10);
3045 toolbar_hbox.set_border_width (1);
3047 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3048 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3049 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3051 hbox->pack_start (snap_box, false, false);
3052 if (!Profile->get_small_screen()) {
3053 hbox->pack_start (*nudge_box, false, false);
3055 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3057 hbox->pack_start (panic_box, false, false);
3061 toolbar_base.set_name ("ToolBarBase");
3062 toolbar_base.add (toolbar_hbox);
3064 _toolbar_viewport.add (toolbar_base);
3065 /* stick to the required height but allow width to vary if there's not enough room */
3066 _toolbar_viewport.set_size_request (1, -1);
3068 toolbar_frame.set_shadow_type (SHADOW_OUT);
3069 toolbar_frame.set_name ("BaseFrame");
3070 toolbar_frame.add (_toolbar_viewport);
3074 Editor::setup_tooltips ()
3076 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3077 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3078 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3079 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3080 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3081 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3082 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3083 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3084 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3085 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3086 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3087 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3088 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3089 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3090 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3091 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3092 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3093 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3094 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3095 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3096 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3097 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3098 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3102 Editor::convert_drop_to_paths (
3103 vector<string>& paths,
3104 const RefPtr<Gdk::DragContext>& /*context*/,
3107 const SelectionData& data,
3111 if (_session == 0) {
3115 vector<string> uris = data.get_uris();
3119 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3120 are actually URI lists. So do it by hand.
3123 if (data.get_target() != "text/plain") {
3127 /* Parse the "uri-list" format that Nautilus provides,
3128 where each pathname is delimited by \r\n.
3130 THERE MAY BE NO NULL TERMINATING CHAR!!!
3133 string txt = data.get_text();
3137 p = (const char *) malloc (txt.length() + 1);
3138 txt.copy (const_cast<char *> (p), txt.length(), 0);
3139 const_cast<char*>(p)[txt.length()] = '\0';
3145 while (g_ascii_isspace (*p))
3149 while (*q && (*q != '\n') && (*q != '\r')) {
3156 while (q > p && g_ascii_isspace (*q))
3161 uris.push_back (string (p, q - p + 1));
3165 p = strchr (p, '\n');
3177 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3179 if ((*i).substr (0,7) == "file://") {
3181 string const p = PBD::url_decode (*i);
3183 // scan forward past three slashes
3185 string::size_type slashcnt = 0;
3186 string::size_type n = 0;
3187 string::const_iterator x = p.begin();
3189 while (slashcnt < 3 && x != p.end()) {
3192 } else if (slashcnt == 3) {
3199 if (slashcnt != 3 || x == p.end()) {
3200 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3204 paths.push_back (p.substr (n - 1));
3212 Editor::new_tempo_section ()
3218 Editor::map_transport_state ()
3220 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3222 if (_session && _session->transport_stopped()) {
3223 have_pending_keyboard_selection = false;
3226 update_loop_range_view (true);
3232 Editor::begin_reversible_command (string name)
3235 _session->begin_reversible_command (name);
3240 Editor::begin_reversible_command (GQuark q)
3243 _session->begin_reversible_command (q);
3248 Editor::commit_reversible_command ()
3251 _session->commit_reversible_command ();
3256 Editor::history_changed ()
3260 if (undo_action && _session) {
3261 if (_session->undo_depth() == 0) {
3262 label = S_("Command|Undo");
3264 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3266 undo_action->property_label() = label;
3269 if (redo_action && _session) {
3270 if (_session->redo_depth() == 0) {
3273 label = string_compose(_("Redo (%1)"), _session->next_redo());
3275 redo_action->property_label() = label;
3280 Editor::duplicate_range (bool with_dialog)
3284 RegionSelection rs = get_regions_from_selection_and_entered ();
3286 if ( selection->time.length() == 0 && rs.empty()) {
3292 ArdourDialog win (_("Duplicate"));
3293 Label label (_("Number of duplications:"));
3294 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3295 SpinButton spinner (adjustment, 0.0, 1);
3298 win.get_vbox()->set_spacing (12);
3299 win.get_vbox()->pack_start (hbox);
3300 hbox.set_border_width (6);
3301 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3303 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3304 place, visually. so do this by hand.
3307 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3308 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3309 spinner.grab_focus();
3315 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3316 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3317 win.set_default_response (RESPONSE_ACCEPT);
3319 spinner.grab_focus ();
3321 switch (win.run ()) {
3322 case RESPONSE_ACCEPT:
3328 times = adjustment.get_value();
3331 if ((current_mouse_mode() == Editing::MouseRange)) {
3332 if (selection->time.length()) {
3333 duplicate_selection (times);
3335 } else if (get_smart_mode()) {
3336 if (selection->time.length()) {
3337 duplicate_selection (times);
3339 duplicate_some_regions (rs, times);
3341 duplicate_some_regions (rs, times);
3346 Editor::set_edit_mode (EditMode m)
3348 Config->set_edit_mode (m);
3352 Editor::cycle_edit_mode ()
3354 switch (Config->get_edit_mode()) {
3356 if (Profile->get_sae()) {
3357 Config->set_edit_mode (Lock);
3359 Config->set_edit_mode (Splice);
3363 Config->set_edit_mode (Lock);
3366 Config->set_edit_mode (Slide);
3372 Editor::edit_mode_selection_done ()
3374 string s = edit_mode_selector.get_active_text ();
3377 Config->set_edit_mode (string_to_edit_mode (s));
3382 Editor::snap_type_selection_done ()
3384 string choice = snap_type_selector.get_active_text();
3385 SnapType snaptype = SnapToBeat;
3387 if (choice == _("Beats/2")) {
3388 snaptype = SnapToBeatDiv2;
3389 } else if (choice == _("Beats/3")) {
3390 snaptype = SnapToBeatDiv3;
3391 } else if (choice == _("Beats/4")) {
3392 snaptype = SnapToBeatDiv4;
3393 } else if (choice == _("Beats/5")) {
3394 snaptype = SnapToBeatDiv5;
3395 } else if (choice == _("Beats/6")) {
3396 snaptype = SnapToBeatDiv6;
3397 } else if (choice == _("Beats/7")) {
3398 snaptype = SnapToBeatDiv7;
3399 } else if (choice == _("Beats/8")) {
3400 snaptype = SnapToBeatDiv8;
3401 } else if (choice == _("Beats/10")) {
3402 snaptype = SnapToBeatDiv10;
3403 } else if (choice == _("Beats/12")) {
3404 snaptype = SnapToBeatDiv12;
3405 } else if (choice == _("Beats/14")) {
3406 snaptype = SnapToBeatDiv14;
3407 } else if (choice == _("Beats/16")) {
3408 snaptype = SnapToBeatDiv16;
3409 } else if (choice == _("Beats/20")) {
3410 snaptype = SnapToBeatDiv20;
3411 } else if (choice == _("Beats/24")) {
3412 snaptype = SnapToBeatDiv24;
3413 } else if (choice == _("Beats/28")) {
3414 snaptype = SnapToBeatDiv28;
3415 } else if (choice == _("Beats/32")) {
3416 snaptype = SnapToBeatDiv32;
3417 } else if (choice == _("Beats/64")) {
3418 snaptype = SnapToBeatDiv64;
3419 } else if (choice == _("Beats/128")) {
3420 snaptype = SnapToBeatDiv128;
3421 } else if (choice == _("Beats")) {
3422 snaptype = SnapToBeat;
3423 } else if (choice == _("Bars")) {
3424 snaptype = SnapToBar;
3425 } else if (choice == _("Marks")) {
3426 snaptype = SnapToMark;
3427 } else if (choice == _("Region starts")) {
3428 snaptype = SnapToRegionStart;
3429 } else if (choice == _("Region ends")) {
3430 snaptype = SnapToRegionEnd;
3431 } else if (choice == _("Region bounds")) {
3432 snaptype = SnapToRegionBoundary;
3433 } else if (choice == _("Region syncs")) {
3434 snaptype = SnapToRegionSync;
3435 } else if (choice == _("CD Frames")) {
3436 snaptype = SnapToCDFrame;
3437 } else if (choice == _("Timecode Frames")) {
3438 snaptype = SnapToTimecodeFrame;
3439 } else if (choice == _("Timecode Seconds")) {
3440 snaptype = SnapToTimecodeSeconds;
3441 } else if (choice == _("Timecode Minutes")) {
3442 snaptype = SnapToTimecodeMinutes;
3443 } else if (choice == _("Seconds")) {
3444 snaptype = SnapToSeconds;
3445 } else if (choice == _("Minutes")) {
3446 snaptype = SnapToMinutes;
3449 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3451 ract->set_active ();
3456 Editor::snap_mode_selection_done ()
3458 string choice = snap_mode_selector.get_active_text();
3459 SnapMode mode = SnapNormal;
3461 if (choice == _("No Grid")) {
3463 } else if (choice == _("Grid")) {
3465 } else if (choice == _("Magnetic")) {
3466 mode = SnapMagnetic;
3469 RefPtr<RadioAction> ract = snap_mode_action (mode);
3472 ract->set_active (true);
3477 Editor::cycle_edit_point (bool with_marker)
3479 switch (_edit_point) {
3481 set_edit_point_preference (EditAtPlayhead);
3483 case EditAtPlayhead:
3485 set_edit_point_preference (EditAtSelectedMarker);
3487 set_edit_point_preference (EditAtMouse);
3490 case EditAtSelectedMarker:
3491 set_edit_point_preference (EditAtMouse);
3497 Editor::edit_point_selection_done ()
3499 string choice = edit_point_selector.get_active_text();
3500 EditPoint ep = EditAtSelectedMarker;
3502 if (choice == _("Marker")) {
3503 set_edit_point_preference (EditAtSelectedMarker);
3504 } else if (choice == _("Playhead")) {
3505 set_edit_point_preference (EditAtPlayhead);
3507 set_edit_point_preference (EditAtMouse);
3510 RefPtr<RadioAction> ract = edit_point_action (ep);
3513 ract->set_active (true);
3518 Editor::zoom_focus_selection_done ()
3520 string choice = zoom_focus_selector.get_active_text();
3521 ZoomFocus focus_type = ZoomFocusLeft;
3523 if (choice == _("Left")) {
3524 focus_type = ZoomFocusLeft;
3525 } else if (choice == _("Right")) {
3526 focus_type = ZoomFocusRight;
3527 } else if (choice == _("Center")) {
3528 focus_type = ZoomFocusCenter;
3529 } else if (choice == _("Playhead")) {
3530 focus_type = ZoomFocusPlayhead;
3531 } else if (choice == _("Mouse")) {
3532 focus_type = ZoomFocusMouse;
3533 } else if (choice == _("Edit point")) {
3534 focus_type = ZoomFocusEdit;
3537 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3540 ract->set_active ();
3545 Editor::edit_controls_button_release (GdkEventButton* ev)
3547 if (Keyboard::is_context_menu_event (ev)) {
3548 ARDOUR_UI::instance()->add_route (this);
3549 } else if (ev->button == 1) {
3550 selection->clear_tracks ();
3557 Editor::mouse_select_button_release (GdkEventButton* ev)
3559 /* this handles just right-clicks */
3561 if (ev->button != 3) {
3569 Editor::set_zoom_focus (ZoomFocus f)
3571 string str = zoom_focus_strings[(int)f];
3573 if (str != zoom_focus_selector.get_active_text()) {
3574 zoom_focus_selector.set_active_text (str);
3577 if (zoom_focus != f) {
3584 Editor::cycle_zoom_focus ()
3586 switch (zoom_focus) {
3588 set_zoom_focus (ZoomFocusRight);
3590 case ZoomFocusRight:
3591 set_zoom_focus (ZoomFocusCenter);
3593 case ZoomFocusCenter:
3594 set_zoom_focus (ZoomFocusPlayhead);
3596 case ZoomFocusPlayhead:
3597 set_zoom_focus (ZoomFocusMouse);
3599 case ZoomFocusMouse:
3600 set_zoom_focus (ZoomFocusEdit);
3603 set_zoom_focus (ZoomFocusLeft);
3609 Editor::ensure_float (Window& win)
3611 win.set_transient_for (*this);
3615 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3617 /* recover or initialize pane positions. do this here rather than earlier because
3618 we don't want the positions to change the child allocations, which they seem to do.
3624 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3633 XMLNode* geometry = find_named_node (*node, "geometry");
3635 if (which == static_cast<Paned*> (&edit_pane)) {
3637 if (done & Horizontal) {
3641 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3642 _notebook_shrunk = string_is_affirmative (prop->value ());
3645 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3646 /* initial allocation is 90% to canvas, 10% to notebook */
3647 pos = (int) floor (alloc.get_width() * 0.90f);
3648 snprintf (buf, sizeof(buf), "%d", pos);
3650 pos = atoi (prop->value());
3653 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3654 edit_pane.set_position (pos);
3657 done = (Pane) (done | Horizontal);
3659 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3661 if (done & Vertical) {
3665 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3666 /* initial allocation is 90% to canvas, 10% to summary */
3667 pos = (int) floor (alloc.get_height() * 0.90f);
3668 snprintf (buf, sizeof(buf), "%d", pos);
3671 pos = atoi (prop->value());
3674 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3675 editor_summary_pane.set_position (pos);
3678 done = (Pane) (done | Vertical);
3683 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3685 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3686 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3687 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3688 top_hbox.remove (toolbar_frame);
3693 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3695 if (toolbar_frame.get_parent() == 0) {
3696 top_hbox.pack_end (toolbar_frame);
3701 Editor::set_show_measures (bool yn)
3703 if (_show_measures != yn) {
3706 if ((_show_measures = yn) == true) {
3708 tempo_lines->show();
3711 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3712 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3714 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3715 draw_measures (begin, end);
3723 Editor::toggle_follow_playhead ()
3725 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3727 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3728 set_follow_playhead (tact->get_active());
3732 /** @param yn true to follow playhead, otherwise false.
3733 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3736 Editor::set_follow_playhead (bool yn, bool catch_up)
3738 if (_follow_playhead != yn) {
3739 if ((_follow_playhead = yn) == true && catch_up) {
3741 reset_x_origin_to_follow_playhead ();
3748 Editor::toggle_stationary_playhead ()
3750 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3752 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3753 set_stationary_playhead (tact->get_active());
3758 Editor::set_stationary_playhead (bool yn)
3760 if (_stationary_playhead != yn) {
3761 if ((_stationary_playhead = yn) == true) {
3763 // FIXME need a 3.0 equivalent of this 2.X call
3764 // update_current_screen ();
3771 Editor::playlist_selector () const
3773 return *_playlist_selector;
3777 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3781 switch (_snap_type) {
3786 case SnapToBeatDiv128:
3789 case SnapToBeatDiv64:
3792 case SnapToBeatDiv32:
3795 case SnapToBeatDiv28:
3798 case SnapToBeatDiv24:
3801 case SnapToBeatDiv20:
3804 case SnapToBeatDiv16:
3807 case SnapToBeatDiv14:
3810 case SnapToBeatDiv12:
3813 case SnapToBeatDiv10:
3816 case SnapToBeatDiv8:
3819 case SnapToBeatDiv7:
3822 case SnapToBeatDiv6:
3825 case SnapToBeatDiv5:
3828 case SnapToBeatDiv4:
3831 case SnapToBeatDiv3:
3834 case SnapToBeatDiv2:
3840 return _session->tempo_map().meter_at (position).divisions_per_bar();
3845 case SnapToTimecodeFrame:
3846 case SnapToTimecodeSeconds:
3847 case SnapToTimecodeMinutes:
3850 case SnapToRegionStart:
3851 case SnapToRegionEnd:
3852 case SnapToRegionSync:
3853 case SnapToRegionBoundary:
3863 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3867 ret = nudge_clock->current_duration (pos);
3868 next = ret + 1; /* XXXX fix me */
3874 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3876 ArdourDialog dialog (_("Playlist Deletion"));
3877 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3878 "If it is kept, its audio files will not be cleaned.\n"
3879 "If it is deleted, audio files used by it alone will be cleaned."),
3882 dialog.set_position (WIN_POS_CENTER);
3883 dialog.get_vbox()->pack_start (label);
3887 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3888 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3889 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3891 switch (dialog.run ()) {
3892 case RESPONSE_ACCEPT:
3893 /* delete the playlist */
3897 case RESPONSE_REJECT:
3898 /* keep the playlist */
3910 Editor::audio_region_selection_covers (framepos_t where)
3912 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3913 if ((*a)->region()->covers (where)) {
3922 Editor::prepare_for_cleanup ()
3924 cut_buffer->clear_regions ();
3925 cut_buffer->clear_playlists ();
3927 selection->clear_regions ();
3928 selection->clear_playlists ();
3930 _regions->suspend_redisplay ();
3934 Editor::finish_cleanup ()
3936 _regions->resume_redisplay ();
3940 Editor::transport_loop_location()
3943 return _session->locations()->auto_loop_location();
3950 Editor::transport_punch_location()
3953 return _session->locations()->auto_punch_location();
3960 Editor::control_layout_scroll (GdkEventScroll* ev)
3962 if (Keyboard::some_magic_widget_has_focus()) {
3966 switch (ev->direction) {
3968 scroll_tracks_up_line ();
3972 case GDK_SCROLL_DOWN:
3973 scroll_tracks_down_line ();
3977 /* no left/right handling yet */
3985 Editor::session_state_saved (string)
3988 _snapshots->redisplay ();
3992 Editor::update_tearoff_visibility()
3994 bool visible = Config->get_keep_tearoffs();
3995 _mouse_mode_tearoff->set_visible (visible);
3996 _tools_tearoff->set_visible (visible);
3997 _zoom_tearoff->set_visible (visible);
4001 Editor::maximise_editing_space ()
4013 Editor::restore_editing_space ()
4025 * Make new playlists for a given track and also any others that belong
4026 * to the same active route group with the `select' property.
4031 Editor::new_playlists (TimeAxisView* v)
4033 begin_reversible_command (_("new playlists"));
4034 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4035 _session->playlists->get (playlists);
4036 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4037 commit_reversible_command ();
4041 * Use a copy of the current playlist for a given track and also any others that belong
4042 * to the same active route group with the `select' property.
4047 Editor::copy_playlists (TimeAxisView* v)
4049 begin_reversible_command (_("copy playlists"));
4050 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4051 _session->playlists->get (playlists);
4052 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4053 commit_reversible_command ();
4056 /** Clear the current playlist for a given track and also any others that belong
4057 * to the same active route group with the `select' property.
4062 Editor::clear_playlists (TimeAxisView* v)
4064 begin_reversible_command (_("clear playlists"));
4065 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4066 _session->playlists->get (playlists);
4067 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4068 commit_reversible_command ();
4072 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4074 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4078 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4080 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4084 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4086 atv.clear_playlist ();
4090 Editor::on_key_press_event (GdkEventKey* ev)
4092 return key_press_focus_accelerator_handler (*this, ev);
4096 Editor::on_key_release_event (GdkEventKey* ev)
4098 return Gtk::Window::on_key_release_event (ev);
4099 // return key_press_focus_accelerator_handler (*this, ev);
4102 /** Queue up a change to the viewport x origin.
4103 * @param frame New x origin.
4106 Editor::reset_x_origin (framepos_t frame)
4108 pending_visual_change.add (VisualChange::TimeOrigin);
4109 pending_visual_change.time_origin = frame;
4110 ensure_visual_change_idle_handler ();
4114 Editor::reset_y_origin (double y)
4116 pending_visual_change.add (VisualChange::YOrigin);
4117 pending_visual_change.y_origin = y;
4118 ensure_visual_change_idle_handler ();
4122 Editor::reset_zoom (framecnt_t spp)
4124 clamp_samples_per_pixel (spp);
4126 if (spp == samples_per_pixel) {
4130 pending_visual_change.add (VisualChange::ZoomLevel);
4131 pending_visual_change.samples_per_pixel = spp;
4132 ensure_visual_change_idle_handler ();
4136 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4138 reset_x_origin (frame);
4141 if (!no_save_visual) {
4142 undo_visual_stack.push_back (current_visual_state(false));
4146 Editor::VisualState::VisualState (bool with_tracks)
4147 : gui_state (with_tracks ? new GUIObjectState : 0)
4151 Editor::VisualState::~VisualState ()
4156 Editor::VisualState*
4157 Editor::current_visual_state (bool with_tracks)
4159 VisualState* vs = new VisualState (with_tracks);
4160 vs->y_position = vertical_adjustment.get_value();
4161 vs->samples_per_pixel = samples_per_pixel;
4162 vs->leftmost_frame = leftmost_frame;
4163 vs->zoom_focus = zoom_focus;
4166 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4173 Editor::undo_visual_state ()
4175 if (undo_visual_stack.empty()) {
4179 VisualState* vs = undo_visual_stack.back();
4180 undo_visual_stack.pop_back();
4183 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4185 use_visual_state (*vs);
4189 Editor::redo_visual_state ()
4191 if (redo_visual_stack.empty()) {
4195 VisualState* vs = redo_visual_stack.back();
4196 redo_visual_stack.pop_back();
4198 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4200 use_visual_state (*vs);
4204 Editor::swap_visual_state ()
4206 if (undo_visual_stack.empty()) {
4207 redo_visual_state ();
4209 undo_visual_state ();
4214 Editor::use_visual_state (VisualState& vs)
4216 PBD::Unwinder<bool> nsv (no_save_visual, true);
4218 _routes->suspend_redisplay ();
4220 vertical_adjustment.set_value (vs.y_position);
4222 set_zoom_focus (vs.zoom_focus);
4223 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4226 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4228 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4229 (*i)->reset_visual_state ();
4233 _routes->update_visibility ();
4234 _routes->resume_redisplay ();
4237 /** This is the core function that controls the zoom level of the canvas. It is called
4238 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4239 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4242 Editor::set_samples_per_pixel (framecnt_t spp)
4244 clamp_samples_per_pixel (spp);
4245 samples_per_pixel = spp;
4248 tempo_lines->tempo_map_changed();
4251 /* convert fpu to frame count */
4253 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4255 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4256 zoom_range_clock->set (frames);
4259 bool const showing_time_selection = selection->time.length() > 0;
4261 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4262 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4263 (*i)->reshow_selection (selection->time);
4267 ZoomChanged (); /* EMIT_SIGNAL */
4269 //reset_scrolling_region ();
4271 if (playhead_cursor) {
4272 playhead_cursor->set_position (playhead_cursor->current_frame ());
4275 refresh_location_display();
4276 _summary->set_overlays_dirty ();
4278 update_marker_labels ();
4284 Editor::queue_visual_videotimeline_update ()
4287 * pending_visual_change.add (VisualChange::VideoTimeline);
4288 * or maybe even more specific: which videotimeline-image
4289 * currently it calls update_video_timeline() to update
4290 * _all outdated_ images on the video-timeline.
4291 * see 'exposeimg()' in video_image_frame.cc
4293 ensure_visual_change_idle_handler ();
4297 Editor::ensure_visual_change_idle_handler ()
4299 if (pending_visual_change.idle_handler_id < 0) {
4300 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4301 pending_visual_change.being_handled = false;
4306 Editor::_idle_visual_changer (void* arg)
4308 return static_cast<Editor*>(arg)->idle_visual_changer ();
4312 Editor::idle_visual_changer ()
4314 /* set_horizontal_position() below (and maybe other calls) call
4315 gtk_main_iteration(), so it's possible that a signal will be handled
4316 half-way through this method. If this signal wants an
4317 idle_visual_changer we must schedule another one after this one, so
4318 mark the idle_handler_id as -1 here to allow that. Also make a note
4319 that we are doing the visual change, so that changes in response to
4320 super-rapid-screen-update can be dropped if we are still processing
4324 pending_visual_change.idle_handler_id = -1;
4325 pending_visual_change.being_handled = true;
4327 VisualChange::Type p = pending_visual_change.pending;
4328 pending_visual_change.pending = (VisualChange::Type) 0;
4330 double const last_time_origin = horizontal_position ();
4332 if (p & VisualChange::ZoomLevel) {
4333 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4335 compute_fixed_ruler_scale ();
4337 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4338 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4340 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4341 current_bbt_points_begin, current_bbt_points_end);
4342 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4343 current_bbt_points_begin, current_bbt_points_end);
4344 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4347 if (p & VisualChange::ZoomLevel) {
4348 update_video_timeline();
4351 if (p & VisualChange::TimeOrigin) {
4352 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4355 if (p & VisualChange::YOrigin) {
4356 vertical_adjustment.set_value (pending_visual_change.y_origin);
4359 if (last_time_origin == horizontal_position ()) {
4360 /* changed signal not emitted */
4361 update_fixed_rulers ();
4362 redisplay_tempo (true);
4365 if (!(p & VisualChange::ZoomLevel)) {
4366 update_video_timeline();
4369 _summary->set_overlays_dirty ();
4371 pending_visual_change.being_handled = false;
4372 return 0; /* this is always a one-shot call */
4375 struct EditorOrderTimeAxisSorter {
4376 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4377 return a->order () < b->order ();
4382 Editor::sort_track_selection (TrackViewList& sel)
4384 EditorOrderTimeAxisSorter cmp;
4389 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4392 framepos_t where = 0;
4393 EditPoint ep = _edit_point;
4395 if (from_context_menu && (ep == EditAtMouse)) {
4396 return window_event_frame (&context_click_event, 0, 0);
4399 if (entered_marker) {
4400 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4401 return entered_marker->position();
4404 if (ignore_playhead && ep == EditAtPlayhead) {
4405 ep = EditAtSelectedMarker;
4409 case EditAtPlayhead:
4410 where = _session->audible_frame();
4411 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4414 case EditAtSelectedMarker:
4415 if (!selection->markers.empty()) {
4417 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4420 where = loc->start();
4424 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4432 if (!mouse_frame (where, ignored)) {
4433 /* XXX not right but what can we do ? */
4437 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4445 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4447 if (!_session) return;
4449 begin_reversible_command (cmd);
4453 if ((tll = transport_loop_location()) == 0) {
4454 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4455 XMLNode &before = _session->locations()->get_state();
4456 _session->locations()->add (loc, true);
4457 _session->set_auto_loop_location (loc);
4458 XMLNode &after = _session->locations()->get_state();
4459 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4461 XMLNode &before = tll->get_state();
4462 tll->set_hidden (false, this);
4463 tll->set (start, end);
4464 XMLNode &after = tll->get_state();
4465 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4468 commit_reversible_command ();
4472 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4474 if (!_session) return;
4476 begin_reversible_command (cmd);
4480 if ((tpl = transport_punch_location()) == 0) {
4481 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4482 XMLNode &before = _session->locations()->get_state();
4483 _session->locations()->add (loc, true);
4484 _session->set_auto_loop_location (loc);
4485 XMLNode &after = _session->locations()->get_state();
4486 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4489 XMLNode &before = tpl->get_state();
4490 tpl->set_hidden (false, this);
4491 tpl->set (start, end);
4492 XMLNode &after = tpl->get_state();
4493 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4496 commit_reversible_command ();
4499 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4500 * @param rs List to which found regions are added.
4501 * @param where Time to look at.
4502 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4505 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4507 const TrackViewList* tracks;
4510 tracks = &track_views;
4515 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4517 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4520 boost::shared_ptr<Track> tr;
4521 boost::shared_ptr<Playlist> pl;
4523 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4525 boost::shared_ptr<RegionList> regions = pl->regions_at (
4526 (framepos_t) floor ( (double) where * tr->speed()));
4528 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4529 RegionView* rv = rtv->view()->find_view (*i);
4540 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4542 const TrackViewList* tracks;
4545 tracks = &track_views;
4550 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4551 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4553 boost::shared_ptr<Track> tr;
4554 boost::shared_ptr<Playlist> pl;
4556 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4558 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4559 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4561 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4563 RegionView* rv = rtv->view()->find_view (*i);
4574 /** Get regions using the following method:
4576 * Make a region list using the selected regions, unless
4577 * the edit point is `mouse' and the mouse is over an unselected
4578 * region. In this case, use just that region.
4580 * If the edit point is not 'mouse', and there are no regions selected,
4581 * search the list of selected tracks and return regions that are under
4582 * the edit point on these tracks. If there are no selected tracks and
4583 * 'No Selection = All Tracks' is active, search all tracks,
4585 * The rationale here is that the mouse edit point is special in that
4586 * its position describes both a time and a track; the other edit
4587 * modes only describe a time. Hence if the edit point is `mouse' we
4588 * ignore selected tracks, as we assume the user means something by
4589 * pointing at a particular track. Also in this case we take note of
4590 * the region directly under the edit point, as there is always just one
4591 * (rather than possibly several with non-mouse edit points).
4595 Editor::get_regions_from_selection_and_edit_point ()
4597 RegionSelection regions;
4599 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4600 regions.add (entered_regionview);
4602 regions = selection->regions;
4606 if (regions.empty() && _edit_point != EditAtMouse) {
4607 TrackViewList tracks = selection->tracks;
4609 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4610 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4611 * is enabled, so consider all tracks
4613 tracks = track_views;
4616 if (!tracks.empty()) {
4617 /* no region selected or entered, but some selected tracks:
4618 * act on all regions on the selected tracks at the edit point
4620 framepos_t const where = get_preferred_edit_position ();
4621 get_regions_at(regions, where, tracks);
4627 /** Start with regions that are selected, or the entered regionview if none are selected.
4628 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4629 * of the regions that we started with.
4633 Editor::get_regions_from_selection_and_entered ()
4635 RegionSelection regions = selection->regions;
4637 if (regions.empty() && entered_regionview) {
4638 regions.add (entered_regionview);
4645 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4647 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4649 RouteTimeAxisView* tatv;
4651 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4653 boost::shared_ptr<Playlist> pl;
4654 vector<boost::shared_ptr<Region> > results;
4656 boost::shared_ptr<Track> tr;
4658 if ((tr = tatv->track()) == 0) {
4663 if ((pl = (tr->playlist())) != 0) {
4664 if (src_comparison) {
4665 pl->get_source_equivalent_regions (region, results);
4667 pl->get_region_list_equivalent_regions (region, results);
4671 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4672 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4673 regions.push_back (marv);
4682 Editor::show_rhythm_ferret ()
4684 if (rhythm_ferret == 0) {
4685 rhythm_ferret = new RhythmFerret(*this);
4688 rhythm_ferret->set_session (_session);
4689 rhythm_ferret->show ();
4690 rhythm_ferret->present ();
4694 Editor::first_idle ()
4696 MessageDialog* dialog = 0;
4698 if (track_views.size() > 1) {
4699 dialog = new MessageDialog (
4701 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4705 ARDOUR_UI::instance()->flush_pending ();
4708 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4712 // first idle adds route children (automation tracks), so we need to redisplay here
4713 _routes->redisplay ();
4720 Editor::_idle_resize (gpointer arg)
4722 return ((Editor*)arg)->idle_resize ();
4726 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4728 if (resize_idle_id < 0) {
4729 resize_idle_id = g_idle_add (_idle_resize, this);
4730 _pending_resize_amount = 0;
4733 /* make a note of the smallest resulting height, so that we can clamp the
4734 lower limit at TimeAxisView::hSmall */
4736 int32_t min_resulting = INT32_MAX;
4738 _pending_resize_amount += h;
4739 _pending_resize_view = view;
4741 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4743 if (selection->tracks.contains (_pending_resize_view)) {
4744 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4745 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4749 if (min_resulting < 0) {
4754 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4755 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4759 /** Handle pending resizing of tracks */
4761 Editor::idle_resize ()
4763 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4765 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4766 selection->tracks.contains (_pending_resize_view)) {
4768 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4769 if (*i != _pending_resize_view) {
4770 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4775 _pending_resize_amount = 0;
4776 _group_tabs->set_dirty ();
4777 resize_idle_id = -1;
4785 ENSURE_GUI_THREAD (*this, &Editor::located);
4788 playhead_cursor->set_position (_session->audible_frame ());
4789 if (_follow_playhead && !_pending_initial_locate) {
4790 reset_x_origin_to_follow_playhead ();
4794 _pending_locate_request = false;
4795 _pending_initial_locate = false;
4799 Editor::region_view_added (RegionView *)
4801 _summary->set_dirty ();
4805 Editor::region_view_removed ()
4807 _summary->set_dirty ();
4811 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4813 TrackViewList::const_iterator j = track_views.begin ();
4814 while (j != track_views.end()) {
4815 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4816 if (rtv && rtv->route() == r) {
4827 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4831 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4832 TimeAxisView* tv = axis_view_from_route (*i);
4842 Editor::add_routes (RouteList& routes)
4844 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4846 RouteTimeAxisView *rtv;
4847 list<RouteTimeAxisView*> new_views;
4849 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4850 boost::shared_ptr<Route> route = (*x);
4852 if (route->is_auditioner() || route->is_monitor()) {
4856 DataType dt = route->input()->default_type();
4858 if (dt == ARDOUR::DataType::AUDIO) {
4859 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4860 rtv->set_route (route);
4861 } else if (dt == ARDOUR::DataType::MIDI) {
4862 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4863 rtv->set_route (route);
4865 throw unknown_type();
4868 new_views.push_back (rtv);
4869 track_views.push_back (rtv);
4871 rtv->effective_gain_display ();
4873 if (internal_editing()) {
4874 rtv->enter_internal_edit_mode ();
4876 rtv->leave_internal_edit_mode ();
4879 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4880 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4883 _routes->routes_added (new_views);
4884 _summary->routes_added (new_views);
4886 if (show_editor_mixer_when_tracks_arrive) {
4887 show_editor_mixer (true);
4890 editor_list_button.set_sensitive (true);
4894 Editor::timeaxisview_deleted (TimeAxisView *tv)
4896 if (_session && _session->deletion_in_progress()) {
4897 /* the situation is under control */
4901 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4903 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4905 _routes->route_removed (tv);
4907 if (tv == entered_track) {
4911 TimeAxisView::Children c = tv->get_child_list ();
4912 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4913 if (entered_track == i->get()) {
4918 /* remove it from the list of track views */
4920 TrackViewList::iterator i;
4922 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4923 i = track_views.erase (i);
4926 /* update whatever the current mixer strip is displaying, if revelant */
4928 boost::shared_ptr<Route> route;
4931 route = rtav->route ();
4934 if (current_mixer_strip && current_mixer_strip->route() == route) {
4936 TimeAxisView* next_tv;
4938 if (track_views.empty()) {
4940 } else if (i == track_views.end()) {
4941 next_tv = track_views.front();
4948 set_selected_mixer_strip (*next_tv);
4950 /* make the editor mixer strip go away setting the
4951 * button to inactive (which also unticks the menu option)
4954 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4960 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4962 if (apply_to_selection) {
4963 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4965 TrackSelection::iterator j = i;
4968 hide_track_in_display (*i, false);
4973 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4975 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4976 // this will hide the mixer strip
4977 set_selected_mixer_strip (*tv);
4980 _routes->hide_track_in_display (*tv);
4985 Editor::sync_track_view_list_and_routes ()
4987 track_views = TrackViewList (_routes->views ());
4989 _summary->set_dirty ();
4990 _group_tabs->set_dirty ();
4992 return false; // do not call again (until needed)
4996 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4998 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5003 /** Find a RouteTimeAxisView by the ID of its route */
5005 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5007 RouteTimeAxisView* v;
5009 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5010 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5011 if(v->route()->id() == id) {
5021 Editor::fit_route_group (RouteGroup *g)
5023 TrackViewList ts = axis_views_from_routes (g->route_list ());
5028 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5030 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5033 _session->cancel_audition ();
5037 if (_session->is_auditioning()) {
5038 _session->cancel_audition ();
5039 if (r == last_audition_region) {
5044 _session->audition_region (r);
5045 last_audition_region = r;
5050 Editor::hide_a_region (boost::shared_ptr<Region> r)
5052 r->set_hidden (true);
5056 Editor::show_a_region (boost::shared_ptr<Region> r)
5058 r->set_hidden (false);
5062 Editor::audition_region_from_region_list ()
5064 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5068 Editor::hide_region_from_region_list ()
5070 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5074 Editor::show_region_in_region_list ()
5076 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5080 Editor::step_edit_status_change (bool yn)
5083 start_step_editing ();
5085 stop_step_editing ();
5090 Editor::start_step_editing ()
5092 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5096 Editor::stop_step_editing ()
5098 step_edit_connection.disconnect ();
5102 Editor::check_step_edit ()
5104 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5105 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5107 mtv->check_step_edit ();
5111 return true; // do it again, till we stop
5115 Editor::scroll_press (Direction dir)
5117 ++_scroll_callbacks;
5119 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5120 /* delay the first auto-repeat */
5126 scroll_backward (1);
5134 scroll_tracks_up_line ();
5138 scroll_tracks_down_line ();
5142 /* do hacky auto-repeat */
5143 if (!_scroll_connection.connected ()) {
5145 _scroll_connection = Glib::signal_timeout().connect (
5146 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5149 _scroll_callbacks = 0;
5156 Editor::scroll_release ()
5158 _scroll_connection.disconnect ();
5161 /** Queue a change for the Editor viewport x origin to follow the playhead */
5163 Editor::reset_x_origin_to_follow_playhead ()
5165 framepos_t const frame = playhead_cursor->current_frame ();
5167 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5169 if (_session->transport_speed() < 0) {
5171 if (frame > (current_page_samples() / 2)) {
5172 center_screen (frame-(current_page_samples()/2));
5174 center_screen (current_page_samples()/2);
5181 if (frame < leftmost_frame) {
5183 if (_session->transport_rolling()) {
5184 /* rolling; end up with the playhead at the right of the page */
5185 l = frame - current_page_samples ();
5187 /* not rolling: end up with the playhead 1/4 of the way along the page */
5188 l = frame - current_page_samples() / 4;
5192 if (_session->transport_rolling()) {
5193 /* rolling: end up with the playhead on the left of the page */
5196 /* not rolling: end up with the playhead 3/4 of the way along the page */
5197 l = frame - 3 * current_page_samples() / 4;
5205 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5211 Editor::super_rapid_screen_update ()
5213 if (!_session || !_session->engine().running()) {
5217 /* METERING / MIXER STRIPS */
5219 /* update track meters, if required */
5220 if (is_mapped() && meters_running) {
5221 RouteTimeAxisView* rtv;
5222 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5223 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5224 rtv->fast_update ();
5229 /* and any current mixer strip */
5230 if (current_mixer_strip) {
5231 current_mixer_strip->fast_update ();
5234 /* PLAYHEAD AND VIEWPORT */
5236 framepos_t const frame = _session->audible_frame();
5238 /* There are a few reasons why we might not update the playhead / viewport stuff:
5240 * 1. we don't update things when there's a pending locate request, otherwise
5241 * when the editor requests a locate there is a chance that this method
5242 * will move the playhead before the locate request is processed, causing
5244 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5245 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5248 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5250 last_update_frame = frame;
5252 if (!_dragging_playhead) {
5253 playhead_cursor->set_position (frame);
5256 if (!_stationary_playhead) {
5258 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5259 /* We only do this if we aren't already
5260 handling a visual change (ie if
5261 pending_visual_change.being_handled is
5262 false) so that these requests don't stack
5263 up there are too many of them to handle in
5266 reset_x_origin_to_follow_playhead ();
5271 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5275 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5276 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5277 if (target <= 0.0) {
5280 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5281 target = (target * 0.15) + (current * 0.85);
5287 set_horizontal_position (current);
5296 Editor::session_going_away ()
5298 _have_idled = false;
5300 _session_connections.drop_connections ();
5302 super_rapid_screen_update_connection.disconnect ();
5304 selection->clear ();
5305 cut_buffer->clear ();
5307 clicked_regionview = 0;
5308 clicked_axisview = 0;
5309 clicked_routeview = 0;
5310 entered_regionview = 0;
5312 last_update_frame = 0;
5315 playhead_cursor->hide ();
5317 /* rip everything out of the list displays */
5321 _route_groups->clear ();
5323 /* do this first so that deleting a track doesn't reset cms to null
5324 and thus cause a leak.
5327 if (current_mixer_strip) {
5328 if (current_mixer_strip->get_parent() != 0) {
5329 global_hpacker.remove (*current_mixer_strip);
5331 delete current_mixer_strip;
5332 current_mixer_strip = 0;
5335 /* delete all trackviews */
5337 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5340 track_views.clear ();
5342 zoom_range_clock->set_session (0);
5343 nudge_clock->set_session (0);
5345 editor_list_button.set_active(false);
5346 editor_list_button.set_sensitive(false);
5348 /* clear tempo/meter rulers */
5349 remove_metric_marks ();
5351 clear_marker_display ();
5353 stop_step_editing ();
5355 /* get rid of any existing editor mixer strip */
5357 WindowTitle title(Glib::get_application_name());
5358 title += _("Editor");
5360 set_title (title.get_string());
5362 SessionHandlePtr::session_going_away ();
5367 Editor::show_editor_list (bool yn)
5370 _the_notebook.show ();
5372 _the_notebook.hide ();
5377 Editor::change_region_layering_order (bool from_context_menu)
5379 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5381 if (!clicked_routeview) {
5382 if (layering_order_editor) {
5383 layering_order_editor->hide ();
5388 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5394 boost::shared_ptr<Playlist> pl = track->playlist();
5400 if (layering_order_editor == 0) {
5401 layering_order_editor = new RegionLayeringOrderEditor (*this);
5404 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5405 layering_order_editor->maybe_present ();
5409 Editor::update_region_layering_order_editor ()
5411 if (layering_order_editor && layering_order_editor->is_visible ()) {
5412 change_region_layering_order (true);
5417 Editor::setup_fade_images ()
5419 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5420 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5421 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5422 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5423 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5425 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5426 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5427 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5428 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5429 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5431 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5432 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5433 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5434 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5435 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5437 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5438 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5439 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5440 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5441 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5445 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5447 Editor::action_menu_item (std::string const & name)
5449 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5452 return *manage (a->create_menu_item ());
5456 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5458 EventBox* b = manage (new EventBox);
5459 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5460 Label* l = manage (new Label (name));
5464 _the_notebook.append_page (widget, *b);
5468 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5470 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5471 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5474 if (ev->type == GDK_2BUTTON_PRESS) {
5476 /* double-click on a notebook tab shrinks or expands the notebook */
5478 if (_notebook_shrunk) {
5479 if (pre_notebook_shrink_pane_width) {
5480 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5482 _notebook_shrunk = false;
5484 pre_notebook_shrink_pane_width = edit_pane.get_position();
5486 /* this expands the LHS of the edit pane to cover the notebook
5487 PAGE but leaves the tabs visible.
5489 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5490 _notebook_shrunk = true;
5498 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5500 using namespace Menu_Helpers;
5502 MenuList& items = _control_point_context_menu.items ();
5505 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5506 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5507 if (!can_remove_control_point (item)) {
5508 items.back().set_sensitive (false);
5511 _control_point_context_menu.popup (event->button.button, event->button.time);
5515 Editor::shift_key_released ()
5517 _stepping_axis_view = 0;