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 <glibmm/uriutils.h>
51 #include <gtkmm/image.h>
52 #include <gdkmm/color.h>
53 #include <gdkmm/bitmap.h>
55 #include "gtkmm2ext/bindings.h"
56 #include "gtkmm2ext/grouped_buttons.h"
57 #include "gtkmm2ext/gtk_ui.h"
58 #include "gtkmm2ext/tearoff.h"
59 #include "gtkmm2ext/utils.h"
60 #include "gtkmm2ext/window_title.h"
61 #include "gtkmm2ext/choice.h"
62 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
64 #include "ardour/audio_track.h"
65 #include "ardour/audioengine.h"
66 #include "ardour/audioregion.h"
67 #include "ardour/location.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_playlists.h"
71 #include "ardour/tempo.h"
72 #include "ardour/utils.h"
74 #include "canvas/debug.h"
75 #include "canvas/text.h"
77 #include "control_protocol/control_protocol.h"
81 #include "analysis_window.h"
82 #include "audio_clock.h"
83 #include "audio_region_view.h"
84 #include "audio_streamview.h"
85 #include "audio_time_axis.h"
86 #include "automation_time_axis.h"
87 #include "bundle_manager.h"
88 #include "crossfade_edit.h"
92 #include "editor_cursors.h"
93 #include "editor_drag.h"
94 #include "editor_group_tabs.h"
95 #include "editor_locations.h"
96 #include "editor_regions.h"
97 #include "editor_route_groups.h"
98 #include "editor_routes.h"
99 #include "editor_snapshots.h"
100 #include "editor_summary.h"
101 #include "global_port_matrix.h"
102 #include "gui_object.h"
103 #include "gui_thread.h"
104 #include "keyboard.h"
106 #include "midi_time_axis.h"
107 #include "mixer_strip.h"
108 #include "mixer_ui.h"
109 #include "mouse_cursors.h"
110 #include "playlist_selector.h"
111 #include "public_editor.h"
112 #include "region_layering_order_editor.h"
113 #include "rgb_macros.h"
114 #include "rhythm_ferret.h"
115 #include "selection.h"
117 #include "tempo_lines.h"
118 #include "time_axis_view.h"
124 using namespace ARDOUR;
127 using namespace Glib;
128 using namespace Gtkmm2ext;
129 using namespace Editing;
131 using PBD::internationalize;
133 using Gtkmm2ext::Keyboard;
135 const double Editor::timebar_height = 15.0;
137 static const gchar *_snap_type_strings[] = {
139 N_("Timecode Frames"),
140 N_("Timecode Seconds"),
141 N_("Timecode Minutes"),
171 static const gchar *_snap_mode_strings[] = {
178 static const gchar *_edit_point_strings[] = {
185 static const gchar *_zoom_focus_strings[] = {
195 #ifdef USE_RUBBERBAND
196 static const gchar *_rb_opt_strings[] = {
199 N_("Balanced multitimbral mixture"),
200 N_("Unpitched percussion with stable notes"),
201 N_("Crisp monophonic instrumental"),
202 N_("Unpitched solo percussion"),
203 N_("Resample without preserving pitch"),
209 pane_size_watcher (Paned* pane)
211 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
215 Quartz: impossible to access
217 so stop that by preventing it from ever getting too narrow. 35
218 pixels is basically a rough guess at the tab width.
223 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
225 gint pos = pane->get_position ();
227 if (pos > max_width_of_lhs) {
228 pane->set_position (max_width_of_lhs);
233 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
235 /* time display buttons */
236 , minsec_label (_("Mins:Secs"))
237 , bbt_label (_("Bars:Beats"))
238 , timecode_label (_("Timecode"))
239 , samples_label (_("Samples"))
240 , tempo_label (_("Tempo"))
241 , meter_label (_("Meter"))
242 , mark_label (_("Location Markers"))
243 , range_mark_label (_("Range Markers"))
244 , transport_mark_label (_("Loop/Punch Ranges"))
245 , cd_mark_label (_("CD Markers"))
246 , videotl_label (_("Video Timeline"))
247 , edit_packer (4, 4, true)
249 /* the values here don't matter: layout widgets
250 reset them as needed.
253 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
254 , horizontal_adjustment (0.0, 0.0, 1e16)
255 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
257 , controls_layout (unused_adjustment, vertical_adjustment)
259 /* tool bar related */
261 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
263 , toolbar_selection_clock_table (2,3)
265 , automation_mode_button (_("mode"))
267 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
272 , meters_running(false)
273 , _pending_locate_request (false)
274 , _pending_initial_locate (false)
275 , _last_cut_copy_source_track (0)
277 , _region_selection_change_updates_region_list (true)
278 , _following_mixer_selection (false)
279 , _control_point_toggled_on_press (false)
280 , _stepping_axis_view (0)
284 /* we are a singleton */
286 PublicEditor::_instance = this;
290 selection = new Selection (this);
291 cut_buffer = new Selection (this);
293 clicked_regionview = 0;
294 clicked_axisview = 0;
295 clicked_routeview = 0;
296 clicked_control_point = 0;
297 last_update_frame = 0;
298 pre_press_cursor = 0;
299 _drags = new DragManager (this);
300 current_mixer_strip = 0;
303 snap_type_strings = I18N (_snap_type_strings);
304 snap_mode_strings = I18N (_snap_mode_strings);
305 zoom_focus_strings = I18N (_zoom_focus_strings);
306 edit_point_strings = I18N (_edit_point_strings);
307 #ifdef USE_RUBBERBAND
308 rb_opt_strings = I18N (_rb_opt_strings);
312 snap_threshold = 5.0;
313 bbt_beat_subdivision = 4;
314 _visible_canvas_width = 0;
315 _visible_canvas_height = 0;
316 last_autoscroll_x = 0;
317 last_autoscroll_y = 0;
318 autoscroll_active = false;
319 autoscroll_timeout_tag = -1;
324 current_interthread_info = 0;
325 _show_measures = true;
327 show_gain_after_trim = false;
329 have_pending_keyboard_selection = false;
330 _follow_playhead = true;
331 _stationary_playhead = false;
332 editor_ruler_menu = 0;
333 no_ruler_shown_update = false;
335 range_marker_menu = 0;
336 marker_menu_item = 0;
337 tempo_or_meter_marker_menu = 0;
338 transport_marker_menu = 0;
339 new_transport_marker_menu = 0;
340 editor_mixer_strip_width = Wide;
341 show_editor_mixer_when_tracks_arrive = false;
342 region_edit_menu_split_multichannel_item = 0;
343 region_edit_menu_split_item = 0;
346 current_stepping_trackview = 0;
348 entered_regionview = 0;
350 clear_entered_track = false;
353 button_release_can_deselect = true;
354 _dragging_playhead = false;
355 _dragging_edit_point = false;
356 select_new_marker = false;
358 layering_order_editor = 0;
359 no_save_visual = false;
361 within_track_canvas = false;
363 scrubbing_direction = 0;
367 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
368 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
369 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
370 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
371 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
373 zoom_focus = ZoomFocusLeft;
374 _edit_point = EditAtMouse;
375 _internal_editing = false;
376 current_canvas_cursor = 0;
378 samples_per_pixel = 2048; /* too early to use reset_zoom () */
380 _scroll_callbacks = 0;
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 set_zoom_focus (zoom_focus);
640 _snap_type = SnapToBeat;
641 set_snap_to (_snap_type);
642 _snap_mode = SnapOff;
643 set_snap_mode (_snap_mode);
644 set_mouse_mode (MouseObject, true);
645 pre_internal_mouse_mode = MouseObject;
646 pre_internal_snap_type = _snap_type;
647 pre_internal_snap_mode = _snap_mode;
648 internal_snap_type = _snap_type;
649 internal_snap_mode = _snap_mode;
650 set_edit_point_preference (EditAtMouse, true);
652 _playlist_selector = new PlaylistSelector();
653 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
655 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
659 nudge_forward_button.set_name ("zoom button");
660 nudge_forward_button.add_elements (ArdourButton::FlatFace);
661 nudge_forward_button.set_image(::get_icon("nudge_right"));
663 nudge_backward_button.set_name ("zoom button");
664 nudge_backward_button.add_elements (ArdourButton::FlatFace);
665 nudge_backward_button.set_image(::get_icon("nudge_left"));
667 fade_context_menu.set_name ("ArdourContextMenu");
669 /* icons, titles, WM stuff */
671 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
672 Glib::RefPtr<Gdk::Pixbuf> icon;
674 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
681 window_icons.push_back (icon);
683 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
684 window_icons.push_back (icon);
686 if (!window_icons.empty()) {
687 // set_icon_list (window_icons);
688 set_default_icon_list (window_icons);
691 WindowTitle title(Glib::get_application_name());
692 title += _("Editor");
693 set_title (title.get_string());
694 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
697 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
699 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
700 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
702 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
704 /* allow external control surfaces/protocols to do various things */
706 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
707 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
708 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
709 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
710 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
711 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
712 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
713 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
714 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
715 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
716 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
717 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
718 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
719 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
721 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
722 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
723 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
724 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
725 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
727 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
729 /* problematic: has to return a value and thus cannot be x-thread */
731 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
733 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
735 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
737 _ignore_region_action = false;
738 _last_region_menu_was_main = false;
739 _popup_region_menu_item = 0;
741 _show_marker_lines = false;
742 _over_region_trim_target = false;
744 /* Button bindings */
746 button_bindings = new Bindings;
748 XMLNode* node = button_settings();
750 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
751 button_bindings->load (**i);
758 setup_fade_images ();
763 delete button_bindings;
765 delete _route_groups;
766 delete _time_bars_canvas_viewport;
767 delete _track_canvas_viewport;
772 Editor::button_settings () const
774 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
775 XMLNode* node = find_named_node (*settings, X_("Buttons"));
778 node = new XMLNode (X_("Buttons"));
785 Editor::add_toplevel_controls (Container& cont)
787 vpacker.pack_start (cont, false, false);
792 Editor::get_smart_mode () const
794 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
798 Editor::catch_vanishing_regionview (RegionView *rv)
800 /* note: the selection will take care of the vanishing
801 audioregionview by itself.
804 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
808 if (clicked_regionview == rv) {
809 clicked_regionview = 0;
812 if (entered_regionview == rv) {
813 set_entered_regionview (0);
816 if (!_all_region_actions_sensitized) {
817 sensitize_all_region_actions (true);
820 _over_region_trim_target = false;
824 Editor::set_entered_regionview (RegionView* rv)
826 if (rv == entered_regionview) {
830 if (entered_regionview) {
831 entered_regionview->exited ();
834 if ((entered_regionview = rv) != 0) {
835 entered_regionview->entered (internal_editing ());
838 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
839 /* This RegionView entry might have changed what region actions
840 are allowed, so sensitize them all in case a key is pressed.
842 sensitize_all_region_actions (true);
847 Editor::set_entered_track (TimeAxisView* tav)
850 entered_track->exited ();
853 if ((entered_track = tav) != 0) {
854 entered_track->entered ();
859 Editor::show_window ()
861 if (!is_visible ()) {
864 /* XXX: this is a bit unfortunate; it would probably
865 be nicer if we could just call show () above rather
866 than needing the show_all ()
869 /* re-hide stuff if necessary */
870 editor_list_button_toggled ();
871 parameter_changed ("show-summary");
872 parameter_changed ("show-group-tabs");
873 parameter_changed ("show-zoom-tools");
875 /* now reset all audio_time_axis heights, because widgets might need
881 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
882 tv = (static_cast<TimeAxisView*>(*i));
886 if (current_mixer_strip) {
887 current_mixer_strip->hide_things ();
888 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
896 Editor::instant_save ()
898 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
903 _session->add_instant_xml(get_state());
905 Config->add_instant_xml(get_state());
910 Editor::zoom_adjustment_changed ()
916 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
917 bool clamped = clamp_samples_per_pixel (fpu);
920 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
927 Editor::control_vertical_zoom_in_all ()
929 tav_zoom_smooth (false, true);
933 Editor::control_vertical_zoom_out_all ()
935 tav_zoom_smooth (true, true);
939 Editor::control_vertical_zoom_in_selected ()
941 tav_zoom_smooth (false, false);
945 Editor::control_vertical_zoom_out_selected ()
947 tav_zoom_smooth (true, false);
951 Editor::control_view (uint32_t view)
953 goto_visual_state (view);
957 Editor::control_unselect ()
959 selection->clear_tracks ();
963 Editor::control_select (uint32_t rid, Selection::Operation op)
965 /* handles the (static) signal from the ControlProtocol class that
966 * requests setting the selected track to a given RID
973 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
979 TimeAxisView* tav = axis_view_from_route (r);
984 selection->add (tav);
986 case Selection::Toggle:
987 selection->toggle (tav);
989 case Selection::Extend:
992 selection->set (tav);
996 selection->clear_tracks ();
1001 Editor::control_step_tracks_up ()
1003 scroll_tracks_up_line ();
1007 Editor::control_step_tracks_down ()
1009 scroll_tracks_down_line ();
1013 Editor::control_scroll (float fraction)
1015 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1021 double step = fraction * current_page_samples();
1024 _control_scroll_target is an optional<T>
1026 it acts like a pointer to an framepos_t, with
1027 a operator conversion to boolean to check
1028 that it has a value could possibly use
1029 playhead_cursor->current_frame to store the
1030 value and a boolean in the class to know
1031 when it's out of date
1034 if (!_control_scroll_target) {
1035 _control_scroll_target = _session->transport_frame();
1036 _dragging_playhead = true;
1039 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1040 *_control_scroll_target = 0;
1041 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1042 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1044 *_control_scroll_target += (framepos_t) floor (step);
1047 /* move visuals, we'll catch up with it later */
1049 playhead_cursor->set_position (*_control_scroll_target);
1050 UpdateAllTransportClocks (*_control_scroll_target);
1052 if (*_control_scroll_target > (current_page_samples() / 2)) {
1053 /* try to center PH in window */
1054 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1060 Now we do a timeout to actually bring the session to the right place
1061 according to the playhead. This is to avoid reading disk buffers on every
1062 call to control_scroll, which is driven by ScrollTimeline and therefore
1063 probably by a control surface wheel which can generate lots of events.
1065 /* cancel the existing timeout */
1067 control_scroll_connection.disconnect ();
1069 /* add the next timeout */
1071 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1075 Editor::deferred_control_scroll (framepos_t /*target*/)
1077 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1078 // reset for next stream
1079 _control_scroll_target = boost::none;
1080 _dragging_playhead = false;
1085 Editor::access_action (std::string action_group, std::string action_item)
1091 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1094 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1102 Editor::on_realize ()
1104 Window::on_realize ();
1109 Editor::map_position_change (framepos_t frame)
1111 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1113 if (_session == 0) {
1117 if (_follow_playhead) {
1118 center_screen (frame);
1121 playhead_cursor->set_position (frame);
1125 Editor::center_screen (framepos_t frame)
1127 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1129 /* if we're off the page, then scroll.
1132 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1133 center_screen_internal (frame, page);
1138 Editor::center_screen_internal (framepos_t frame, float page)
1143 frame -= (framepos_t) page;
1148 reset_x_origin (frame);
1153 Editor::update_title ()
1155 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1158 bool dirty = _session->dirty();
1160 string session_name;
1162 if (_session->snap_name() != _session->name()) {
1163 session_name = _session->snap_name();
1165 session_name = _session->name();
1169 session_name = "*" + session_name;
1172 WindowTitle title(session_name);
1173 title += Glib::get_application_name();
1174 set_title (title.get_string());
1176 /* ::session_going_away() will have taken care of it */
1181 Editor::set_session (Session *t)
1183 SessionHandlePtr::set_session (t);
1189 zoom_range_clock->set_session (_session);
1190 _playlist_selector->set_session (_session);
1191 nudge_clock->set_session (_session);
1192 _summary->set_session (_session);
1193 _group_tabs->set_session (_session);
1194 _route_groups->set_session (_session);
1195 _regions->set_session (_session);
1196 _snapshots->set_session (_session);
1197 _routes->set_session (_session);
1198 _locations->set_session (_session);
1200 if (rhythm_ferret) {
1201 rhythm_ferret->set_session (_session);
1204 if (analysis_window) {
1205 analysis_window->set_session (_session);
1209 sfbrowser->set_session (_session);
1212 compute_fixed_ruler_scale ();
1214 /* Make sure we have auto loop and auto punch ranges */
1216 Location* loc = _session->locations()->auto_loop_location();
1218 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1220 if (loc->start() == loc->end()) {
1221 loc->set_end (loc->start() + 1);
1224 _session->locations()->add (loc, false);
1225 _session->set_auto_loop_location (loc);
1228 loc->set_name (_("Loop"));
1231 loc = _session->locations()->auto_punch_location();
1234 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1236 if (loc->start() == loc->end()) {
1237 loc->set_end (loc->start() + 1);
1240 _session->locations()->add (loc, false);
1241 _session->set_auto_punch_location (loc);
1244 loc->set_name (_("Punch"));
1247 refresh_location_display ();
1249 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1250 the selected Marker; this needs the LocationMarker list to be available.
1252 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1253 set_state (*node, Stateful::loading_state_version);
1255 /* catch up with the playhead */
1257 _session->request_locate (playhead_cursor->current_frame ());
1258 _pending_initial_locate = true;
1262 /* These signals can all be emitted by a non-GUI thread. Therefore the
1263 handlers for them must not attempt to directly interact with the GUI,
1264 but use PBD::Signal<T>::connect() which accepts an event loop
1265 ("context") where the handler will be asked to run.
1268 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1269 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1270 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1271 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1272 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1273 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1274 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1275 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1276 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1277 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1278 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1279 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1280 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1281 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1283 playhead_cursor->show ();
1285 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1286 Config->map_parameters (pc);
1287 _session->config.map_parameters (pc);
1289 restore_ruler_visibility ();
1290 //tempo_map_changed (PropertyChange (0));
1291 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1293 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1294 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1297 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1298 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1301 switch (_snap_type) {
1302 case SnapToRegionStart:
1303 case SnapToRegionEnd:
1304 case SnapToRegionSync:
1305 case SnapToRegionBoundary:
1306 build_region_boundary_cache ();
1313 /* register for undo history */
1314 _session->register_with_memento_command_factory(id(), this);
1316 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1318 start_updating_meters ();
1322 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1324 if (a->get_name() == "RegionMenu") {
1325 /* When the main menu's region menu is opened, we setup the actions so that they look right
1326 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1327 so we resensitize all region actions when the entered regionview or the region selection
1328 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1329 happens after the region context menu is opened. So we set a flag here, too.
1333 sensitize_the_right_region_actions ();
1334 _last_region_menu_was_main = true;
1339 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1341 using namespace Menu_Helpers;
1343 void (Editor::*emf)(FadeShape);
1344 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1347 images = &_xfade_in_images;
1348 emf = &Editor::set_fade_in_shape;
1350 images = &_xfade_out_images;
1351 emf = &Editor::set_fade_out_shape;
1356 _("Linear (for highly correlated material)"),
1357 *(*images)[FadeLinear],
1358 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1362 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1366 _("Constant power"),
1367 *(*images)[FadeConstantPower],
1368 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1371 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1376 *(*images)[FadeSymmetric],
1377 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1381 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1386 *(*images)[FadeSlow],
1387 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1390 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1395 *(*images)[FadeFast],
1396 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1399 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1402 /** Pop up a context menu for when the user clicks on a start crossfade */
1404 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1406 using namespace Menu_Helpers;
1408 MenuList& items (xfade_in_context_menu.items());
1410 if (items.empty()) {
1411 fill_xfade_menu (items, true);
1414 xfade_in_context_menu.popup (button, time);
1417 /** Pop up a context menu for when the user clicks on an end crossfade */
1419 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1421 using namespace Menu_Helpers;
1423 MenuList& items (xfade_out_context_menu.items());
1425 if (items.empty()) {
1426 fill_xfade_menu (items, false);
1429 xfade_out_context_menu.popup (button, time);
1433 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1435 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1437 using namespace Menu_Helpers;
1438 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1441 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1445 MenuList& items (fade_context_menu.items());
1448 switch (item_type) {
1450 case FadeInHandleItem:
1451 if (arv->audio_region()->fade_in_active()) {
1452 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1454 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1457 items.push_back (SeparatorElem());
1459 if (Profile->get_sae()) {
1461 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1462 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1469 *_fade_in_images[FadeLinear],
1470 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *_fade_in_images[FadeSlow],
1480 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 *_fade_in_images[FadeFast],
1489 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *_fade_in_images[FadeSymmetric],
1498 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1503 _("Constant power"),
1504 *_fade_in_images[FadeConstantPower],
1505 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1514 case FadeOutHandleItem:
1515 if (arv->audio_region()->fade_out_active()) {
1516 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1518 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1521 items.push_back (SeparatorElem());
1523 if (Profile->get_sae()) {
1524 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1525 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1531 *_fade_out_images[FadeLinear],
1532 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1536 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1541 *_fade_out_images[FadeSlow],
1542 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1545 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1550 *_fade_out_images[FadeFast],
1551 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1554 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1559 *_fade_out_images[FadeSymmetric],
1560 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1565 _("Constant power"),
1566 *_fade_out_images[FadeConstantPower],
1567 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1570 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1576 fatal << _("programming error: ")
1577 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1582 fade_context_menu.popup (button, time);
1586 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1588 using namespace Menu_Helpers;
1589 Menu* (Editor::*build_menu_function)();
1592 switch (item_type) {
1594 case RegionViewName:
1595 case RegionViewNameHighlight:
1596 case LeftFrameHandle:
1597 case RightFrameHandle:
1598 if (with_selection) {
1599 build_menu_function = &Editor::build_track_selection_context_menu;
1601 build_menu_function = &Editor::build_track_region_context_menu;
1606 if (with_selection) {
1607 build_menu_function = &Editor::build_track_selection_context_menu;
1609 build_menu_function = &Editor::build_track_context_menu;
1614 if (clicked_routeview->track()) {
1615 build_menu_function = &Editor::build_track_context_menu;
1617 build_menu_function = &Editor::build_track_bus_context_menu;
1622 /* probably shouldn't happen but if it does, we don't care */
1626 menu = (this->*build_menu_function)();
1627 menu->set_name ("ArdourContextMenu");
1629 /* now handle specific situations */
1631 switch (item_type) {
1633 case RegionViewName:
1634 case RegionViewNameHighlight:
1635 case LeftFrameHandle:
1636 case RightFrameHandle:
1637 if (!with_selection) {
1638 if (region_edit_menu_split_item) {
1639 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1640 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1642 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1645 if (region_edit_menu_split_multichannel_item) {
1646 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1647 region_edit_menu_split_multichannel_item->set_sensitive (true);
1649 region_edit_menu_split_multichannel_item->set_sensitive (false);
1662 /* probably shouldn't happen but if it does, we don't care */
1666 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1668 /* Bounce to disk */
1670 using namespace Menu_Helpers;
1671 MenuList& edit_items = menu->items();
1673 edit_items.push_back (SeparatorElem());
1675 switch (clicked_routeview->audio_track()->freeze_state()) {
1676 case AudioTrack::NoFreeze:
1677 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1680 case AudioTrack::Frozen:
1681 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1684 case AudioTrack::UnFrozen:
1685 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1691 if (item_type == StreamItem && clicked_routeview) {
1692 clicked_routeview->build_underlay_menu(menu);
1695 /* When the region menu is opened, we setup the actions so that they look right
1698 sensitize_the_right_region_actions ();
1699 _last_region_menu_was_main = false;
1701 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1702 menu->popup (button, time);
1706 Editor::build_track_context_menu ()
1708 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_context_menu.items();
1713 add_dstream_context_items (edit_items);
1714 return &track_context_menu;
1718 Editor::build_track_bus_context_menu ()
1720 using namespace Menu_Helpers;
1722 MenuList& edit_items = track_context_menu.items();
1725 add_bus_context_items (edit_items);
1726 return &track_context_menu;
1730 Editor::build_track_region_context_menu ()
1732 using namespace Menu_Helpers;
1733 MenuList& edit_items = track_region_context_menu.items();
1736 /* we've just cleared the track region context menu, so the menu that these
1737 two items were on will have disappeared; stop them dangling.
1739 region_edit_menu_split_item = 0;
1740 region_edit_menu_split_multichannel_item = 0;
1742 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1745 boost::shared_ptr<Track> tr;
1746 boost::shared_ptr<Playlist> pl;
1748 if ((tr = rtv->track())) {
1749 add_region_context_items (edit_items, tr);
1753 add_dstream_context_items (edit_items);
1755 return &track_region_context_menu;
1759 Editor::analyze_region_selection ()
1761 if (analysis_window == 0) {
1762 analysis_window = new AnalysisWindow();
1765 analysis_window->set_session(_session);
1767 analysis_window->show_all();
1770 analysis_window->set_regionmode();
1771 analysis_window->analyze();
1773 analysis_window->present();
1777 Editor::analyze_range_selection()
1779 if (analysis_window == 0) {
1780 analysis_window = new AnalysisWindow();
1783 analysis_window->set_session(_session);
1785 analysis_window->show_all();
1788 analysis_window->set_rangemode();
1789 analysis_window->analyze();
1791 analysis_window->present();
1795 Editor::build_track_selection_context_menu ()
1797 using namespace Menu_Helpers;
1798 MenuList& edit_items = track_selection_context_menu.items();
1799 edit_items.clear ();
1801 add_selection_context_items (edit_items);
1802 // edit_items.push_back (SeparatorElem());
1803 // add_dstream_context_items (edit_items);
1805 return &track_selection_context_menu;
1809 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1811 using namespace Menu_Helpers;
1813 /* OK, stick the region submenu at the top of the list, and then add
1817 RegionSelection rs = get_regions_from_selection_and_entered ();
1819 string::size_type pos = 0;
1820 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1822 /* we have to hack up the region name because "_" has a special
1823 meaning for menu titles.
1826 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1827 menu_item_name.replace (pos, 1, "__");
1831 if (_popup_region_menu_item == 0) {
1832 _popup_region_menu_item = new MenuItem (menu_item_name);
1833 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1834 _popup_region_menu_item->show ();
1836 _popup_region_menu_item->set_label (menu_item_name);
1839 const framepos_t position = get_preferred_edit_position (false, true);
1841 edit_items.push_back (*_popup_region_menu_item);
1842 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1843 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1845 edit_items.push_back (SeparatorElem());
1848 /** Add context menu items relevant to selection ranges.
1849 * @param edit_items List to add the items to.
1852 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1854 using namespace Menu_Helpers;
1856 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1857 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1859 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1862 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (
1866 _("Move Range Start to Previous Region Boundary"),
1867 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1871 edit_items.push_back (
1873 _("Move Range Start to Next Region Boundary"),
1874 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1878 edit_items.push_back (
1880 _("Move Range End to Previous Region Boundary"),
1881 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1885 edit_items.push_back (
1887 _("Move Range End to Next Region Boundary"),
1888 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1892 edit_items.push_back (SeparatorElem());
1893 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1894 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1899 edit_items.push_back (SeparatorElem());
1900 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1901 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1906 edit_items.push_back (SeparatorElem());
1907 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1908 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1909 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1913 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1914 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1915 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1916 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1917 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1918 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1924 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1926 using namespace Menu_Helpers;
1930 Menu *play_menu = manage (new Menu);
1931 MenuList& play_items = play_menu->items();
1932 play_menu->set_name ("ArdourContextMenu");
1934 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1935 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1936 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1937 play_items.push_back (SeparatorElem());
1938 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1940 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1944 Menu *select_menu = manage (new Menu);
1945 MenuList& select_items = select_menu->items();
1946 select_menu->set_name ("ArdourContextMenu");
1948 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1949 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1950 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1951 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1952 select_items.push_back (SeparatorElem());
1953 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1954 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1955 select_items.push_back (SeparatorElem());
1956 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1957 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1958 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1959 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1960 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1961 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1962 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1964 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1968 Menu *cutnpaste_menu = manage (new Menu);
1969 MenuList& cutnpaste_items = cutnpaste_menu->items();
1970 cutnpaste_menu->set_name ("ArdourContextMenu");
1972 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1973 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1974 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1976 cutnpaste_items.push_back (SeparatorElem());
1978 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1979 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1981 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1983 /* Adding new material */
1985 edit_items.push_back (SeparatorElem());
1986 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1987 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1991 Menu *nudge_menu = manage (new Menu());
1992 MenuList& nudge_items = nudge_menu->items();
1993 nudge_menu->set_name ("ArdourContextMenu");
1995 edit_items.push_back (SeparatorElem());
1996 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1997 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1998 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1999 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2001 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2005 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2007 using namespace Menu_Helpers;
2011 Menu *play_menu = manage (new Menu);
2012 MenuList& play_items = play_menu->items();
2013 play_menu->set_name ("ArdourContextMenu");
2015 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2016 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2017 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2021 Menu *select_menu = manage (new Menu);
2022 MenuList& select_items = select_menu->items();
2023 select_menu->set_name ("ArdourContextMenu");
2025 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2026 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2027 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2028 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2029 select_items.push_back (SeparatorElem());
2030 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2031 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2032 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2033 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2035 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2039 Menu *cutnpaste_menu = manage (new Menu);
2040 MenuList& cutnpaste_items = cutnpaste_menu->items();
2041 cutnpaste_menu->set_name ("ArdourContextMenu");
2043 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2044 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2045 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2047 Menu *nudge_menu = manage (new Menu());
2048 MenuList& nudge_items = nudge_menu->items();
2049 nudge_menu->set_name ("ArdourContextMenu");
2051 edit_items.push_back (SeparatorElem());
2052 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2053 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2054 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2055 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2057 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2061 Editor::snap_type() const
2067 Editor::snap_mode() const
2073 Editor::set_snap_to (SnapType st)
2075 unsigned int snap_ind = (unsigned int)st;
2079 if (snap_ind > snap_type_strings.size() - 1) {
2081 _snap_type = (SnapType)snap_ind;
2084 string str = snap_type_strings[snap_ind];
2086 if (str != snap_type_selector.get_active_text()) {
2087 snap_type_selector.set_active_text (str);
2092 switch (_snap_type) {
2093 case SnapToBeatDiv128:
2094 case SnapToBeatDiv64:
2095 case SnapToBeatDiv32:
2096 case SnapToBeatDiv28:
2097 case SnapToBeatDiv24:
2098 case SnapToBeatDiv20:
2099 case SnapToBeatDiv16:
2100 case SnapToBeatDiv14:
2101 case SnapToBeatDiv12:
2102 case SnapToBeatDiv10:
2103 case SnapToBeatDiv8:
2104 case SnapToBeatDiv7:
2105 case SnapToBeatDiv6:
2106 case SnapToBeatDiv5:
2107 case SnapToBeatDiv4:
2108 case SnapToBeatDiv3:
2109 case SnapToBeatDiv2: {
2110 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2111 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2113 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2114 current_bbt_points_begin, current_bbt_points_end);
2115 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2116 current_bbt_points_begin, current_bbt_points_end);
2117 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2121 case SnapToRegionStart:
2122 case SnapToRegionEnd:
2123 case SnapToRegionSync:
2124 case SnapToRegionBoundary:
2125 build_region_boundary_cache ();
2133 SnapChanged (); /* EMIT SIGNAL */
2137 Editor::set_snap_mode (SnapMode mode)
2139 string str = snap_mode_strings[(int)mode];
2141 if (_internal_editing) {
2142 internal_snap_mode = mode;
2144 pre_internal_snap_mode = mode;
2149 if (str != snap_mode_selector.get_active_text ()) {
2150 snap_mode_selector.set_active_text (str);
2156 Editor::set_edit_point_preference (EditPoint ep, bool force)
2158 bool changed = (_edit_point != ep);
2161 string str = edit_point_strings[(int)ep];
2163 if (str != edit_point_selector.get_active_text ()) {
2164 edit_point_selector.set_active_text (str);
2167 set_canvas_cursor ();
2169 if (!force && !changed) {
2173 const char* action=NULL;
2175 switch (_edit_point) {
2176 case EditAtPlayhead:
2177 action = "edit-at-playhead";
2179 case EditAtSelectedMarker:
2180 action = "edit-at-marker";
2183 action = "edit-at-mouse";
2187 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2189 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2193 bool in_track_canvas;
2195 if (!mouse_frame (foo, in_track_canvas)) {
2196 in_track_canvas = false;
2199 reset_canvas_action_sensitivity (in_track_canvas);
2205 Editor::set_state (const XMLNode& node, int /*version*/)
2207 const XMLProperty* prop;
2214 g.base_width = default_width;
2215 g.base_height = default_height;
2219 if ((geometry = find_named_node (node, "geometry")) != 0) {
2223 if ((prop = geometry->property("x_size")) == 0) {
2224 prop = geometry->property ("x-size");
2227 g.base_width = atoi(prop->value());
2229 if ((prop = geometry->property("y_size")) == 0) {
2230 prop = geometry->property ("y-size");
2233 g.base_height = atoi(prop->value());
2236 if ((prop = geometry->property ("x_pos")) == 0) {
2237 prop = geometry->property ("x-pos");
2240 x = atoi (prop->value());
2243 if ((prop = geometry->property ("y_pos")) == 0) {
2244 prop = geometry->property ("y-pos");
2247 y = atoi (prop->value());
2251 set_default_size (g.base_width, g.base_height);
2254 if (_session && (prop = node.property ("playhead"))) {
2256 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2257 playhead_cursor->set_position (pos);
2259 playhead_cursor->set_position (0);
2262 if ((prop = node.property ("mixer-width"))) {
2263 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2266 if ((prop = node.property ("zoom-focus"))) {
2267 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2270 if ((prop = node.property ("zoom"))) {
2271 /* older versions of ardour used floating point samples_per_pixel */
2272 double f = PBD::atof (prop->value());
2273 reset_zoom (llrintf (f));
2275 reset_zoom (samples_per_pixel);
2278 if ((prop = node.property ("snap-to"))) {
2279 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2282 if ((prop = node.property ("snap-mode"))) {
2283 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2286 if ((prop = node.property ("internal-snap-to"))) {
2287 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2290 if ((prop = node.property ("internal-snap-mode"))) {
2291 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2294 if ((prop = node.property ("pre-internal-snap-to"))) {
2295 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2299 if ((prop = node.property ("pre-internal-snap-mode"))) {
2300 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2303 if ((prop = node.property ("mouse-mode"))) {
2304 MouseMode m = str2mousemode(prop->value());
2305 set_mouse_mode (m, true);
2307 set_mouse_mode (MouseObject, true);
2310 if ((prop = node.property ("left-frame")) != 0) {
2312 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2316 reset_x_origin (pos);
2320 if ((prop = node.property ("y-origin")) != 0) {
2321 reset_y_origin (atof (prop->value ()));
2324 if ((prop = node.property ("internal-edit"))) {
2325 bool yn = string_is_affirmative (prop->value());
2326 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2328 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2329 tact->set_active (!yn);
2330 tact->set_active (yn);
2334 if ((prop = node.property ("join-object-range"))) {
2335 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2336 bool yn = string_is_affirmative (prop->value());
2338 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2339 tact->set_active (!yn);
2340 tact->set_active (yn);
2342 set_mouse_mode(mouse_mode, true);
2345 if ((prop = node.property ("edit-point"))) {
2346 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2349 if ((prop = node.property ("show-measures"))) {
2350 bool yn = string_is_affirmative (prop->value());
2351 _show_measures = yn;
2352 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2354 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2355 /* do it twice to force the change */
2356 tact->set_active (!yn);
2357 tact->set_active (yn);
2361 if ((prop = node.property ("follow-playhead"))) {
2362 bool yn = string_is_affirmative (prop->value());
2363 set_follow_playhead (yn);
2364 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2366 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2367 if (tact->get_active() != yn) {
2368 tact->set_active (yn);
2373 if ((prop = node.property ("stationary-playhead"))) {
2374 bool yn = string_is_affirmative (prop->value());
2375 set_stationary_playhead (yn);
2376 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2378 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2379 if (tact->get_active() != yn) {
2380 tact->set_active (yn);
2385 if ((prop = node.property ("region-list-sort-type"))) {
2386 RegionListSortType st;
2387 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2390 if ((prop = node.property ("show-editor-mixer"))) {
2392 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2395 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2396 bool yn = string_is_affirmative (prop->value());
2398 /* do it twice to force the change */
2400 tact->set_active (!yn);
2401 tact->set_active (yn);
2404 if ((prop = node.property ("show-editor-list"))) {
2406 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2409 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2410 bool yn = string_is_affirmative (prop->value());
2412 /* do it twice to force the change */
2414 tact->set_active (!yn);
2415 tact->set_active (yn);
2418 if ((prop = node.property (X_("editor-list-page")))) {
2419 _the_notebook.set_current_page (atoi (prop->value ()));
2422 if ((prop = node.property (X_("show-marker-lines")))) {
2423 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2425 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2426 bool yn = string_is_affirmative (prop->value ());
2428 tact->set_active (!yn);
2429 tact->set_active (yn);
2432 XMLNodeList children = node.children ();
2433 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2434 selection->set_state (**i, Stateful::current_state_version);
2435 _regions->set_state (**i);
2438 if ((prop = node.property ("maximised"))) {
2439 bool yn = string_is_affirmative (prop->value());
2441 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2445 if ((prop = node.property ("nudge-clock-value"))) {
2447 sscanf (prop->value().c_str(), "%" PRId64, &f);
2448 nudge_clock->set (f);
2450 nudge_clock->set_mode (AudioClock::Timecode);
2451 nudge_clock->set (_session->frame_rate() * 5, true);
2458 Editor::get_state ()
2460 XMLNode* node = new XMLNode ("Editor");
2463 id().print (buf, sizeof (buf));
2464 node->add_property ("id", buf);
2466 if (is_realized()) {
2467 Glib::RefPtr<Gdk::Window> win = get_window();
2469 int x, y, width, height;
2470 win->get_root_origin(x, y);
2471 win->get_size(width, height);
2473 XMLNode* geometry = new XMLNode ("geometry");
2475 snprintf(buf, sizeof(buf), "%d", width);
2476 geometry->add_property("x-size", string(buf));
2477 snprintf(buf, sizeof(buf), "%d", height);
2478 geometry->add_property("y-size", string(buf));
2479 snprintf(buf, sizeof(buf), "%d", x);
2480 geometry->add_property("x-pos", string(buf));
2481 snprintf(buf, sizeof(buf), "%d", y);
2482 geometry->add_property("y-pos", string(buf));
2483 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2484 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2485 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2486 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2487 geometry->add_property("edit-vertical-pane-pos", string(buf));
2489 node->add_child_nocopy (*geometry);
2492 maybe_add_mixer_strip_width (*node);
2494 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2496 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2497 node->add_property ("zoom", buf);
2498 node->add_property ("snap-to", enum_2_string (_snap_type));
2499 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2500 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2501 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2502 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2503 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2504 node->add_property ("edit-point", enum_2_string (_edit_point));
2506 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2507 node->add_property ("playhead", buf);
2508 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2509 node->add_property ("left-frame", buf);
2510 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2511 node->add_property ("y-origin", buf);
2513 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2514 node->add_property ("maximised", _maximised ? "yes" : "no");
2515 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2516 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2517 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2518 node->add_property ("mouse-mode", enum2str(mouse_mode));
2519 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2520 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2522 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2524 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2525 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2528 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2530 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2531 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2534 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2535 node->add_property (X_("editor-list-page"), buf);
2537 if (button_bindings) {
2538 XMLNode* bb = new XMLNode (X_("Buttons"));
2539 button_bindings->save (*bb);
2540 node->add_child_nocopy (*bb);
2543 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2545 node->add_child_nocopy (selection->get_state ());
2546 node->add_child_nocopy (_regions->get_state ());
2548 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2549 node->add_property ("nudge-clock-value", buf);
2556 /** @param y y offset from the top of all trackviews.
2557 * @return pair: TimeAxisView that y is over, layer index.
2558 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2559 * in stacked or expanded region display mode, otherwise 0.
2561 std::pair<TimeAxisView *, double>
2562 Editor::trackview_by_y_position (double y)
2564 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2566 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2572 return std::make_pair ( (TimeAxisView *) 0, 0);
2575 /** Snap a position to the grid, if appropriate, taking into account current
2576 * grid settings and also the state of any snap modifier keys that may be pressed.
2577 * @param start Position to snap.
2578 * @param event Event to get current key modifier information from, or 0.
2581 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2583 if (!_session || !event) {
2587 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2588 if (_snap_mode == SnapOff) {
2589 snap_to_internal (start, direction, for_mark);
2592 if (_snap_mode != SnapOff) {
2593 snap_to_internal (start, direction, for_mark);
2599 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2601 if (!_session || _snap_mode == SnapOff) {
2605 snap_to_internal (start, direction, for_mark);
2609 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2611 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2612 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2614 switch (_snap_type) {
2615 case SnapToTimecodeFrame:
2616 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2617 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2619 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2623 case SnapToTimecodeSeconds:
2624 if (_session->config.get_timecode_offset_negative()) {
2625 start += _session->config.get_timecode_offset ();
2627 start -= _session->config.get_timecode_offset ();
2629 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2630 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2632 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2635 if (_session->config.get_timecode_offset_negative()) {
2636 start -= _session->config.get_timecode_offset ();
2638 start += _session->config.get_timecode_offset ();
2642 case SnapToTimecodeMinutes:
2643 if (_session->config.get_timecode_offset_negative()) {
2644 start += _session->config.get_timecode_offset ();
2646 start -= _session->config.get_timecode_offset ();
2648 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2649 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2651 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2653 if (_session->config.get_timecode_offset_negative()) {
2654 start -= _session->config.get_timecode_offset ();
2656 start += _session->config.get_timecode_offset ();
2660 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2666 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2668 const framepos_t one_second = _session->frame_rate();
2669 const framepos_t one_minute = _session->frame_rate() * 60;
2670 framepos_t presnap = start;
2674 switch (_snap_type) {
2675 case SnapToTimecodeFrame:
2676 case SnapToTimecodeSeconds:
2677 case SnapToTimecodeMinutes:
2678 return timecode_snap_to_internal (start, direction, for_mark);
2681 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2682 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2684 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2689 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2690 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2692 start = (framepos_t) floor ((double) start / one_second) * one_second;
2697 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2698 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2700 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2705 start = _session->tempo_map().round_to_bar (start, direction);
2709 start = _session->tempo_map().round_to_beat (start, direction);
2712 case SnapToBeatDiv128:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2715 case SnapToBeatDiv64:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2718 case SnapToBeatDiv32:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2721 case SnapToBeatDiv28:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2724 case SnapToBeatDiv24:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2727 case SnapToBeatDiv20:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2730 case SnapToBeatDiv16:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2733 case SnapToBeatDiv14:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2736 case SnapToBeatDiv12:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2739 case SnapToBeatDiv10:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2742 case SnapToBeatDiv8:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2745 case SnapToBeatDiv7:
2746 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2748 case SnapToBeatDiv6:
2749 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2751 case SnapToBeatDiv5:
2752 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2754 case SnapToBeatDiv4:
2755 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2757 case SnapToBeatDiv3:
2758 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2760 case SnapToBeatDiv2:
2761 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2769 _session->locations()->marks_either_side (start, before, after);
2771 if (before == max_framepos && after == max_framepos) {
2772 /* No marks to snap to, so just don't snap */
2774 } else if (before == max_framepos) {
2776 } else if (after == max_framepos) {
2778 } else if (before != max_framepos && after != max_framepos) {
2779 /* have before and after */
2780 if ((start - before) < (after - start)) {
2789 case SnapToRegionStart:
2790 case SnapToRegionEnd:
2791 case SnapToRegionSync:
2792 case SnapToRegionBoundary:
2793 if (!region_boundary_cache.empty()) {
2795 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2796 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2798 if (direction > 0) {
2799 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2801 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2804 if (next != region_boundary_cache.begin ()) {
2809 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2810 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2812 if (start > (p + n) / 2) {
2821 switch (_snap_mode) {
2827 if (presnap > start) {
2828 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2832 } else if (presnap < start) {
2833 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2839 /* handled at entry */
2847 Editor::setup_toolbar ()
2849 HBox* mode_box = manage(new HBox);
2850 mode_box->set_border_width (2);
2851 mode_box->set_spacing(4);
2853 HBox* mouse_mode_box = manage (new HBox);
2854 HBox* mouse_mode_hbox = manage (new HBox);
2855 VBox* mouse_mode_vbox = manage (new VBox);
2856 Alignment* mouse_mode_align = manage (new Alignment);
2858 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2859 // mouse_mode_size_group->add_widget (smart_mode_button);
2860 mouse_mode_size_group->add_widget (mouse_move_button);
2861 mouse_mode_size_group->add_widget (mouse_select_button);
2862 mouse_mode_size_group->add_widget (mouse_zoom_button);
2863 mouse_mode_size_group->add_widget (mouse_gain_button);
2864 mouse_mode_size_group->add_widget (mouse_timefx_button);
2865 mouse_mode_size_group->add_widget (mouse_audition_button);
2866 mouse_mode_size_group->add_widget (mouse_draw_button);
2867 mouse_mode_size_group->add_widget (internal_edit_button);
2869 /* make them just a bit bigger */
2870 mouse_move_button.set_size_request (-1, 30);
2872 mouse_mode_hbox->set_spacing (2);
2874 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2875 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2876 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2877 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2878 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2879 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2880 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2881 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2882 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2884 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2886 mouse_mode_align->add (*mouse_mode_vbox);
2887 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2889 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2891 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2892 if (!Profile->get_sae()) {
2893 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2895 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2897 edit_mode_selector.set_name ("EditModeSelector");
2898 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2899 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2901 mode_box->pack_start (edit_mode_selector, false, false);
2902 mode_box->pack_start (*mouse_mode_box, false, false);
2904 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2905 _mouse_mode_tearoff->set_name ("MouseModeBase");
2906 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2908 if (Profile->get_sae()) {
2909 _mouse_mode_tearoff->set_can_be_torn_off (false);
2912 _mouse_mode_tearoff->Detach.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->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2915 &_mouse_mode_tearoff->tearoff_window(), 1));
2916 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2917 &_mouse_mode_tearoff->tearoff_window()));
2918 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2919 &_mouse_mode_tearoff->tearoff_window(), 1));
2923 _zoom_box.set_spacing (2);
2924 _zoom_box.set_border_width (2);
2928 zoom_in_button.set_name ("zoom button");
2929 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2930 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2931 zoom_in_button.set_image(::get_icon ("zoom_in"));
2932 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2933 zoom_in_button.set_related_action (act);
2935 zoom_out_button.set_name ("zoom button");
2936 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2937 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2938 zoom_out_button.set_image(::get_icon ("zoom_out"));
2939 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2940 zoom_out_button.set_related_action (act);
2942 zoom_out_full_button.set_name ("zoom button");
2943 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2944 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2945 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2946 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2947 zoom_out_full_button.set_related_action (act);
2949 zoom_focus_selector.set_name ("ZoomFocusSelector");
2950 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2951 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2953 _zoom_box.pack_start (zoom_out_button, false, false);
2954 _zoom_box.pack_start (zoom_in_button, false, false);
2955 _zoom_box.pack_start (zoom_out_full_button, false, false);
2957 _zoom_box.pack_start (zoom_focus_selector, false, false);
2959 /* Track zoom buttons */
2960 tav_expand_button.set_name ("zoom button");
2961 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2962 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2963 tav_expand_button.set_size_request (-1, 20);
2964 tav_expand_button.set_image(::get_icon ("tav_exp"));
2965 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2966 tav_expand_button.set_related_action (act);
2968 tav_shrink_button.set_name ("zoom button");
2969 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2970 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2971 tav_shrink_button.set_size_request (-1, 20);
2972 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2973 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2974 tav_shrink_button.set_related_action (act);
2976 _zoom_box.pack_start (tav_shrink_button);
2977 _zoom_box.pack_start (tav_expand_button);
2979 _zoom_tearoff = manage (new TearOff (_zoom_box));
2981 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2982 &_zoom_tearoff->tearoff_window()));
2983 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2984 &_zoom_tearoff->tearoff_window(), 0));
2985 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2986 &_zoom_tearoff->tearoff_window()));
2987 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2988 &_zoom_tearoff->tearoff_window(), 0));
2990 snap_box.set_spacing (2);
2991 snap_box.set_border_width (2);
2993 snap_type_selector.set_name ("SnapTypeSelector");
2994 set_popdown_strings (snap_type_selector, snap_type_strings);
2995 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2997 snap_mode_selector.set_name ("SnapModeSelector");
2998 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2999 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3001 edit_point_selector.set_name ("EditPointSelector");
3002 set_popdown_strings (edit_point_selector, edit_point_strings);
3003 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3005 snap_box.pack_start (snap_mode_selector, false, false);
3006 snap_box.pack_start (snap_type_selector, false, false);
3007 snap_box.pack_start (edit_point_selector, false, false);
3011 HBox *nudge_box = manage (new HBox);
3012 nudge_box->set_spacing (2);
3013 nudge_box->set_border_width (2);
3015 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3016 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3018 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3019 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3021 nudge_box->pack_start (nudge_backward_button, false, false);
3022 nudge_box->pack_start (nudge_forward_button, false, false);
3023 nudge_box->pack_start (*nudge_clock, false, false);
3026 /* Pack everything in... */
3028 HBox* hbox = manage (new HBox);
3029 hbox->set_spacing(10);
3031 _tools_tearoff = manage (new TearOff (*hbox));
3032 _tools_tearoff->set_name ("MouseModeBase");
3033 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3035 if (Profile->get_sae()) {
3036 _tools_tearoff->set_can_be_torn_off (false);
3039 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3040 &_tools_tearoff->tearoff_window()));
3041 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3042 &_tools_tearoff->tearoff_window(), 0));
3043 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3044 &_tools_tearoff->tearoff_window()));
3045 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3046 &_tools_tearoff->tearoff_window(), 0));
3048 toolbar_hbox.set_spacing (10);
3049 toolbar_hbox.set_border_width (1);
3051 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3052 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3053 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3055 hbox->pack_start (snap_box, false, false);
3056 if (!Profile->get_small_screen()) {
3057 hbox->pack_start (*nudge_box, false, false);
3059 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3061 hbox->pack_start (panic_box, false, false);
3065 toolbar_base.set_name ("ToolBarBase");
3066 toolbar_base.add (toolbar_hbox);
3068 _toolbar_viewport.add (toolbar_base);
3069 /* stick to the required height but allow width to vary if there's not enough room */
3070 _toolbar_viewport.set_size_request (1, -1);
3072 toolbar_frame.set_shadow_type (SHADOW_OUT);
3073 toolbar_frame.set_name ("BaseFrame");
3074 toolbar_frame.add (_toolbar_viewport);
3078 Editor::setup_tooltips ()
3080 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3081 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3082 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3083 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3084 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3085 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3086 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3087 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3088 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3089 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3090 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3091 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3092 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3093 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3094 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3095 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3096 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3097 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3098 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3099 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3100 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3101 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3102 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3106 Editor::convert_drop_to_paths (
3107 vector<string>& paths,
3108 const RefPtr<Gdk::DragContext>& /*context*/,
3111 const SelectionData& data,
3115 if (_session == 0) {
3119 vector<string> uris = data.get_uris();
3123 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3124 are actually URI lists. So do it by hand.
3127 if (data.get_target() != "text/plain") {
3131 /* Parse the "uri-list" format that Nautilus provides,
3132 where each pathname is delimited by \r\n.
3134 THERE MAY BE NO NULL TERMINATING CHAR!!!
3137 string txt = data.get_text();
3141 p = (char *) malloc (txt.length() + 1);
3142 txt.copy (p, txt.length(), 0);
3143 p[txt.length()] = '\0';
3149 while (g_ascii_isspace (*p))
3153 while (*q && (*q != '\n') && (*q != '\r')) {
3160 while (q > p && g_ascii_isspace (*q))
3165 uris.push_back (string (p, q - p + 1));
3169 p = strchr (p, '\n');
3181 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3182 if ((*i).substr (0,7) == "file://") {
3183 paths.push_back (Glib::filename_from_uri (*i));
3191 Editor::new_tempo_section ()
3196 Editor::map_transport_state ()
3198 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3200 if (_session && _session->transport_stopped()) {
3201 have_pending_keyboard_selection = false;
3204 update_loop_range_view (true);
3210 Editor::begin_reversible_command (string name)
3213 _session->begin_reversible_command (name);
3218 Editor::begin_reversible_command (GQuark q)
3221 _session->begin_reversible_command (q);
3226 Editor::commit_reversible_command ()
3229 _session->commit_reversible_command ();
3234 Editor::history_changed ()
3238 if (undo_action && _session) {
3239 if (_session->undo_depth() == 0) {
3240 label = S_("Command|Undo");
3242 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3244 undo_action->property_label() = label;
3247 if (redo_action && _session) {
3248 if (_session->redo_depth() == 0) {
3251 label = string_compose(_("Redo (%1)"), _session->next_redo());
3253 redo_action->property_label() = label;
3258 Editor::duplicate_range (bool with_dialog)
3262 RegionSelection rs = get_regions_from_selection_and_entered ();
3264 if ( selection->time.length() == 0 && rs.empty()) {
3270 ArdourDialog win (_("Duplicate"));
3271 Label label (_("Number of duplications:"));
3272 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3273 SpinButton spinner (adjustment, 0.0, 1);
3276 win.get_vbox()->set_spacing (12);
3277 win.get_vbox()->pack_start (hbox);
3278 hbox.set_border_width (6);
3279 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3281 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3282 place, visually. so do this by hand.
3285 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3286 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3287 spinner.grab_focus();
3293 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3294 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3295 win.set_default_response (RESPONSE_ACCEPT);
3297 spinner.grab_focus ();
3299 switch (win.run ()) {
3300 case RESPONSE_ACCEPT:
3306 times = adjustment.get_value();
3309 if ((current_mouse_mode() == Editing::MouseRange)) {
3310 if (selection->time.length()) {
3311 duplicate_selection (times);
3313 } else if (get_smart_mode()) {
3314 if (selection->time.length()) {
3315 duplicate_selection (times);
3317 duplicate_some_regions (rs, times);
3319 duplicate_some_regions (rs, times);
3324 Editor::set_edit_mode (EditMode m)
3326 Config->set_edit_mode (m);
3330 Editor::cycle_edit_mode ()
3332 switch (Config->get_edit_mode()) {
3334 if (Profile->get_sae()) {
3335 Config->set_edit_mode (Lock);
3337 Config->set_edit_mode (Splice);
3341 Config->set_edit_mode (Lock);
3344 Config->set_edit_mode (Slide);
3350 Editor::edit_mode_selection_done ()
3352 string s = edit_mode_selector.get_active_text ();
3355 Config->set_edit_mode (string_to_edit_mode (s));
3360 Editor::snap_type_selection_done ()
3362 string choice = snap_type_selector.get_active_text();
3363 SnapType snaptype = SnapToBeat;
3365 if (choice == _("Beats/2")) {
3366 snaptype = SnapToBeatDiv2;
3367 } else if (choice == _("Beats/3")) {
3368 snaptype = SnapToBeatDiv3;
3369 } else if (choice == _("Beats/4")) {
3370 snaptype = SnapToBeatDiv4;
3371 } else if (choice == _("Beats/5")) {
3372 snaptype = SnapToBeatDiv5;
3373 } else if (choice == _("Beats/6")) {
3374 snaptype = SnapToBeatDiv6;
3375 } else if (choice == _("Beats/7")) {
3376 snaptype = SnapToBeatDiv7;
3377 } else if (choice == _("Beats/8")) {
3378 snaptype = SnapToBeatDiv8;
3379 } else if (choice == _("Beats/10")) {
3380 snaptype = SnapToBeatDiv10;
3381 } else if (choice == _("Beats/12")) {
3382 snaptype = SnapToBeatDiv12;
3383 } else if (choice == _("Beats/14")) {
3384 snaptype = SnapToBeatDiv14;
3385 } else if (choice == _("Beats/16")) {
3386 snaptype = SnapToBeatDiv16;
3387 } else if (choice == _("Beats/20")) {
3388 snaptype = SnapToBeatDiv20;
3389 } else if (choice == _("Beats/24")) {
3390 snaptype = SnapToBeatDiv24;
3391 } else if (choice == _("Beats/28")) {
3392 snaptype = SnapToBeatDiv28;
3393 } else if (choice == _("Beats/32")) {
3394 snaptype = SnapToBeatDiv32;
3395 } else if (choice == _("Beats/64")) {
3396 snaptype = SnapToBeatDiv64;
3397 } else if (choice == _("Beats/128")) {
3398 snaptype = SnapToBeatDiv128;
3399 } else if (choice == _("Beats")) {
3400 snaptype = SnapToBeat;
3401 } else if (choice == _("Bars")) {
3402 snaptype = SnapToBar;
3403 } else if (choice == _("Marks")) {
3404 snaptype = SnapToMark;
3405 } else if (choice == _("Region starts")) {
3406 snaptype = SnapToRegionStart;
3407 } else if (choice == _("Region ends")) {
3408 snaptype = SnapToRegionEnd;
3409 } else if (choice == _("Region bounds")) {
3410 snaptype = SnapToRegionBoundary;
3411 } else if (choice == _("Region syncs")) {
3412 snaptype = SnapToRegionSync;
3413 } else if (choice == _("CD Frames")) {
3414 snaptype = SnapToCDFrame;
3415 } else if (choice == _("Timecode Frames")) {
3416 snaptype = SnapToTimecodeFrame;
3417 } else if (choice == _("Timecode Seconds")) {
3418 snaptype = SnapToTimecodeSeconds;
3419 } else if (choice == _("Timecode Minutes")) {
3420 snaptype = SnapToTimecodeMinutes;
3421 } else if (choice == _("Seconds")) {
3422 snaptype = SnapToSeconds;
3423 } else if (choice == _("Minutes")) {
3424 snaptype = SnapToMinutes;
3427 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3429 ract->set_active ();
3434 Editor::snap_mode_selection_done ()
3436 string choice = snap_mode_selector.get_active_text();
3437 SnapMode mode = SnapNormal;
3439 if (choice == _("No Grid")) {
3441 } else if (choice == _("Grid")) {
3443 } else if (choice == _("Magnetic")) {
3444 mode = SnapMagnetic;
3447 RefPtr<RadioAction> ract = snap_mode_action (mode);
3450 ract->set_active (true);
3455 Editor::cycle_edit_point (bool with_marker)
3457 switch (_edit_point) {
3459 set_edit_point_preference (EditAtPlayhead);
3461 case EditAtPlayhead:
3463 set_edit_point_preference (EditAtSelectedMarker);
3465 set_edit_point_preference (EditAtMouse);
3468 case EditAtSelectedMarker:
3469 set_edit_point_preference (EditAtMouse);
3475 Editor::edit_point_selection_done ()
3477 string choice = edit_point_selector.get_active_text();
3478 EditPoint ep = EditAtSelectedMarker;
3480 if (choice == _("Marker")) {
3481 set_edit_point_preference (EditAtSelectedMarker);
3482 } else if (choice == _("Playhead")) {
3483 set_edit_point_preference (EditAtPlayhead);
3485 set_edit_point_preference (EditAtMouse);
3488 RefPtr<RadioAction> ract = edit_point_action (ep);
3491 ract->set_active (true);
3496 Editor::zoom_focus_selection_done ()
3498 string choice = zoom_focus_selector.get_active_text();
3499 ZoomFocus focus_type = ZoomFocusLeft;
3501 if (choice == _("Left")) {
3502 focus_type = ZoomFocusLeft;
3503 } else if (choice == _("Right")) {
3504 focus_type = ZoomFocusRight;
3505 } else if (choice == _("Center")) {
3506 focus_type = ZoomFocusCenter;
3507 } else if (choice == _("Playhead")) {
3508 focus_type = ZoomFocusPlayhead;
3509 } else if (choice == _("Mouse")) {
3510 focus_type = ZoomFocusMouse;
3511 } else if (choice == _("Edit point")) {
3512 focus_type = ZoomFocusEdit;
3515 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3518 ract->set_active ();
3523 Editor::edit_controls_button_release (GdkEventButton* ev)
3525 if (Keyboard::is_context_menu_event (ev)) {
3526 ARDOUR_UI::instance()->add_route (this);
3527 } else if (ev->button == 1) {
3528 selection->clear_tracks ();
3535 Editor::mouse_select_button_release (GdkEventButton* ev)
3537 /* this handles just right-clicks */
3539 if (ev->button != 3) {
3547 Editor::set_zoom_focus (ZoomFocus f)
3549 string str = zoom_focus_strings[(int)f];
3551 if (str != zoom_focus_selector.get_active_text()) {
3552 zoom_focus_selector.set_active_text (str);
3555 if (zoom_focus != f) {
3562 Editor::cycle_zoom_focus ()
3564 switch (zoom_focus) {
3566 set_zoom_focus (ZoomFocusRight);
3568 case ZoomFocusRight:
3569 set_zoom_focus (ZoomFocusCenter);
3571 case ZoomFocusCenter:
3572 set_zoom_focus (ZoomFocusPlayhead);
3574 case ZoomFocusPlayhead:
3575 set_zoom_focus (ZoomFocusMouse);
3577 case ZoomFocusMouse:
3578 set_zoom_focus (ZoomFocusEdit);
3581 set_zoom_focus (ZoomFocusLeft);
3587 Editor::ensure_float (Window& win)
3589 win.set_transient_for (*this);
3593 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3595 /* recover or initialize pane positions. do this here rather than earlier because
3596 we don't want the positions to change the child allocations, which they seem to do.
3602 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3611 XMLNode* geometry = find_named_node (*node, "geometry");
3613 if (which == static_cast<Paned*> (&edit_pane)) {
3615 if (done & Horizontal) {
3619 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3620 _notebook_shrunk = string_is_affirmative (prop->value ());
3623 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3624 /* initial allocation is 90% to canvas, 10% to notebook */
3625 pos = (int) floor (alloc.get_width() * 0.90f);
3626 snprintf (buf, sizeof(buf), "%d", pos);
3628 pos = atoi (prop->value());
3631 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3632 edit_pane.set_position (pos);
3635 done = (Pane) (done | Horizontal);
3637 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3639 if (done & Vertical) {
3643 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3644 /* initial allocation is 90% to canvas, 10% to summary */
3645 pos = (int) floor (alloc.get_height() * 0.90f);
3646 snprintf (buf, sizeof(buf), "%d", pos);
3649 pos = atoi (prop->value());
3652 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3653 editor_summary_pane.set_position (pos);
3656 done = (Pane) (done | Vertical);
3661 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3663 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3664 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3665 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3666 top_hbox.remove (toolbar_frame);
3671 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3673 if (toolbar_frame.get_parent() == 0) {
3674 top_hbox.pack_end (toolbar_frame);
3679 Editor::set_show_measures (bool yn)
3681 if (_show_measures != yn) {
3684 if ((_show_measures = yn) == true) {
3686 tempo_lines->show();
3689 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3690 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3692 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3693 draw_measures (begin, end);
3701 Editor::toggle_follow_playhead ()
3703 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3705 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3706 set_follow_playhead (tact->get_active());
3710 /** @param yn true to follow playhead, otherwise false.
3711 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3714 Editor::set_follow_playhead (bool yn, bool catch_up)
3716 if (_follow_playhead != yn) {
3717 if ((_follow_playhead = yn) == true && catch_up) {
3719 reset_x_origin_to_follow_playhead ();
3726 Editor::toggle_stationary_playhead ()
3728 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3730 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3731 set_stationary_playhead (tact->get_active());
3736 Editor::set_stationary_playhead (bool yn)
3738 if (_stationary_playhead != yn) {
3739 if ((_stationary_playhead = yn) == true) {
3741 // FIXME need a 3.0 equivalent of this 2.X call
3742 // update_current_screen ();
3749 Editor::playlist_selector () const
3751 return *_playlist_selector;
3755 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3759 switch (_snap_type) {
3764 case SnapToBeatDiv128:
3767 case SnapToBeatDiv64:
3770 case SnapToBeatDiv32:
3773 case SnapToBeatDiv28:
3776 case SnapToBeatDiv24:
3779 case SnapToBeatDiv20:
3782 case SnapToBeatDiv16:
3785 case SnapToBeatDiv14:
3788 case SnapToBeatDiv12:
3791 case SnapToBeatDiv10:
3794 case SnapToBeatDiv8:
3797 case SnapToBeatDiv7:
3800 case SnapToBeatDiv6:
3803 case SnapToBeatDiv5:
3806 case SnapToBeatDiv4:
3809 case SnapToBeatDiv3:
3812 case SnapToBeatDiv2:
3818 return _session->tempo_map().meter_at (position).divisions_per_bar();
3823 case SnapToTimecodeFrame:
3824 case SnapToTimecodeSeconds:
3825 case SnapToTimecodeMinutes:
3828 case SnapToRegionStart:
3829 case SnapToRegionEnd:
3830 case SnapToRegionSync:
3831 case SnapToRegionBoundary:
3841 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3845 ret = nudge_clock->current_duration (pos);
3846 next = ret + 1; /* XXXX fix me */
3852 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3854 ArdourDialog dialog (_("Playlist Deletion"));
3855 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3856 "If it is kept, its audio files will not be cleaned.\n"
3857 "If it is deleted, audio files used by it alone will be cleaned."),
3860 dialog.set_position (WIN_POS_CENTER);
3861 dialog.get_vbox()->pack_start (label);
3865 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3866 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3867 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3869 switch (dialog.run ()) {
3870 case RESPONSE_ACCEPT:
3871 /* delete the playlist */
3875 case RESPONSE_REJECT:
3876 /* keep the playlist */
3888 Editor::audio_region_selection_covers (framepos_t where)
3890 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3891 if ((*a)->region()->covers (where)) {
3900 Editor::prepare_for_cleanup ()
3902 cut_buffer->clear_regions ();
3903 cut_buffer->clear_playlists ();
3905 selection->clear_regions ();
3906 selection->clear_playlists ();
3908 _regions->suspend_redisplay ();
3912 Editor::finish_cleanup ()
3914 _regions->resume_redisplay ();
3918 Editor::transport_loop_location()
3921 return _session->locations()->auto_loop_location();
3928 Editor::transport_punch_location()
3931 return _session->locations()->auto_punch_location();
3938 Editor::control_layout_scroll (GdkEventScroll* ev)
3940 if (Keyboard::some_magic_widget_has_focus()) {
3944 switch (ev->direction) {
3946 scroll_tracks_up_line ();
3950 case GDK_SCROLL_DOWN:
3951 scroll_tracks_down_line ();
3955 /* no left/right handling yet */
3963 Editor::session_state_saved (string)
3966 _snapshots->redisplay ();
3970 Editor::update_tearoff_visibility()
3972 bool visible = Config->get_keep_tearoffs();
3973 _mouse_mode_tearoff->set_visible (visible);
3974 _tools_tearoff->set_visible (visible);
3975 _zoom_tearoff->set_visible (visible);
3979 Editor::maximise_editing_space ()
3991 Editor::restore_editing_space ()
4003 * Make new playlists for a given track and also any others that belong
4004 * to the same active route group with the `select' property.
4009 Editor::new_playlists (TimeAxisView* v)
4011 begin_reversible_command (_("new playlists"));
4012 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4013 _session->playlists->get (playlists);
4014 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4015 commit_reversible_command ();
4019 * Use a copy of the current playlist for a given track and also any others that belong
4020 * to the same active route group with the `select' property.
4025 Editor::copy_playlists (TimeAxisView* v)
4027 begin_reversible_command (_("copy playlists"));
4028 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4029 _session->playlists->get (playlists);
4030 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4031 commit_reversible_command ();
4034 /** Clear the current playlist for a given track and also any others that belong
4035 * to the same active route group with the `select' property.
4040 Editor::clear_playlists (TimeAxisView* v)
4042 begin_reversible_command (_("clear playlists"));
4043 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4044 _session->playlists->get (playlists);
4045 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4046 commit_reversible_command ();
4050 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4052 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4056 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4058 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4062 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4064 atv.clear_playlist ();
4068 Editor::on_key_press_event (GdkEventKey* ev)
4070 return key_press_focus_accelerator_handler (*this, ev);
4074 Editor::on_key_release_event (GdkEventKey* ev)
4076 return Gtk::Window::on_key_release_event (ev);
4077 // return key_press_focus_accelerator_handler (*this, ev);
4080 /** Queue up a change to the viewport x origin.
4081 * @param frame New x origin.
4084 Editor::reset_x_origin (framepos_t frame)
4086 pending_visual_change.add (VisualChange::TimeOrigin);
4087 pending_visual_change.time_origin = frame;
4088 ensure_visual_change_idle_handler ();
4092 Editor::reset_y_origin (double y)
4094 pending_visual_change.add (VisualChange::YOrigin);
4095 pending_visual_change.y_origin = y;
4096 ensure_visual_change_idle_handler ();
4100 Editor::reset_zoom (framecnt_t spp)
4102 clamp_samples_per_pixel (spp);
4104 if (spp == samples_per_pixel) {
4108 pending_visual_change.add (VisualChange::ZoomLevel);
4109 pending_visual_change.samples_per_pixel = spp;
4110 ensure_visual_change_idle_handler ();
4114 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4116 reset_x_origin (frame);
4119 if (!no_save_visual) {
4120 undo_visual_stack.push_back (current_visual_state(false));
4124 Editor::VisualState::VisualState (bool with_tracks)
4125 : gui_state (with_tracks ? new GUIObjectState : 0)
4129 Editor::VisualState::~VisualState ()
4134 Editor::VisualState*
4135 Editor::current_visual_state (bool with_tracks)
4137 VisualState* vs = new VisualState (with_tracks);
4138 vs->y_position = vertical_adjustment.get_value();
4139 vs->samples_per_pixel = samples_per_pixel;
4140 vs->leftmost_frame = leftmost_frame;
4141 vs->zoom_focus = zoom_focus;
4144 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4151 Editor::undo_visual_state ()
4153 if (undo_visual_stack.empty()) {
4157 VisualState* vs = undo_visual_stack.back();
4158 undo_visual_stack.pop_back();
4161 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4163 use_visual_state (*vs);
4167 Editor::redo_visual_state ()
4169 if (redo_visual_stack.empty()) {
4173 VisualState* vs = redo_visual_stack.back();
4174 redo_visual_stack.pop_back();
4176 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4178 use_visual_state (*vs);
4182 Editor::swap_visual_state ()
4184 if (undo_visual_stack.empty()) {
4185 redo_visual_state ();
4187 undo_visual_state ();
4192 Editor::use_visual_state (VisualState& vs)
4194 PBD::Unwinder<bool> nsv (no_save_visual, true);
4196 _routes->suspend_redisplay ();
4198 vertical_adjustment.set_value (vs.y_position);
4200 set_zoom_focus (vs.zoom_focus);
4201 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4204 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4206 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4207 (*i)->reset_visual_state ();
4211 _routes->update_visibility ();
4212 _routes->resume_redisplay ();
4215 /** This is the core function that controls the zoom level of the canvas. It is called
4216 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4217 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4220 Editor::set_samples_per_pixel (framecnt_t spp)
4222 clamp_samples_per_pixel (spp);
4223 samples_per_pixel = spp;
4226 tempo_lines->tempo_map_changed();
4229 /* convert fpu to frame count */
4231 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4233 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4234 zoom_range_clock->set (frames);
4237 bool const showing_time_selection = selection->time.length() > 0;
4239 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4240 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4241 (*i)->reshow_selection (selection->time);
4245 ZoomChanged (); /* EMIT_SIGNAL */
4247 ArdourCanvas::GtkCanvasViewport* c;
4249 c = get_time_bars_canvas();
4251 c->canvas()->zoomed ();
4253 c = get_track_canvas();
4255 c->canvas()->zoomed ();
4258 if (playhead_cursor) {
4259 playhead_cursor->set_position (playhead_cursor->current_frame ());
4262 refresh_location_display();
4263 _summary->set_overlays_dirty ();
4265 update_marker_labels ();
4271 Editor::queue_visual_videotimeline_update ()
4274 * pending_visual_change.add (VisualChange::VideoTimeline);
4275 * or maybe even more specific: which videotimeline-image
4276 * currently it calls update_video_timeline() to update
4277 * _all outdated_ images on the video-timeline.
4278 * see 'exposeimg()' in video_image_frame.cc
4280 ensure_visual_change_idle_handler ();
4284 Editor::ensure_visual_change_idle_handler ()
4286 if (pending_visual_change.idle_handler_id < 0) {
4287 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4288 pending_visual_change.being_handled = false;
4293 Editor::_idle_visual_changer (void* arg)
4295 return static_cast<Editor*>(arg)->idle_visual_changer ();
4299 Editor::idle_visual_changer ()
4301 /* set_horizontal_position() below (and maybe other calls) call
4302 gtk_main_iteration(), so it's possible that a signal will be handled
4303 half-way through this method. If this signal wants an
4304 idle_visual_changer we must schedule another one after this one, so
4305 mark the idle_handler_id as -1 here to allow that. Also make a note
4306 that we are doing the visual change, so that changes in response to
4307 super-rapid-screen-update can be dropped if we are still processing
4311 pending_visual_change.idle_handler_id = -1;
4312 pending_visual_change.being_handled = true;
4314 VisualChange::Type p = pending_visual_change.pending;
4315 pending_visual_change.pending = (VisualChange::Type) 0;
4317 double const last_time_origin = horizontal_position ();
4320 if (p & VisualChange::ZoomLevel) {
4321 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4323 compute_fixed_ruler_scale ();
4325 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4326 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4328 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4329 current_bbt_points_begin, current_bbt_points_end);
4330 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4331 current_bbt_points_begin, current_bbt_points_end);
4332 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4334 update_video_timeline();
4337 if (p & VisualChange::TimeOrigin) {
4338 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4341 if (p & VisualChange::YOrigin) {
4342 vertical_adjustment.set_value (pending_visual_change.y_origin);
4345 if (last_time_origin == horizontal_position ()) {
4346 /* changed signal not emitted */
4347 update_fixed_rulers ();
4348 redisplay_tempo (true);
4351 if (!(p & VisualChange::ZoomLevel)) {
4352 update_video_timeline();
4355 _summary->set_overlays_dirty ();
4357 pending_visual_change.being_handled = false;
4358 return 0; /* this is always a one-shot call */
4361 struct EditorOrderTimeAxisSorter {
4362 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4363 return a->order () < b->order ();
4368 Editor::sort_track_selection (TrackViewList& sel)
4370 EditorOrderTimeAxisSorter cmp;
4375 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4378 framepos_t where = 0;
4379 EditPoint ep = _edit_point;
4381 if (from_context_menu && (ep == EditAtMouse)) {
4382 return canvas_event_frame (&context_click_event, 0, 0);
4385 if (entered_marker) {
4386 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4387 return entered_marker->position();
4390 if (ignore_playhead && ep == EditAtPlayhead) {
4391 ep = EditAtSelectedMarker;
4395 case EditAtPlayhead:
4396 where = _session->audible_frame();
4397 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4400 case EditAtSelectedMarker:
4401 if (!selection->markers.empty()) {
4403 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4406 where = loc->start();
4410 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4418 if (!mouse_frame (where, ignored)) {
4419 /* XXX not right but what can we do ? */
4423 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4431 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4433 if (!_session) return;
4435 begin_reversible_command (cmd);
4439 if ((tll = transport_loop_location()) == 0) {
4440 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4441 XMLNode &before = _session->locations()->get_state();
4442 _session->locations()->add (loc, true);
4443 _session->set_auto_loop_location (loc);
4444 XMLNode &after = _session->locations()->get_state();
4445 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4447 XMLNode &before = tll->get_state();
4448 tll->set_hidden (false, this);
4449 tll->set (start, end);
4450 XMLNode &after = tll->get_state();
4451 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4454 commit_reversible_command ();
4458 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4460 if (!_session) return;
4462 begin_reversible_command (cmd);
4466 if ((tpl = transport_punch_location()) == 0) {
4467 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4468 XMLNode &before = _session->locations()->get_state();
4469 _session->locations()->add (loc, true);
4470 _session->set_auto_loop_location (loc);
4471 XMLNode &after = _session->locations()->get_state();
4472 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4475 XMLNode &before = tpl->get_state();
4476 tpl->set_hidden (false, this);
4477 tpl->set (start, end);
4478 XMLNode &after = tpl->get_state();
4479 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4482 commit_reversible_command ();
4485 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4486 * @param rs List to which found regions are added.
4487 * @param where Time to look at.
4488 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4491 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4493 const TrackViewList* tracks;
4496 tracks = &track_views;
4501 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4503 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4506 boost::shared_ptr<Track> tr;
4507 boost::shared_ptr<Playlist> pl;
4509 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4511 boost::shared_ptr<RegionList> regions = pl->regions_at (
4512 (framepos_t) floor ( (double) where * tr->speed()));
4514 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4515 RegionView* rv = rtv->view()->find_view (*i);
4526 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4528 const TrackViewList* tracks;
4531 tracks = &track_views;
4536 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4537 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4539 boost::shared_ptr<Track> tr;
4540 boost::shared_ptr<Playlist> pl;
4542 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4544 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4545 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4547 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4549 RegionView* rv = rtv->view()->find_view (*i);
4560 /** Get regions using the following method:
4562 * Make a region list using the selected regions, unless
4563 * the edit point is `mouse' and the mouse is over an unselected
4564 * region. In this case, use just that region.
4566 * If the edit point is not 'mouse', and there are no regions selected,
4567 * search the list of selected tracks and return regions that are under
4568 * the edit point on these tracks. If there are no selected tracks and
4569 * 'No Selection = All Tracks' is active, search all tracks,
4571 * The rationale here is that the mouse edit point is special in that
4572 * its position describes both a time and a track; the other edit
4573 * modes only describe a time. Hence if the edit point is `mouse' we
4574 * ignore selected tracks, as we assume the user means something by
4575 * pointing at a particular track. Also in this case we take note of
4576 * the region directly under the edit point, as there is always just one
4577 * (rather than possibly several with non-mouse edit points).
4581 Editor::get_regions_from_selection_and_edit_point ()
4583 RegionSelection regions;
4585 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4586 regions.add (entered_regionview);
4588 regions = selection->regions;
4592 if (regions.empty() && _edit_point != EditAtMouse) {
4593 TrackViewList tracks = selection->tracks;
4595 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4596 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4597 * is enabled, so consider all tracks
4599 tracks = track_views;
4602 if (!tracks.empty()) {
4603 /* no region selected or entered, but some selected tracks:
4604 * act on all regions on the selected tracks at the edit point
4606 framepos_t const where = get_preferred_edit_position ();
4607 get_regions_at(regions, where, tracks);
4613 /** Start with regions that are selected, or the entered regionview if none are selected.
4614 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4615 * of the regions that we started with.
4619 Editor::get_regions_from_selection_and_entered ()
4621 RegionSelection regions = selection->regions;
4623 if (regions.empty() && entered_regionview) {
4624 regions.add (entered_regionview);
4631 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4633 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4635 RouteTimeAxisView* tatv;
4637 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4639 boost::shared_ptr<Playlist> pl;
4640 vector<boost::shared_ptr<Region> > results;
4642 boost::shared_ptr<Track> tr;
4644 if ((tr = tatv->track()) == 0) {
4649 if ((pl = (tr->playlist())) != 0) {
4650 if (src_comparison) {
4651 pl->get_source_equivalent_regions (region, results);
4653 pl->get_region_list_equivalent_regions (region, results);
4657 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4658 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4659 regions.push_back (marv);
4668 Editor::show_rhythm_ferret ()
4670 if (rhythm_ferret == 0) {
4671 rhythm_ferret = new RhythmFerret(*this);
4674 rhythm_ferret->set_session (_session);
4675 rhythm_ferret->show ();
4676 rhythm_ferret->present ();
4680 Editor::first_idle ()
4682 MessageDialog* dialog = 0;
4684 if (track_views.size() > 1) {
4685 dialog = new MessageDialog (
4687 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4691 ARDOUR_UI::instance()->flush_pending ();
4694 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4698 // first idle adds route children (automation tracks), so we need to redisplay here
4699 _routes->redisplay ();
4706 Editor::_idle_resize (gpointer arg)
4708 return ((Editor*)arg)->idle_resize ();
4712 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4714 if (resize_idle_id < 0) {
4715 resize_idle_id = g_idle_add (_idle_resize, this);
4716 _pending_resize_amount = 0;
4719 /* make a note of the smallest resulting height, so that we can clamp the
4720 lower limit at TimeAxisView::hSmall */
4722 int32_t min_resulting = INT32_MAX;
4724 _pending_resize_amount += h;
4725 _pending_resize_view = view;
4727 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4729 if (selection->tracks.contains (_pending_resize_view)) {
4730 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4731 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4735 if (min_resulting < 0) {
4740 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4741 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4745 /** Handle pending resizing of tracks */
4747 Editor::idle_resize ()
4749 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4751 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4752 selection->tracks.contains (_pending_resize_view)) {
4754 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4755 if (*i != _pending_resize_view) {
4756 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4761 _pending_resize_amount = 0;
4762 _group_tabs->set_dirty ();
4763 resize_idle_id = -1;
4771 ENSURE_GUI_THREAD (*this, &Editor::located);
4774 playhead_cursor->set_position (_session->audible_frame ());
4775 if (_follow_playhead && !_pending_initial_locate) {
4776 reset_x_origin_to_follow_playhead ();
4780 _pending_locate_request = false;
4781 _pending_initial_locate = false;
4785 Editor::region_view_added (RegionView *)
4787 _summary->set_dirty ();
4791 Editor::region_view_removed ()
4793 _summary->set_dirty ();
4797 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4799 TrackViewList::const_iterator j = track_views.begin ();
4800 while (j != track_views.end()) {
4801 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4802 if (rtv && rtv->route() == r) {
4813 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4817 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4818 TimeAxisView* tv = axis_view_from_route (*i);
4828 Editor::add_routes (RouteList& routes)
4830 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4832 RouteTimeAxisView *rtv;
4833 list<RouteTimeAxisView*> new_views;
4835 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4836 boost::shared_ptr<Route> route = (*x);
4838 if (route->is_auditioner() || route->is_monitor()) {
4842 DataType dt = route->input()->default_type();
4844 if (dt == ARDOUR::DataType::AUDIO) {
4845 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4846 rtv->set_route (route);
4847 } else if (dt == ARDOUR::DataType::MIDI) {
4848 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4849 rtv->set_route (route);
4851 throw unknown_type();
4854 new_views.push_back (rtv);
4855 track_views.push_back (rtv);
4857 rtv->effective_gain_display ();
4859 if (internal_editing()) {
4860 rtv->enter_internal_edit_mode ();
4862 rtv->leave_internal_edit_mode ();
4865 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4866 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4869 if (new_views.size() > 0) {
4870 _routes->routes_added (new_views);
4871 _summary->routes_added (new_views);
4874 if (show_editor_mixer_when_tracks_arrive) {
4875 show_editor_mixer (true);
4878 editor_list_button.set_sensitive (true);
4882 Editor::timeaxisview_deleted (TimeAxisView *tv)
4884 if (_session && _session->deletion_in_progress()) {
4885 /* the situation is under control */
4889 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4891 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4893 _routes->route_removed (tv);
4895 if (tv == entered_track) {
4899 TimeAxisView::Children c = tv->get_child_list ();
4900 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4901 if (entered_track == i->get()) {
4906 /* remove it from the list of track views */
4908 TrackViewList::iterator i;
4910 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4911 i = track_views.erase (i);
4914 /* update whatever the current mixer strip is displaying, if revelant */
4916 boost::shared_ptr<Route> route;
4919 route = rtav->route ();
4922 if (current_mixer_strip && current_mixer_strip->route() == route) {
4924 TimeAxisView* next_tv;
4926 if (track_views.empty()) {
4928 } else if (i == track_views.end()) {
4929 next_tv = track_views.front();
4936 set_selected_mixer_strip (*next_tv);
4938 /* make the editor mixer strip go away setting the
4939 * button to inactive (which also unticks the menu option)
4942 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4948 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4950 if (apply_to_selection) {
4951 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4953 TrackSelection::iterator j = i;
4956 hide_track_in_display (*i, false);
4961 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4963 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4964 // this will hide the mixer strip
4965 set_selected_mixer_strip (*tv);
4968 _routes->hide_track_in_display (*tv);
4973 Editor::sync_track_view_list_and_routes ()
4975 track_views = TrackViewList (_routes->views ());
4977 _summary->set_dirty ();
4978 _group_tabs->set_dirty ();
4980 return false; // do not call again (until needed)
4984 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4986 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4991 /** Find a RouteTimeAxisView by the ID of its route */
4993 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4995 RouteTimeAxisView* v;
4997 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4998 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4999 if(v->route()->id() == id) {
5009 Editor::fit_route_group (RouteGroup *g)
5011 TrackViewList ts = axis_views_from_routes (g->route_list ());
5016 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5018 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5021 _session->cancel_audition ();
5025 if (_session->is_auditioning()) {
5026 _session->cancel_audition ();
5027 if (r == last_audition_region) {
5032 _session->audition_region (r);
5033 last_audition_region = r;
5038 Editor::hide_a_region (boost::shared_ptr<Region> r)
5040 r->set_hidden (true);
5044 Editor::show_a_region (boost::shared_ptr<Region> r)
5046 r->set_hidden (false);
5050 Editor::audition_region_from_region_list ()
5052 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5056 Editor::hide_region_from_region_list ()
5058 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5062 Editor::show_region_in_region_list ()
5064 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5068 Editor::step_edit_status_change (bool yn)
5071 start_step_editing ();
5073 stop_step_editing ();
5078 Editor::start_step_editing ()
5080 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5084 Editor::stop_step_editing ()
5086 step_edit_connection.disconnect ();
5090 Editor::check_step_edit ()
5092 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5093 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5095 mtv->check_step_edit ();
5099 return true; // do it again, till we stop
5103 Editor::scroll_press (Direction dir)
5105 ++_scroll_callbacks;
5107 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5108 /* delay the first auto-repeat */
5114 scroll_backward (1);
5122 scroll_tracks_up_line ();
5126 scroll_tracks_down_line ();
5130 /* do hacky auto-repeat */
5131 if (!_scroll_connection.connected ()) {
5133 _scroll_connection = Glib::signal_timeout().connect (
5134 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5137 _scroll_callbacks = 0;
5144 Editor::scroll_release ()
5146 _scroll_connection.disconnect ();
5149 /** Queue a change for the Editor viewport x origin to follow the playhead */
5151 Editor::reset_x_origin_to_follow_playhead ()
5153 framepos_t const frame = playhead_cursor->current_frame ();
5155 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5157 if (_session->transport_speed() < 0) {
5159 if (frame > (current_page_samples() / 2)) {
5160 center_screen (frame-(current_page_samples()/2));
5162 center_screen (current_page_samples()/2);
5169 if (frame < leftmost_frame) {
5171 if (_session->transport_rolling()) {
5172 /* rolling; end up with the playhead at the right of the page */
5173 l = frame - current_page_samples ();
5175 /* not rolling: end up with the playhead 1/4 of the way along the page */
5176 l = frame - current_page_samples() / 4;
5180 if (_session->transport_rolling()) {
5181 /* rolling: end up with the playhead on the left of the page */
5184 /* not rolling: end up with the playhead 3/4 of the way along the page */
5185 l = frame - 3 * current_page_samples() / 4;
5193 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5199 Editor::super_rapid_screen_update ()
5201 if (!_session || !_session->engine().running()) {
5205 /* METERING / MIXER STRIPS */
5207 /* update track meters, if required */
5208 if (is_mapped() && meters_running) {
5209 RouteTimeAxisView* rtv;
5210 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5211 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5212 rtv->fast_update ();
5217 /* and any current mixer strip */
5218 if (current_mixer_strip) {
5219 current_mixer_strip->fast_update ();
5222 /* PLAYHEAD AND VIEWPORT */
5224 framepos_t const frame = _session->audible_frame();
5226 /* There are a few reasons why we might not update the playhead / viewport stuff:
5228 * 1. we don't update things when there's a pending locate request, otherwise
5229 * when the editor requests a locate there is a chance that this method
5230 * will move the playhead before the locate request is processed, causing
5232 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5233 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5236 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5238 last_update_frame = frame;
5240 if (!_dragging_playhead) {
5241 playhead_cursor->set_position (frame);
5244 if (!_stationary_playhead) {
5246 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5247 /* We only do this if we aren't already
5248 handling a visual change (ie if
5249 pending_visual_change.being_handled is
5250 false) so that these requests don't stack
5251 up there are too many of them to handle in
5254 reset_x_origin_to_follow_playhead ();
5259 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5263 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5264 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5265 if (target <= 0.0) {
5268 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5269 target = (target * 0.15) + (current * 0.85);
5275 set_horizontal_position (current);
5284 Editor::session_going_away ()
5286 _have_idled = false;
5288 _session_connections.drop_connections ();
5290 super_rapid_screen_update_connection.disconnect ();
5292 selection->clear ();
5293 cut_buffer->clear ();
5295 clicked_regionview = 0;
5296 clicked_axisview = 0;
5297 clicked_routeview = 0;
5298 entered_regionview = 0;
5300 last_update_frame = 0;
5303 playhead_cursor->hide ();
5305 /* rip everything out of the list displays */
5309 _route_groups->clear ();
5311 /* do this first so that deleting a track doesn't reset cms to null
5312 and thus cause a leak.
5315 if (current_mixer_strip) {
5316 if (current_mixer_strip->get_parent() != 0) {
5317 global_hpacker.remove (*current_mixer_strip);
5319 delete current_mixer_strip;
5320 current_mixer_strip = 0;
5323 /* delete all trackviews */
5325 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5328 track_views.clear ();
5330 zoom_range_clock->set_session (0);
5331 nudge_clock->set_session (0);
5333 editor_list_button.set_active(false);
5334 editor_list_button.set_sensitive(false);
5336 /* clear tempo/meter rulers */
5337 remove_metric_marks ();
5339 clear_marker_display ();
5341 stop_step_editing ();
5343 /* get rid of any existing editor mixer strip */
5345 WindowTitle title(Glib::get_application_name());
5346 title += _("Editor");
5348 set_title (title.get_string());
5350 SessionHandlePtr::session_going_away ();
5355 Editor::show_editor_list (bool yn)
5358 _the_notebook.show ();
5360 _the_notebook.hide ();
5365 Editor::change_region_layering_order (bool from_context_menu)
5367 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5369 if (!clicked_routeview) {
5370 if (layering_order_editor) {
5371 layering_order_editor->hide ();
5376 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5382 boost::shared_ptr<Playlist> pl = track->playlist();
5388 if (layering_order_editor == 0) {
5389 layering_order_editor = new RegionLayeringOrderEditor (*this);
5392 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5393 layering_order_editor->maybe_present ();
5397 Editor::update_region_layering_order_editor ()
5399 if (layering_order_editor && layering_order_editor->is_visible ()) {
5400 change_region_layering_order (true);
5405 Editor::setup_fade_images ()
5407 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5408 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5409 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5410 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5411 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5413 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5414 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5415 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5416 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5417 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5419 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5420 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5421 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5422 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5423 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5425 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5426 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5427 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5428 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5429 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5433 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5435 Editor::action_menu_item (std::string const & name)
5437 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5440 return *manage (a->create_menu_item ());
5444 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5446 EventBox* b = manage (new EventBox);
5447 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5448 Label* l = manage (new Label (name));
5452 _the_notebook.append_page (widget, *b);
5456 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5458 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5459 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5462 if (ev->type == GDK_2BUTTON_PRESS) {
5464 /* double-click on a notebook tab shrinks or expands the notebook */
5466 if (_notebook_shrunk) {
5467 if (pre_notebook_shrink_pane_width) {
5468 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5470 _notebook_shrunk = false;
5472 pre_notebook_shrink_pane_width = edit_pane.get_position();
5474 /* this expands the LHS of the edit pane to cover the notebook
5475 PAGE but leaves the tabs visible.
5477 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5478 _notebook_shrunk = true;
5486 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5488 using namespace Menu_Helpers;
5490 MenuList& items = _control_point_context_menu.items ();
5493 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5494 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5495 if (!can_remove_control_point (item)) {
5496 items.back().set_sensitive (false);
5499 _control_point_context_menu.popup (event->button.button, event->button.time);
5503 Editor::zoom_vertical_modifier_released()
5505 _stepping_axis_view = 0;