2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "canvas/debug.h"
74 #include "canvas/text.h"
76 #include "control_protocol/control_protocol.h"
80 #include "analysis_window.h"
81 #include "audio_clock.h"
82 #include "audio_region_view.h"
83 #include "audio_streamview.h"
84 #include "audio_time_axis.h"
85 #include "automation_time_axis.h"
86 #include "bundle_manager.h"
87 #include "crossfade_edit.h"
91 #include "editor_cursors.h"
92 #include "editor_drag.h"
93 #include "editor_group_tabs.h"
94 #include "editor_locations.h"
95 #include "editor_regions.h"
96 #include "editor_route_groups.h"
97 #include "editor_routes.h"
98 #include "editor_snapshots.h"
99 #include "editor_summary.h"
100 #include "global_port_matrix.h"
101 #include "gui_object.h"
102 #include "gui_thread.h"
103 #include "keyboard.h"
105 #include "midi_time_axis.h"
106 #include "mixer_strip.h"
107 #include "mixer_ui.h"
108 #include "mouse_cursors.h"
109 #include "playlist_selector.h"
110 #include "public_editor.h"
111 #include "region_layering_order_editor.h"
112 #include "rgb_macros.h"
113 #include "rhythm_ferret.h"
114 #include "selection.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 using namespace ARDOUR;
126 using namespace Glib;
127 using namespace Gtkmm2ext;
128 using namespace Editing;
130 using PBD::internationalize;
132 using Gtkmm2ext::Keyboard;
134 const double Editor::timebar_height = 15.0;
136 static const gchar *_snap_type_strings[] = {
138 N_("Timecode Frames"),
139 N_("Timecode Seconds"),
140 N_("Timecode Minutes"),
170 static const gchar *_snap_mode_strings[] = {
177 static const gchar *_edit_point_strings[] = {
184 static const gchar *_zoom_focus_strings[] = {
194 #ifdef USE_RUBBERBAND
195 static const gchar *_rb_opt_strings[] = {
198 N_("Balanced multitimbral mixture"),
199 N_("Unpitched percussion with stable notes"),
200 N_("Crisp monophonic instrumental"),
201 N_("Unpitched solo percussion"),
202 N_("Resample without preserving pitch"),
208 pane_size_watcher (Paned* pane)
210 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
214 Quartz: impossible to access
216 so stop that by preventing it from ever getting too narrow. 35
217 pixels is basically a rough guess at the tab width.
222 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
224 gint pos = pane->get_position ();
226 if (pos > max_width_of_lhs) {
227 pane->set_position (max_width_of_lhs);
232 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
234 /* time display buttons */
235 , minsec_label (_("Mins:Secs"))
236 , bbt_label (_("Bars:Beats"))
237 , timecode_label (_("Timecode"))
238 , samples_label (_("Samples"))
239 , tempo_label (_("Tempo"))
240 , meter_label (_("Meter"))
241 , mark_label (_("Location Markers"))
242 , range_mark_label (_("Range Markers"))
243 , transport_mark_label (_("Loop/Punch Ranges"))
244 , cd_mark_label (_("CD Markers"))
245 , videotl_label (_("Video Timeline"))
246 , edit_packer (4, 4, true)
248 /* the values here don't matter: layout widgets
249 reset them as needed.
252 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
253 , horizontal_adjustment (0.0, 0.0, 1e16)
254 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
256 , controls_layout (unused_adjustment, vertical_adjustment)
258 /* tool bar related */
260 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
262 , toolbar_selection_clock_table (2,3)
264 , automation_mode_button (_("mode"))
266 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
270 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
271 , meters_running(false)
272 , _pending_locate_request (false)
273 , _pending_initial_locate (false)
274 , _last_cut_copy_source_track (0)
276 , _region_selection_change_updates_region_list (true)
277 , _following_mixer_selection (false)
278 , _control_point_toggled_on_press (false)
279 , _stepping_axis_view (0)
283 /* we are a singleton */
285 PublicEditor::_instance = this;
289 selection = new Selection (this);
290 cut_buffer = new Selection (this);
292 clicked_regionview = 0;
293 clicked_axisview = 0;
294 clicked_routeview = 0;
295 clicked_control_point = 0;
296 last_update_frame = 0;
297 pre_press_cursor = 0;
298 _drags = new DragManager (this);
299 current_mixer_strip = 0;
302 snap_type_strings = I18N (_snap_type_strings);
303 snap_mode_strings = I18N (_snap_mode_strings);
304 zoom_focus_strings = I18N (_zoom_focus_strings);
305 edit_point_strings = I18N (_edit_point_strings);
306 #ifdef USE_RUBBERBAND
307 rb_opt_strings = I18N (_rb_opt_strings);
311 snap_threshold = 5.0;
312 bbt_beat_subdivision = 4;
313 _visible_canvas_width = 0;
314 _visible_canvas_height = 0;
315 last_autoscroll_x = 0;
316 last_autoscroll_y = 0;
317 autoscroll_active = false;
318 autoscroll_timeout_tag = -1;
323 current_interthread_info = 0;
324 _show_measures = true;
326 show_gain_after_trim = false;
328 have_pending_keyboard_selection = false;
329 _follow_playhead = true;
330 _stationary_playhead = false;
331 editor_ruler_menu = 0;
332 no_ruler_shown_update = false;
334 range_marker_menu = 0;
335 marker_menu_item = 0;
336 tempo_or_meter_marker_menu = 0;
337 transport_marker_menu = 0;
338 new_transport_marker_menu = 0;
339 editor_mixer_strip_width = Wide;
340 show_editor_mixer_when_tracks_arrive = false;
341 region_edit_menu_split_multichannel_item = 0;
342 region_edit_menu_split_item = 0;
345 current_stepping_trackview = 0;
347 entered_regionview = 0;
349 clear_entered_track = false;
352 button_release_can_deselect = true;
353 _dragging_playhead = false;
354 _dragging_edit_point = false;
355 select_new_marker = false;
357 layering_order_editor = 0;
358 no_save_visual = false;
360 within_track_canvas = false;
362 scrubbing_direction = 0;
366 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
367 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
368 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
369 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
370 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
372 _edit_point = EditAtMouse;
373 _internal_editing = false;
374 current_canvas_cursor = 0;
376 samples_per_pixel = 2048; /* too early to use reset_zoom () */
378 _scroll_callbacks = 0;
380 zoom_focus = ZoomFocusLeft;
381 set_zoom_focus (ZoomFocusLeft);
382 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
384 bbt_label.set_name ("EditorRulerLabel");
385 bbt_label.set_size_request (-1, (int)timebar_height);
386 bbt_label.set_alignment (1.0, 0.5);
387 bbt_label.set_padding (5,0);
389 bbt_label.set_no_show_all();
390 minsec_label.set_name ("EditorRulerLabel");
391 minsec_label.set_size_request (-1, (int)timebar_height);
392 minsec_label.set_alignment (1.0, 0.5);
393 minsec_label.set_padding (5,0);
394 minsec_label.hide ();
395 minsec_label.set_no_show_all();
396 timecode_label.set_name ("EditorRulerLabel");
397 timecode_label.set_size_request (-1, (int)timebar_height);
398 timecode_label.set_alignment (1.0, 0.5);
399 timecode_label.set_padding (5,0);
400 timecode_label.hide ();
401 timecode_label.set_no_show_all();
402 samples_label.set_name ("EditorRulerLabel");
403 samples_label.set_size_request (-1, (int)timebar_height);
404 samples_label.set_alignment (1.0, 0.5);
405 samples_label.set_padding (5,0);
406 samples_label.hide ();
407 samples_label.set_no_show_all();
409 tempo_label.set_name ("EditorRulerLabel");
410 tempo_label.set_size_request (-1, (int)timebar_height);
411 tempo_label.set_alignment (1.0, 0.5);
412 tempo_label.set_padding (5,0);
414 tempo_label.set_no_show_all();
416 meter_label.set_name ("EditorRulerLabel");
417 meter_label.set_size_request (-1, (int)timebar_height);
418 meter_label.set_alignment (1.0, 0.5);
419 meter_label.set_padding (5,0);
421 meter_label.set_no_show_all();
423 mark_label.set_name ("EditorRulerLabel");
424 mark_label.set_size_request (-1, (int)timebar_height);
425 mark_label.set_alignment (1.0, 0.5);
426 mark_label.set_padding (5,0);
428 mark_label.set_no_show_all();
430 cd_mark_label.set_name ("EditorRulerLabel");
431 cd_mark_label.set_size_request (-1, (int)timebar_height);
432 cd_mark_label.set_alignment (1.0, 0.5);
433 cd_mark_label.set_padding (5,0);
434 cd_mark_label.hide();
435 cd_mark_label.set_no_show_all();
437 videotl_bar_height = 4;
438 videotl_label.set_name ("EditorRulerLabel");
439 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
440 videotl_label.set_alignment (1.0, 0.5);
441 videotl_label.set_padding (5,0);
442 videotl_label.hide();
443 videotl_label.set_no_show_all();
445 range_mark_label.set_name ("EditorRulerLabel");
446 range_mark_label.set_size_request (-1, (int)timebar_height);
447 range_mark_label.set_alignment (1.0, 0.5);
448 range_mark_label.set_padding (5,0);
449 range_mark_label.hide();
450 range_mark_label.set_no_show_all();
452 transport_mark_label.set_name ("EditorRulerLabel");
453 transport_mark_label.set_size_request (-1, (int)timebar_height);
454 transport_mark_label.set_alignment (1.0, 0.5);
455 transport_mark_label.set_padding (5,0);
456 transport_mark_label.hide();
457 transport_mark_label.set_no_show_all();
459 initialize_rulers ();
460 initialize_canvas ();
462 _summary = new EditorSummary (this);
464 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
465 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
467 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
469 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
470 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
472 edit_controls_vbox.set_spacing (0);
473 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
474 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
476 HBox* h = manage (new HBox);
477 _group_tabs = new EditorGroupTabs (this);
478 h->pack_start (*_group_tabs, PACK_SHRINK);
479 h->pack_start (edit_controls_vbox);
480 controls_layout.add (*h);
482 controls_layout.set_name ("EditControlsBase");
483 controls_layout.add_events (Gdk::SCROLL_MASK);
484 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
486 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
487 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
489 _cursors = new MouseCursors;
491 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
493 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
494 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
495 pad_line_1->set_outline_color (0xFF0000FF);
501 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
502 time_canvas_vbox.set_size_request (-1, -1);
504 ruler_label_event_box.add (ruler_label_vbox);
505 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
506 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
508 time_bars_event_box.add (time_bars_vbox);
509 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 time_canvas_event_box.add (time_canvas_vbox);
513 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
515 edit_packer.set_col_spacings (0);
516 edit_packer.set_row_spacings (0);
517 edit_packer.set_homogeneous (false);
518 edit_packer.set_border_width (0);
519 edit_packer.set_name ("EditorWindow");
521 /* labels for the rulers */
522 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
523 /* labels for the marker "tracks" (time bars) */
524 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
526 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
528 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
529 /* time bars canvas */
530 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
532 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
534 bottom_hbox.set_border_width (2);
535 bottom_hbox.set_spacing (3);
537 _route_groups = new EditorRouteGroups (this);
538 _routes = new EditorRoutes (this);
539 _regions = new EditorRegions (this);
540 _snapshots = new EditorSnapshots (this);
541 _locations = new EditorLocations (this);
543 add_notebook_page (_("Regions"), _regions->widget ());
544 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
545 add_notebook_page (_("Snapshots"), _snapshots->widget ());
546 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
547 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
549 _the_notebook.set_show_tabs (true);
550 _the_notebook.set_scrollable (true);
551 _the_notebook.popup_disable ();
552 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
553 _the_notebook.show_all ();
555 _notebook_shrunk = false;
557 editor_summary_pane.pack1(edit_packer);
559 Button* summary_arrows_left_left = manage (new Button);
560 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
561 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
562 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
564 Button* summary_arrows_left_right = manage (new Button);
565 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
566 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
567 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 VBox* summary_arrows_left = manage (new VBox);
570 summary_arrows_left->pack_start (*summary_arrows_left_left);
571 summary_arrows_left->pack_start (*summary_arrows_left_right);
573 Button* summary_arrows_right_up = manage (new Button);
574 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
575 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
576 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 Button* summary_arrows_right_down = manage (new Button);
579 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
580 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
581 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 VBox* summary_arrows_right = manage (new VBox);
584 summary_arrows_right->pack_start (*summary_arrows_right_up);
585 summary_arrows_right->pack_start (*summary_arrows_right_down);
587 Frame* summary_frame = manage (new Frame);
588 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
590 summary_frame->add (*_summary);
591 summary_frame->show ();
593 _summary_hbox.pack_start (*summary_arrows_left, false, false);
594 _summary_hbox.pack_start (*summary_frame, true, true);
595 _summary_hbox.pack_start (*summary_arrows_right, false, false);
597 editor_summary_pane.pack2 (_summary_hbox);
599 edit_pane.pack1 (editor_summary_pane, true, true);
600 edit_pane.pack2 (_the_notebook, false, true);
602 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
604 /* XXX: editor_summary_pane might need similar to the edit_pane */
606 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
608 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
609 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
611 top_hbox.pack_start (toolbar_frame);
613 HBox *hbox = manage (new HBox);
614 hbox->pack_start (edit_pane, true, true);
616 global_vpacker.pack_start (top_hbox, false, false);
617 global_vpacker.pack_start (*hbox, true, true);
619 global_hpacker.pack_start (global_vpacker, true, true);
621 set_name ("EditorWindow");
622 add_accel_group (ActionManager::ui_manager->get_accel_group());
624 status_bar_hpacker.show ();
626 vpacker.pack_end (status_bar_hpacker, false, false);
627 vpacker.pack_end (global_hpacker, true, true);
629 /* register actions now so that set_state() can find them and set toggles/checks etc */
632 /* when we start using our own keybinding system for the editor, this
633 * will be uncommented
639 _snap_type = SnapToBeat;
640 set_snap_to (_snap_type);
641 _snap_mode = SnapOff;
642 set_snap_mode (_snap_mode);
643 set_mouse_mode (MouseObject, true);
644 pre_internal_mouse_mode = MouseObject;
645 pre_internal_snap_type = _snap_type;
646 pre_internal_snap_mode = _snap_mode;
647 internal_snap_type = _snap_type;
648 internal_snap_mode = _snap_mode;
649 set_edit_point_preference (EditAtMouse, true);
651 _playlist_selector = new PlaylistSelector();
652 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
654 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
658 nudge_forward_button.set_name ("zoom button");
659 nudge_forward_button.add_elements (ArdourButton::FlatFace);
660 nudge_forward_button.set_image(::get_icon("nudge_right"));
662 nudge_backward_button.set_name ("zoom button");
663 nudge_backward_button.add_elements (ArdourButton::FlatFace);
664 nudge_backward_button.set_image(::get_icon("nudge_left"));
666 fade_context_menu.set_name ("ArdourContextMenu");
668 /* icons, titles, WM stuff */
670 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
671 Glib::RefPtr<Gdk::Pixbuf> icon;
673 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
683 window_icons.push_back (icon);
685 if (!window_icons.empty()) {
686 // set_icon_list (window_icons);
687 set_default_icon_list (window_icons);
690 WindowTitle title(Glib::get_application_name());
691 title += _("Editor");
692 set_title (title.get_string());
693 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
696 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
698 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
699 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
701 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
703 /* allow external control surfaces/protocols to do various things */
705 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
706 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
707 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
708 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
709 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
710 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
711 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
712 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
713 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
714 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
715 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
716 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
717 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
718 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
720 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
721 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
722 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
723 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
724 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
726 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
728 /* problematic: has to return a value and thus cannot be x-thread */
730 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
732 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
734 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
736 _ignore_region_action = false;
737 _last_region_menu_was_main = false;
738 _popup_region_menu_item = 0;
740 _show_marker_lines = false;
741 _over_region_trim_target = false;
743 /* Button bindings */
745 button_bindings = new Bindings;
747 XMLNode* node = button_settings();
749 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
750 button_bindings->load (**i);
757 setup_fade_images ();
762 delete button_bindings;
764 delete _route_groups;
765 delete _time_bars_canvas_viewport;
766 delete _track_canvas_viewport;
771 Editor::button_settings () const
773 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
774 XMLNode* node = find_named_node (*settings, X_("Buttons"));
777 node = new XMLNode (X_("Buttons"));
784 Editor::add_toplevel_controls (Container& cont)
786 vpacker.pack_start (cont, false, false);
791 Editor::get_smart_mode () const
793 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
797 Editor::catch_vanishing_regionview (RegionView *rv)
799 /* note: the selection will take care of the vanishing
800 audioregionview by itself.
803 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
807 if (clicked_regionview == rv) {
808 clicked_regionview = 0;
811 if (entered_regionview == rv) {
812 set_entered_regionview (0);
815 if (!_all_region_actions_sensitized) {
816 sensitize_all_region_actions (true);
819 _over_region_trim_target = false;
823 Editor::set_entered_regionview (RegionView* rv)
825 if (rv == entered_regionview) {
829 if (entered_regionview) {
830 entered_regionview->exited ();
833 if ((entered_regionview = rv) != 0) {
834 entered_regionview->entered (internal_editing ());
837 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
838 /* This RegionView entry might have changed what region actions
839 are allowed, so sensitize them all in case a key is pressed.
841 sensitize_all_region_actions (true);
846 Editor::set_entered_track (TimeAxisView* tav)
849 entered_track->exited ();
852 if ((entered_track = tav) != 0) {
853 entered_track->entered ();
858 Editor::show_window ()
860 if (!is_visible ()) {
863 /* XXX: this is a bit unfortunate; it would probably
864 be nicer if we could just call show () above rather
865 than needing the show_all ()
868 /* re-hide stuff if necessary */
869 editor_list_button_toggled ();
870 parameter_changed ("show-summary");
871 parameter_changed ("show-group-tabs");
872 parameter_changed ("show-zoom-tools");
874 /* now reset all audio_time_axis heights, because widgets might need
880 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
881 tv = (static_cast<TimeAxisView*>(*i));
885 if (current_mixer_strip) {
886 current_mixer_strip->hide_things ();
887 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
895 Editor::instant_save ()
897 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
902 _session->add_instant_xml(get_state());
904 Config->add_instant_xml(get_state());
909 Editor::zoom_adjustment_changed ()
915 double fpu = zoom_range_clock->current_duration() / _visible_canvas_width;
916 bool clamped = clamp_samples_per_pixel (fpu);
919 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
926 Editor::control_vertical_zoom_in_all ()
928 tav_zoom_smooth (false, true);
932 Editor::control_vertical_zoom_out_all ()
934 tav_zoom_smooth (true, true);
938 Editor::control_vertical_zoom_in_selected ()
940 tav_zoom_smooth (false, false);
944 Editor::control_vertical_zoom_out_selected ()
946 tav_zoom_smooth (true, false);
950 Editor::control_view (uint32_t view)
952 goto_visual_state (view);
956 Editor::control_unselect ()
958 selection->clear_tracks ();
962 Editor::control_select (uint32_t rid, Selection::Operation op)
964 /* handles the (static) signal from the ControlProtocol class that
965 * requests setting the selected track to a given RID
972 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
978 TimeAxisView* tav = axis_view_from_route (r);
983 selection->add (tav);
985 case Selection::Toggle:
986 selection->toggle (tav);
988 case Selection::Extend:
991 selection->set (tav);
995 selection->clear_tracks ();
1000 Editor::control_step_tracks_up ()
1002 scroll_tracks_up_line ();
1006 Editor::control_step_tracks_down ()
1008 scroll_tracks_down_line ();
1012 Editor::control_scroll (float fraction)
1014 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1020 double step = fraction * current_page_samples();
1023 _control_scroll_target is an optional<T>
1025 it acts like a pointer to an framepos_t, with
1026 a operator conversion to boolean to check
1027 that it has a value could possibly use
1028 playhead_cursor->current_frame to store the
1029 value and a boolean in the class to know
1030 when it's out of date
1033 if (!_control_scroll_target) {
1034 _control_scroll_target = _session->transport_frame();
1035 _dragging_playhead = true;
1038 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1039 *_control_scroll_target = 0;
1040 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1041 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1043 *_control_scroll_target += (framepos_t) floor (step);
1046 /* move visuals, we'll catch up with it later */
1048 playhead_cursor->set_position (*_control_scroll_target);
1049 UpdateAllTransportClocks (*_control_scroll_target);
1051 if (*_control_scroll_target > (current_page_samples() / 2)) {
1052 /* try to center PH in window */
1053 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1059 Now we do a timeout to actually bring the session to the right place
1060 according to the playhead. This is to avoid reading disk buffers on every
1061 call to control_scroll, which is driven by ScrollTimeline and therefore
1062 probably by a control surface wheel which can generate lots of events.
1064 /* cancel the existing timeout */
1066 control_scroll_connection.disconnect ();
1068 /* add the next timeout */
1070 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1074 Editor::deferred_control_scroll (framepos_t /*target*/)
1076 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1077 // reset for next stream
1078 _control_scroll_target = boost::none;
1079 _dragging_playhead = false;
1084 Editor::access_action (std::string action_group, std::string action_item)
1090 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1093 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1101 Editor::on_realize ()
1103 Window::on_realize ();
1108 Editor::map_position_change (framepos_t frame)
1110 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1112 if (_session == 0) {
1116 if (_follow_playhead) {
1117 center_screen (frame);
1120 playhead_cursor->set_position (frame);
1124 Editor::center_screen (framepos_t frame)
1126 double const page = _visible_canvas_width * samples_per_pixel;
1128 /* if we're off the page, then scroll.
1131 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1132 center_screen_internal (frame, page);
1137 Editor::center_screen_internal (framepos_t frame, float page)
1142 frame -= (framepos_t) page;
1147 reset_x_origin (frame);
1152 Editor::update_title ()
1154 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1157 bool dirty = _session->dirty();
1159 string session_name;
1161 if (_session->snap_name() != _session->name()) {
1162 session_name = _session->snap_name();
1164 session_name = _session->name();
1168 session_name = "*" + session_name;
1171 WindowTitle title(session_name);
1172 title += Glib::get_application_name();
1173 set_title (title.get_string());
1175 /* ::session_going_away() will have taken care of it */
1180 Editor::set_session (Session *t)
1182 SessionHandlePtr::set_session (t);
1188 zoom_range_clock->set_session (_session);
1189 _playlist_selector->set_session (_session);
1190 nudge_clock->set_session (_session);
1191 _summary->set_session (_session);
1192 _group_tabs->set_session (_session);
1193 _route_groups->set_session (_session);
1194 _regions->set_session (_session);
1195 _snapshots->set_session (_session);
1196 _routes->set_session (_session);
1197 _locations->set_session (_session);
1199 if (rhythm_ferret) {
1200 rhythm_ferret->set_session (_session);
1203 if (analysis_window) {
1204 analysis_window->set_session (_session);
1208 sfbrowser->set_session (_session);
1211 compute_fixed_ruler_scale ();
1213 /* Make sure we have auto loop and auto punch ranges */
1215 Location* loc = _session->locations()->auto_loop_location();
1217 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1219 if (loc->start() == loc->end()) {
1220 loc->set_end (loc->start() + 1);
1223 _session->locations()->add (loc, false);
1224 _session->set_auto_loop_location (loc);
1227 loc->set_name (_("Loop"));
1230 loc = _session->locations()->auto_punch_location();
1233 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1235 if (loc->start() == loc->end()) {
1236 loc->set_end (loc->start() + 1);
1239 _session->locations()->add (loc, false);
1240 _session->set_auto_punch_location (loc);
1243 loc->set_name (_("Punch"));
1246 refresh_location_display ();
1248 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1249 the selected Marker; this needs the LocationMarker list to be available.
1251 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1252 set_state (*node, Stateful::loading_state_version);
1254 /* catch up with the playhead */
1256 _session->request_locate (playhead_cursor->current_frame ());
1257 _pending_initial_locate = true;
1261 /* These signals can all be emitted by a non-GUI thread. Therefore the
1262 handlers for them must not attempt to directly interact with the GUI,
1263 but use Gtkmm2ext::UI::instance()->call_slot();
1266 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1267 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1268 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1269 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1270 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1271 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1272 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1273 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1274 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1275 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1276 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1277 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1278 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1279 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1281 playhead_cursor->show ();
1283 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1284 Config->map_parameters (pc);
1285 _session->config.map_parameters (pc);
1287 restore_ruler_visibility ();
1288 //tempo_map_changed (PropertyChange (0));
1289 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1291 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1292 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1295 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1296 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1299 switch (_snap_type) {
1300 case SnapToRegionStart:
1301 case SnapToRegionEnd:
1302 case SnapToRegionSync:
1303 case SnapToRegionBoundary:
1304 build_region_boundary_cache ();
1311 /* register for undo history */
1312 _session->register_with_memento_command_factory(id(), this);
1314 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1316 start_updating_meters ();
1320 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1322 if (a->get_name() == "RegionMenu") {
1323 /* When the main menu's region menu is opened, we setup the actions so that they look right
1324 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1325 so we resensitize all region actions when the entered regionview or the region selection
1326 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1327 happens after the region context menu is opened. So we set a flag here, too.
1331 sensitize_the_right_region_actions ();
1332 _last_region_menu_was_main = true;
1337 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1339 using namespace Menu_Helpers;
1341 void (Editor::*emf)(FadeShape);
1342 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1345 images = &_xfade_in_images;
1346 emf = &Editor::set_fade_in_shape;
1348 images = &_xfade_out_images;
1349 emf = &Editor::set_fade_out_shape;
1354 _("Linear (for highly correlated material)"),
1355 *(*images)[FadeLinear],
1356 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1360 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1364 _("Constant power"),
1365 *(*images)[FadeConstantPower],
1366 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1369 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1374 *(*images)[FadeSymmetric],
1375 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1379 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1384 *(*images)[FadeSlow],
1385 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1388 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1393 *(*images)[FadeFast],
1394 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1397 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 /** Pop up a context menu for when the user clicks on a start crossfade */
1402 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1404 using namespace Menu_Helpers;
1406 MenuList& items (xfade_in_context_menu.items());
1408 if (items.empty()) {
1409 fill_xfade_menu (items, true);
1412 xfade_in_context_menu.popup (button, time);
1415 /** Pop up a context menu for when the user clicks on an end crossfade */
1417 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1419 using namespace Menu_Helpers;
1421 MenuList& items (xfade_out_context_menu.items());
1423 if (items.empty()) {
1424 fill_xfade_menu (items, false);
1427 xfade_out_context_menu.popup (button, time);
1431 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1433 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1435 using namespace Menu_Helpers;
1436 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1439 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1443 MenuList& items (fade_context_menu.items());
1446 switch (item_type) {
1448 case FadeInHandleItem:
1449 if (arv->audio_region()->fade_in_active()) {
1450 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1452 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1455 items.push_back (SeparatorElem());
1457 if (Profile->get_sae()) {
1459 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1460 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1467 *_fade_in_images[FadeLinear],
1468 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1472 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 *_fade_in_images[FadeSlow],
1478 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1481 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1486 *_fade_in_images[FadeFast],
1487 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1490 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1495 *_fade_in_images[FadeSymmetric],
1496 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1501 _("Constant power"),
1502 *_fade_in_images[FadeConstantPower],
1503 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1506 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1512 case FadeOutHandleItem:
1513 if (arv->audio_region()->fade_out_active()) {
1514 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1516 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1519 items.push_back (SeparatorElem());
1521 if (Profile->get_sae()) {
1522 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1523 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1529 *_fade_out_images[FadeLinear],
1530 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1534 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1539 *_fade_out_images[FadeSlow],
1540 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1543 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1548 *_fade_out_images[FadeFast],
1549 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1552 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1557 *_fade_out_images[FadeSymmetric],
1558 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1563 _("Constant power"),
1564 *_fade_out_images[FadeConstantPower],
1565 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1568 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1574 fatal << _("programming error: ")
1575 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1580 fade_context_menu.popup (button, time);
1584 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1586 using namespace Menu_Helpers;
1587 Menu* (Editor::*build_menu_function)();
1590 switch (item_type) {
1592 case RegionViewName:
1593 case RegionViewNameHighlight:
1594 case LeftFrameHandle:
1595 case RightFrameHandle:
1596 if (with_selection) {
1597 build_menu_function = &Editor::build_track_selection_context_menu;
1599 build_menu_function = &Editor::build_track_region_context_menu;
1604 if (with_selection) {
1605 build_menu_function = &Editor::build_track_selection_context_menu;
1607 build_menu_function = &Editor::build_track_context_menu;
1612 if (clicked_routeview->track()) {
1613 build_menu_function = &Editor::build_track_context_menu;
1615 build_menu_function = &Editor::build_track_bus_context_menu;
1620 /* probably shouldn't happen but if it does, we don't care */
1624 menu = (this->*build_menu_function)();
1625 menu->set_name ("ArdourContextMenu");
1627 /* now handle specific situations */
1629 switch (item_type) {
1631 case RegionViewName:
1632 case RegionViewNameHighlight:
1633 case LeftFrameHandle:
1634 case RightFrameHandle:
1635 if (!with_selection) {
1636 if (region_edit_menu_split_item) {
1637 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1638 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1640 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1643 if (region_edit_menu_split_multichannel_item) {
1644 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1645 region_edit_menu_split_multichannel_item->set_sensitive (true);
1647 region_edit_menu_split_multichannel_item->set_sensitive (false);
1660 /* probably shouldn't happen but if it does, we don't care */
1664 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1666 /* Bounce to disk */
1668 using namespace Menu_Helpers;
1669 MenuList& edit_items = menu->items();
1671 edit_items.push_back (SeparatorElem());
1673 switch (clicked_routeview->audio_track()->freeze_state()) {
1674 case AudioTrack::NoFreeze:
1675 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1678 case AudioTrack::Frozen:
1679 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1682 case AudioTrack::UnFrozen:
1683 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1689 if (item_type == StreamItem && clicked_routeview) {
1690 clicked_routeview->build_underlay_menu(menu);
1693 /* When the region menu is opened, we setup the actions so that they look right
1696 sensitize_the_right_region_actions ();
1697 _last_region_menu_was_main = false;
1699 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1700 menu->popup (button, time);
1704 Editor::build_track_context_menu ()
1706 using namespace Menu_Helpers;
1708 MenuList& edit_items = track_context_menu.items();
1711 add_dstream_context_items (edit_items);
1712 return &track_context_menu;
1716 Editor::build_track_bus_context_menu ()
1718 using namespace Menu_Helpers;
1720 MenuList& edit_items = track_context_menu.items();
1723 add_bus_context_items (edit_items);
1724 return &track_context_menu;
1728 Editor::build_track_region_context_menu ()
1730 using namespace Menu_Helpers;
1731 MenuList& edit_items = track_region_context_menu.items();
1734 /* we've just cleared the track region context menu, so the menu that these
1735 two items were on will have disappeared; stop them dangling.
1737 region_edit_menu_split_item = 0;
1738 region_edit_menu_split_multichannel_item = 0;
1740 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1743 boost::shared_ptr<Track> tr;
1744 boost::shared_ptr<Playlist> pl;
1746 if ((tr = rtv->track())) {
1747 add_region_context_items (edit_items, tr);
1751 add_dstream_context_items (edit_items);
1753 return &track_region_context_menu;
1757 Editor::analyze_region_selection ()
1759 if (analysis_window == 0) {
1760 analysis_window = new AnalysisWindow();
1763 analysis_window->set_session(_session);
1765 analysis_window->show_all();
1768 analysis_window->set_regionmode();
1769 analysis_window->analyze();
1771 analysis_window->present();
1775 Editor::analyze_range_selection()
1777 if (analysis_window == 0) {
1778 analysis_window = new AnalysisWindow();
1781 analysis_window->set_session(_session);
1783 analysis_window->show_all();
1786 analysis_window->set_rangemode();
1787 analysis_window->analyze();
1789 analysis_window->present();
1793 Editor::build_track_selection_context_menu ()
1795 using namespace Menu_Helpers;
1796 MenuList& edit_items = track_selection_context_menu.items();
1797 edit_items.clear ();
1799 add_selection_context_items (edit_items);
1800 // edit_items.push_back (SeparatorElem());
1801 // add_dstream_context_items (edit_items);
1803 return &track_selection_context_menu;
1807 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1809 using namespace Menu_Helpers;
1811 /* OK, stick the region submenu at the top of the list, and then add
1815 RegionSelection rs = get_regions_from_selection_and_entered ();
1817 string::size_type pos = 0;
1818 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1820 /* we have to hack up the region name because "_" has a special
1821 meaning for menu titles.
1824 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1825 menu_item_name.replace (pos, 1, "__");
1829 if (_popup_region_menu_item == 0) {
1830 _popup_region_menu_item = new MenuItem (menu_item_name);
1831 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1832 _popup_region_menu_item->show ();
1834 _popup_region_menu_item->set_label (menu_item_name);
1837 const framepos_t position = get_preferred_edit_position (false, true);
1839 edit_items.push_back (*_popup_region_menu_item);
1840 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1841 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1843 edit_items.push_back (SeparatorElem());
1846 /** Add context menu items relevant to selection ranges.
1847 * @param edit_items List to add the items to.
1850 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1852 using namespace Menu_Helpers;
1854 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1855 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1857 edit_items.push_back (SeparatorElem());
1858 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1860 edit_items.push_back (SeparatorElem());
1862 edit_items.push_back (
1864 _("Move Range Start to Previous Region Boundary"),
1865 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1869 edit_items.push_back (
1871 _("Move Range Start to Next Region Boundary"),
1872 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1876 edit_items.push_back (
1878 _("Move Range End to Previous Region Boundary"),
1879 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1883 edit_items.push_back (
1885 _("Move Range End to Next Region Boundary"),
1886 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1890 edit_items.push_back (SeparatorElem());
1891 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1892 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1894 edit_items.push_back (SeparatorElem());
1895 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1897 edit_items.push_back (SeparatorElem());
1898 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1899 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1901 edit_items.push_back (SeparatorElem());
1902 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1904 edit_items.push_back (SeparatorElem());
1905 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1906 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1907 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1909 edit_items.push_back (SeparatorElem());
1910 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1911 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1912 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1913 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1914 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1919 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1921 using namespace Menu_Helpers;
1925 Menu *play_menu = manage (new Menu);
1926 MenuList& play_items = play_menu->items();
1927 play_menu->set_name ("ArdourContextMenu");
1929 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1930 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1931 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1932 play_items.push_back (SeparatorElem());
1933 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1935 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1939 Menu *select_menu = manage (new Menu);
1940 MenuList& select_items = select_menu->items();
1941 select_menu->set_name ("ArdourContextMenu");
1943 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1944 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1945 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1946 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1947 select_items.push_back (SeparatorElem());
1948 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1949 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1950 select_items.push_back (SeparatorElem());
1951 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1952 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1953 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1954 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1955 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1956 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1957 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1959 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1963 Menu *cutnpaste_menu = manage (new Menu);
1964 MenuList& cutnpaste_items = cutnpaste_menu->items();
1965 cutnpaste_menu->set_name ("ArdourContextMenu");
1967 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1968 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1969 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1971 cutnpaste_items.push_back (SeparatorElem());
1973 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1974 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1976 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1978 /* Adding new material */
1980 edit_items.push_back (SeparatorElem());
1981 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1982 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1986 Menu *nudge_menu = manage (new Menu());
1987 MenuList& nudge_items = nudge_menu->items();
1988 nudge_menu->set_name ("ArdourContextMenu");
1990 edit_items.push_back (SeparatorElem());
1991 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1992 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1993 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1994 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1996 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2000 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2002 using namespace Menu_Helpers;
2006 Menu *play_menu = manage (new Menu);
2007 MenuList& play_items = play_menu->items();
2008 play_menu->set_name ("ArdourContextMenu");
2010 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2011 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2012 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2016 Menu *select_menu = manage (new Menu);
2017 MenuList& select_items = select_menu->items();
2018 select_menu->set_name ("ArdourContextMenu");
2020 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2021 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2022 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2023 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2024 select_items.push_back (SeparatorElem());
2025 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2026 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2027 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2028 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2030 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2034 Menu *cutnpaste_menu = manage (new Menu);
2035 MenuList& cutnpaste_items = cutnpaste_menu->items();
2036 cutnpaste_menu->set_name ("ArdourContextMenu");
2038 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2039 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2040 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2042 Menu *nudge_menu = manage (new Menu());
2043 MenuList& nudge_items = nudge_menu->items();
2044 nudge_menu->set_name ("ArdourContextMenu");
2046 edit_items.push_back (SeparatorElem());
2047 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2048 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2049 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2050 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2052 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2056 Editor::snap_type() const
2062 Editor::snap_mode() const
2068 Editor::set_snap_to (SnapType st)
2070 unsigned int snap_ind = (unsigned int)st;
2074 if (snap_ind > snap_type_strings.size() - 1) {
2076 _snap_type = (SnapType)snap_ind;
2079 string str = snap_type_strings[snap_ind];
2081 if (str != snap_type_selector.get_active_text()) {
2082 snap_type_selector.set_active_text (str);
2087 switch (_snap_type) {
2088 case SnapToBeatDiv128:
2089 case SnapToBeatDiv64:
2090 case SnapToBeatDiv32:
2091 case SnapToBeatDiv28:
2092 case SnapToBeatDiv24:
2093 case SnapToBeatDiv20:
2094 case SnapToBeatDiv16:
2095 case SnapToBeatDiv14:
2096 case SnapToBeatDiv12:
2097 case SnapToBeatDiv10:
2098 case SnapToBeatDiv8:
2099 case SnapToBeatDiv7:
2100 case SnapToBeatDiv6:
2101 case SnapToBeatDiv5:
2102 case SnapToBeatDiv4:
2103 case SnapToBeatDiv3:
2104 case SnapToBeatDiv2: {
2105 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2106 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2108 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2109 current_bbt_points_begin, current_bbt_points_end);
2110 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2111 current_bbt_points_begin, current_bbt_points_end);
2112 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2116 case SnapToRegionStart:
2117 case SnapToRegionEnd:
2118 case SnapToRegionSync:
2119 case SnapToRegionBoundary:
2120 build_region_boundary_cache ();
2128 SnapChanged (); /* EMIT SIGNAL */
2132 Editor::set_snap_mode (SnapMode mode)
2134 string str = snap_mode_strings[(int)mode];
2136 if (_internal_editing) {
2137 internal_snap_mode = mode;
2139 pre_internal_snap_mode = mode;
2144 if (str != snap_mode_selector.get_active_text ()) {
2145 snap_mode_selector.set_active_text (str);
2151 Editor::set_edit_point_preference (EditPoint ep, bool force)
2153 bool changed = (_edit_point != ep);
2156 string str = edit_point_strings[(int)ep];
2158 if (str != edit_point_selector.get_active_text ()) {
2159 edit_point_selector.set_active_text (str);
2162 set_canvas_cursor ();
2164 if (!force && !changed) {
2168 const char* action=NULL;
2170 switch (_edit_point) {
2171 case EditAtPlayhead:
2172 action = "edit-at-playhead";
2174 case EditAtSelectedMarker:
2175 action = "edit-at-marker";
2178 action = "edit-at-mouse";
2182 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2184 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2188 bool in_track_canvas;
2190 if (!mouse_frame (foo, in_track_canvas)) {
2191 in_track_canvas = false;
2194 reset_canvas_action_sensitivity (in_track_canvas);
2200 Editor::set_state (const XMLNode& node, int /*version*/)
2202 const XMLProperty* prop;
2209 g.base_width = default_width;
2210 g.base_height = default_height;
2214 if ((geometry = find_named_node (node, "geometry")) != 0) {
2218 if ((prop = geometry->property("x_size")) == 0) {
2219 prop = geometry->property ("x-size");
2222 g.base_width = atoi(prop->value());
2224 if ((prop = geometry->property("y_size")) == 0) {
2225 prop = geometry->property ("y-size");
2228 g.base_height = atoi(prop->value());
2231 if ((prop = geometry->property ("x_pos")) == 0) {
2232 prop = geometry->property ("x-pos");
2235 x = atoi (prop->value());
2238 if ((prop = geometry->property ("y_pos")) == 0) {
2239 prop = geometry->property ("y-pos");
2242 y = atoi (prop->value());
2246 set_default_size (g.base_width, g.base_height);
2249 if (_session && (prop = node.property ("playhead"))) {
2251 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2252 playhead_cursor->set_position (pos);
2254 playhead_cursor->set_position (0);
2257 if ((prop = node.property ("mixer-width"))) {
2258 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2261 if ((prop = node.property ("zoom-focus"))) {
2262 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2265 if ((prop = node.property ("zoom"))) {
2266 reset_zoom (PBD::atof (prop->value()));
2268 reset_zoom (samples_per_pixel);
2271 if ((prop = node.property ("snap-to"))) {
2272 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2275 if ((prop = node.property ("snap-mode"))) {
2276 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2279 if ((prop = node.property ("internal-snap-to"))) {
2280 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2283 if ((prop = node.property ("internal-snap-mode"))) {
2284 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2287 if ((prop = node.property ("pre-internal-snap-to"))) {
2288 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2292 if ((prop = node.property ("pre-internal-snap-mode"))) {
2293 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2296 if ((prop = node.property ("mouse-mode"))) {
2297 MouseMode m = str2mousemode(prop->value());
2298 set_mouse_mode (m, true);
2300 set_mouse_mode (MouseObject, true);
2303 if ((prop = node.property ("left-frame")) != 0) {
2305 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2309 reset_x_origin (pos);
2313 if ((prop = node.property ("y-origin")) != 0) {
2314 reset_y_origin (atof (prop->value ()));
2317 if ((prop = node.property ("internal-edit"))) {
2318 bool yn = string_is_affirmative (prop->value());
2319 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2321 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322 tact->set_active (!yn);
2323 tact->set_active (yn);
2327 if ((prop = node.property ("join-object-range"))) {
2328 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2329 bool yn = string_is_affirmative (prop->value());
2331 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2332 tact->set_active (!yn);
2333 tact->set_active (yn);
2335 set_mouse_mode(mouse_mode, true);
2338 if ((prop = node.property ("edit-point"))) {
2339 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2342 if ((prop = node.property ("show-measures"))) {
2343 bool yn = string_is_affirmative (prop->value());
2344 _show_measures = yn;
2345 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2347 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2348 /* do it twice to force the change */
2349 tact->set_active (!yn);
2350 tact->set_active (yn);
2354 if ((prop = node.property ("follow-playhead"))) {
2355 bool yn = string_is_affirmative (prop->value());
2356 set_follow_playhead (yn);
2357 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2359 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2360 if (tact->get_active() != yn) {
2361 tact->set_active (yn);
2366 if ((prop = node.property ("stationary-playhead"))) {
2367 bool yn = string_is_affirmative (prop->value());
2368 set_stationary_playhead (yn);
2369 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2371 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2372 if (tact->get_active() != yn) {
2373 tact->set_active (yn);
2378 if ((prop = node.property ("region-list-sort-type"))) {
2379 RegionListSortType st;
2380 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2383 if ((prop = node.property ("show-editor-mixer"))) {
2385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2388 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2389 bool yn = string_is_affirmative (prop->value());
2391 /* do it twice to force the change */
2393 tact->set_active (!yn);
2394 tact->set_active (yn);
2397 if ((prop = node.property ("show-editor-list"))) {
2399 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2402 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2403 bool yn = string_is_affirmative (prop->value());
2405 /* do it twice to force the change */
2407 tact->set_active (!yn);
2408 tact->set_active (yn);
2411 if ((prop = node.property (X_("editor-list-page")))) {
2412 _the_notebook.set_current_page (atoi (prop->value ()));
2415 if ((prop = node.property (X_("show-marker-lines")))) {
2416 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2418 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2419 bool yn = string_is_affirmative (prop->value ());
2421 tact->set_active (!yn);
2422 tact->set_active (yn);
2425 XMLNodeList children = node.children ();
2426 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2427 selection->set_state (**i, Stateful::current_state_version);
2428 _regions->set_state (**i);
2431 if ((prop = node.property ("maximised"))) {
2432 bool yn = string_is_affirmative (prop->value());
2434 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2438 if ((prop = node.property ("nudge-clock-value"))) {
2440 sscanf (prop->value().c_str(), "%" PRId64, &f);
2441 nudge_clock->set (f);
2443 nudge_clock->set_mode (AudioClock::Timecode);
2444 nudge_clock->set (_session->frame_rate() * 5, true);
2451 Editor::get_state ()
2453 XMLNode* node = new XMLNode ("Editor");
2456 id().print (buf, sizeof (buf));
2457 node->add_property ("id", buf);
2459 if (is_realized()) {
2460 Glib::RefPtr<Gdk::Window> win = get_window();
2462 int x, y, width, height;
2463 win->get_root_origin(x, y);
2464 win->get_size(width, height);
2466 XMLNode* geometry = new XMLNode ("geometry");
2468 snprintf(buf, sizeof(buf), "%d", width);
2469 geometry->add_property("x-size", string(buf));
2470 snprintf(buf, sizeof(buf), "%d", height);
2471 geometry->add_property("y-size", string(buf));
2472 snprintf(buf, sizeof(buf), "%d", x);
2473 geometry->add_property("x-pos", string(buf));
2474 snprintf(buf, sizeof(buf), "%d", y);
2475 geometry->add_property("y-pos", string(buf));
2476 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2477 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2478 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2479 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2480 geometry->add_property("edit-vertical-pane-pos", string(buf));
2482 node->add_child_nocopy (*geometry);
2485 maybe_add_mixer_strip_width (*node);
2487 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2488 snprintf (buf, sizeof(buf), "%f", samples_per_pixel);
2489 node->add_property ("zoom", buf);
2490 node->add_property ("snap-to", enum_2_string (_snap_type));
2491 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2492 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2493 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2494 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2495 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2496 node->add_property ("edit-point", enum_2_string (_edit_point));
2498 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2499 node->add_property ("playhead", buf);
2500 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2501 node->add_property ("left-frame", buf);
2502 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2503 node->add_property ("y-origin", buf);
2505 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2506 node->add_property ("maximised", _maximised ? "yes" : "no");
2507 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2508 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2509 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2510 node->add_property ("mouse-mode", enum2str(mouse_mode));
2511 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2512 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2514 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2516 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2517 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2520 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2522 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2523 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2526 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2527 node->add_property (X_("editor-list-page"), buf);
2529 if (button_bindings) {
2530 XMLNode* bb = new XMLNode (X_("Buttons"));
2531 button_bindings->save (*bb);
2532 node->add_child_nocopy (*bb);
2535 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2537 node->add_child_nocopy (selection->get_state ());
2538 node->add_child_nocopy (_regions->get_state ());
2540 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2541 node->add_property ("nudge-clock-value", buf);
2548 /** @param y y offset from the top of all trackviews.
2549 * @return pair: TimeAxisView that y is over, layer index.
2550 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2551 * in stacked or expanded region display mode, otherwise 0.
2553 std::pair<TimeAxisView *, double>
2554 Editor::trackview_by_y_position (double y)
2556 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2558 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2564 return std::make_pair ( (TimeAxisView *) 0, 0);
2567 /** Snap a position to the grid, if appropriate, taking into account current
2568 * grid settings and also the state of any snap modifier keys that may be pressed.
2569 * @param start Position to snap.
2570 * @param event Event to get current key modifier information from, or 0.
2573 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2575 if (!_session || !event) {
2579 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2580 if (_snap_mode == SnapOff) {
2581 snap_to_internal (start, direction, for_mark);
2584 if (_snap_mode != SnapOff) {
2585 snap_to_internal (start, direction, for_mark);
2591 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2593 if (!_session || _snap_mode == SnapOff) {
2597 snap_to_internal (start, direction, for_mark);
2601 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2603 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2604 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2606 switch (_snap_type) {
2607 case SnapToTimecodeFrame:
2608 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2609 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2611 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2615 case SnapToTimecodeSeconds:
2616 if (_session->config.get_timecode_offset_negative()) {
2617 start += _session->config.get_timecode_offset ();
2619 start -= _session->config.get_timecode_offset ();
2621 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2622 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2624 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2627 if (_session->config.get_timecode_offset_negative()) {
2628 start -= _session->config.get_timecode_offset ();
2630 start += _session->config.get_timecode_offset ();
2634 case SnapToTimecodeMinutes:
2635 if (_session->config.get_timecode_offset_negative()) {
2636 start += _session->config.get_timecode_offset ();
2638 start -= _session->config.get_timecode_offset ();
2640 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2641 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2643 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2645 if (_session->config.get_timecode_offset_negative()) {
2646 start -= _session->config.get_timecode_offset ();
2648 start += _session->config.get_timecode_offset ();
2652 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2658 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2660 const framepos_t one_second = _session->frame_rate();
2661 const framepos_t one_minute = _session->frame_rate() * 60;
2662 framepos_t presnap = start;
2666 switch (_snap_type) {
2667 case SnapToTimecodeFrame:
2668 case SnapToTimecodeSeconds:
2669 case SnapToTimecodeMinutes:
2670 return timecode_snap_to_internal (start, direction, for_mark);
2673 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2674 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2676 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2681 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2682 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2684 start = (framepos_t) floor ((double) start / one_second) * one_second;
2689 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2690 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2692 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2697 start = _session->tempo_map().round_to_bar (start, direction);
2701 start = _session->tempo_map().round_to_beat (start, direction);
2704 case SnapToBeatDiv128:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2707 case SnapToBeatDiv64:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2710 case SnapToBeatDiv32:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2713 case SnapToBeatDiv28:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2716 case SnapToBeatDiv24:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2719 case SnapToBeatDiv20:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2722 case SnapToBeatDiv16:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2725 case SnapToBeatDiv14:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2728 case SnapToBeatDiv12:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2731 case SnapToBeatDiv10:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2734 case SnapToBeatDiv8:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2737 case SnapToBeatDiv7:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2740 case SnapToBeatDiv6:
2741 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2743 case SnapToBeatDiv5:
2744 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2746 case SnapToBeatDiv4:
2747 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2749 case SnapToBeatDiv3:
2750 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2752 case SnapToBeatDiv2:
2753 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2761 _session->locations()->marks_either_side (start, before, after);
2763 if (before == max_framepos && after == max_framepos) {
2764 /* No marks to snap to, so just don't snap */
2766 } else if (before == max_framepos) {
2768 } else if (after == max_framepos) {
2770 } else if (before != max_framepos && after != max_framepos) {
2771 /* have before and after */
2772 if ((start - before) < (after - start)) {
2781 case SnapToRegionStart:
2782 case SnapToRegionEnd:
2783 case SnapToRegionSync:
2784 case SnapToRegionBoundary:
2785 if (!region_boundary_cache.empty()) {
2787 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2788 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2790 if (direction > 0) {
2791 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2793 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2796 if (next != region_boundary_cache.begin ()) {
2801 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2802 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2804 if (start > (p + n) / 2) {
2813 switch (_snap_mode) {
2819 if (presnap > start) {
2820 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2824 } else if (presnap < start) {
2825 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2831 /* handled at entry */
2839 Editor::setup_toolbar ()
2841 HBox* mode_box = manage(new HBox);
2842 mode_box->set_border_width (2);
2843 mode_box->set_spacing(4);
2845 HBox* mouse_mode_box = manage (new HBox);
2846 HBox* mouse_mode_hbox = manage (new HBox);
2847 VBox* mouse_mode_vbox = manage (new VBox);
2848 Alignment* mouse_mode_align = manage (new Alignment);
2850 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2851 // mouse_mode_size_group->add_widget (smart_mode_button);
2852 mouse_mode_size_group->add_widget (mouse_move_button);
2853 mouse_mode_size_group->add_widget (mouse_select_button);
2854 mouse_mode_size_group->add_widget (mouse_zoom_button);
2855 mouse_mode_size_group->add_widget (mouse_gain_button);
2856 mouse_mode_size_group->add_widget (mouse_timefx_button);
2857 mouse_mode_size_group->add_widget (mouse_audition_button);
2858 mouse_mode_size_group->add_widget (mouse_draw_button);
2859 mouse_mode_size_group->add_widget (internal_edit_button);
2861 /* make them just a bit bigger */
2862 mouse_move_button.set_size_request (-1, 30);
2864 mouse_mode_hbox->set_spacing (2);
2866 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2867 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2868 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2873 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2874 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2876 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2878 mouse_mode_align->add (*mouse_mode_vbox);
2879 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2881 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2883 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2884 if (!Profile->get_sae()) {
2885 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2887 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2889 edit_mode_selector.set_name ("EditModeSelector");
2890 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2891 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2893 mode_box->pack_start (edit_mode_selector, false, false);
2894 mode_box->pack_start (*mouse_mode_box, false, false);
2896 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2897 _mouse_mode_tearoff->set_name ("MouseModeBase");
2898 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2900 if (Profile->get_sae()) {
2901 _mouse_mode_tearoff->set_can_be_torn_off (false);
2904 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2905 &_mouse_mode_tearoff->tearoff_window()));
2906 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2907 &_mouse_mode_tearoff->tearoff_window(), 1));
2908 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2909 &_mouse_mode_tearoff->tearoff_window()));
2910 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2911 &_mouse_mode_tearoff->tearoff_window(), 1));
2915 _zoom_box.set_spacing (2);
2916 _zoom_box.set_border_width (2);
2920 zoom_in_button.set_name ("zoom button");
2921 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2922 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2923 zoom_in_button.set_image(::get_icon ("zoom_in"));
2924 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2925 zoom_in_button.set_related_action (act);
2927 zoom_out_button.set_name ("zoom button");
2928 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2929 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2930 zoom_out_button.set_image(::get_icon ("zoom_out"));
2931 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2932 zoom_out_button.set_related_action (act);
2934 zoom_out_full_button.set_name ("zoom button");
2935 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2936 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2937 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2938 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2939 zoom_out_full_button.set_related_action (act);
2941 zoom_focus_selector.set_name ("ZoomFocusSelector");
2942 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2943 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2945 _zoom_box.pack_start (zoom_out_button, false, false);
2946 _zoom_box.pack_start (zoom_in_button, false, false);
2947 _zoom_box.pack_start (zoom_out_full_button, false, false);
2949 _zoom_box.pack_start (zoom_focus_selector, false, false);
2951 /* Track zoom buttons */
2952 tav_expand_button.set_name ("zoom button");
2953 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2954 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2955 tav_expand_button.set_size_request (-1, 20);
2956 tav_expand_button.set_image(::get_icon ("tav_exp"));
2957 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2958 tav_expand_button.set_related_action (act);
2960 tav_shrink_button.set_name ("zoom button");
2961 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2962 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2963 tav_shrink_button.set_size_request (-1, 20);
2964 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2965 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2966 tav_shrink_button.set_related_action (act);
2968 _zoom_box.pack_start (tav_shrink_button);
2969 _zoom_box.pack_start (tav_expand_button);
2971 _zoom_tearoff = manage (new TearOff (_zoom_box));
2973 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2974 &_zoom_tearoff->tearoff_window()));
2975 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2976 &_zoom_tearoff->tearoff_window(), 0));
2977 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2978 &_zoom_tearoff->tearoff_window()));
2979 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2980 &_zoom_tearoff->tearoff_window(), 0));
2982 snap_box.set_spacing (2);
2983 snap_box.set_border_width (2);
2985 snap_type_selector.set_name ("SnapTypeSelector");
2986 set_popdown_strings (snap_type_selector, snap_type_strings);
2987 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2989 snap_mode_selector.set_name ("SnapModeSelector");
2990 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2991 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2993 edit_point_selector.set_name ("EditPointSelector");
2994 set_popdown_strings (edit_point_selector, edit_point_strings);
2995 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2997 snap_box.pack_start (snap_mode_selector, false, false);
2998 snap_box.pack_start (snap_type_selector, false, false);
2999 snap_box.pack_start (edit_point_selector, false, false);
3003 HBox *nudge_box = manage (new HBox);
3004 nudge_box->set_spacing (2);
3005 nudge_box->set_border_width (2);
3007 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3008 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3010 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3011 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3013 nudge_box->pack_start (nudge_backward_button, false, false);
3014 nudge_box->pack_start (nudge_forward_button, false, false);
3015 nudge_box->pack_start (*nudge_clock, false, false);
3018 /* Pack everything in... */
3020 HBox* hbox = manage (new HBox);
3021 hbox->set_spacing(10);
3023 _tools_tearoff = manage (new TearOff (*hbox));
3024 _tools_tearoff->set_name ("MouseModeBase");
3025 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3027 if (Profile->get_sae()) {
3028 _tools_tearoff->set_can_be_torn_off (false);
3031 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3032 &_tools_tearoff->tearoff_window()));
3033 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3034 &_tools_tearoff->tearoff_window(), 0));
3035 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3036 &_tools_tearoff->tearoff_window()));
3037 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3038 &_tools_tearoff->tearoff_window(), 0));
3040 toolbar_hbox.set_spacing (10);
3041 toolbar_hbox.set_border_width (1);
3043 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3044 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3045 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3047 hbox->pack_start (snap_box, false, false);
3048 if (!Profile->get_small_screen()) {
3049 hbox->pack_start (*nudge_box, false, false);
3051 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3053 hbox->pack_start (panic_box, false, false);
3057 toolbar_base.set_name ("ToolBarBase");
3058 toolbar_base.add (toolbar_hbox);
3060 _toolbar_viewport.add (toolbar_base);
3061 /* stick to the required height but allow width to vary if there's not enough room */
3062 _toolbar_viewport.set_size_request (1, -1);
3064 toolbar_frame.set_shadow_type (SHADOW_OUT);
3065 toolbar_frame.set_name ("BaseFrame");
3066 toolbar_frame.add (_toolbar_viewport);
3070 Editor::setup_tooltips ()
3072 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3073 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3074 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3075 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3076 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3077 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3078 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3079 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3080 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3081 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3082 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3083 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3084 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3085 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3086 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3087 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3088 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3089 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3090 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3091 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3092 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3093 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3094 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3098 Editor::convert_drop_to_paths (
3099 vector<string>& paths,
3100 const RefPtr<Gdk::DragContext>& /*context*/,
3103 const SelectionData& data,
3107 if (_session == 0) {
3111 vector<string> uris = data.get_uris();
3115 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3116 are actually URI lists. So do it by hand.
3119 if (data.get_target() != "text/plain") {
3123 /* Parse the "uri-list" format that Nautilus provides,
3124 where each pathname is delimited by \r\n.
3126 THERE MAY BE NO NULL TERMINATING CHAR!!!
3129 string txt = data.get_text();
3133 p = (const char *) malloc (txt.length() + 1);
3134 txt.copy (const_cast<char *> (p), txt.length(), 0);
3135 const_cast<char*>(p)[txt.length()] = '\0';
3141 while (g_ascii_isspace (*p))
3145 while (*q && (*q != '\n') && (*q != '\r')) {
3152 while (q > p && g_ascii_isspace (*q))
3157 uris.push_back (string (p, q - p + 1));
3161 p = strchr (p, '\n');
3173 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3175 if ((*i).substr (0,7) == "file://") {
3177 string const p = PBD::url_decode (*i);
3179 // scan forward past three slashes
3181 string::size_type slashcnt = 0;
3182 string::size_type n = 0;
3183 string::const_iterator x = p.begin();
3185 while (slashcnt < 3 && x != p.end()) {
3188 } else if (slashcnt == 3) {
3195 if (slashcnt != 3 || x == p.end()) {
3196 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3200 paths.push_back (p.substr (n - 1));
3208 Editor::new_tempo_section ()
3214 Editor::map_transport_state ()
3216 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3218 if (_session && _session->transport_stopped()) {
3219 have_pending_keyboard_selection = false;
3222 update_loop_range_view (true);
3228 Editor::begin_reversible_command (string name)
3231 _session->begin_reversible_command (name);
3236 Editor::begin_reversible_command (GQuark q)
3239 _session->begin_reversible_command (q);
3244 Editor::commit_reversible_command ()
3247 _session->commit_reversible_command ();
3252 Editor::history_changed ()
3256 if (undo_action && _session) {
3257 if (_session->undo_depth() == 0) {
3258 label = S_("Command|Undo");
3260 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3262 undo_action->property_label() = label;
3265 if (redo_action && _session) {
3266 if (_session->redo_depth() == 0) {
3269 label = string_compose(_("Redo (%1)"), _session->next_redo());
3271 redo_action->property_label() = label;
3276 Editor::duplicate_range (bool with_dialog)
3280 RegionSelection rs = get_regions_from_selection_and_entered ();
3282 if ( selection->time.length() == 0 && rs.empty()) {
3288 ArdourDialog win (_("Duplicate"));
3289 Label label (_("Number of duplications:"));
3290 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3291 SpinButton spinner (adjustment, 0.0, 1);
3294 win.get_vbox()->set_spacing (12);
3295 win.get_vbox()->pack_start (hbox);
3296 hbox.set_border_width (6);
3297 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3299 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3300 place, visually. so do this by hand.
3303 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3304 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3305 spinner.grab_focus();
3311 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3312 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3313 win.set_default_response (RESPONSE_ACCEPT);
3315 spinner.grab_focus ();
3317 switch (win.run ()) {
3318 case RESPONSE_ACCEPT:
3324 times = adjustment.get_value();
3327 if ((current_mouse_mode() == Editing::MouseRange)) {
3328 if (selection->time.length()) {
3329 duplicate_selection (times);
3331 } else if (get_smart_mode()) {
3332 if (selection->time.length()) {
3333 duplicate_selection (times);
3335 duplicate_some_regions (rs, times);
3337 duplicate_some_regions (rs, times);
3342 Editor::set_edit_mode (EditMode m)
3344 Config->set_edit_mode (m);
3348 Editor::cycle_edit_mode ()
3350 switch (Config->get_edit_mode()) {
3352 if (Profile->get_sae()) {
3353 Config->set_edit_mode (Lock);
3355 Config->set_edit_mode (Splice);
3359 Config->set_edit_mode (Lock);
3362 Config->set_edit_mode (Slide);
3368 Editor::edit_mode_selection_done ()
3370 string s = edit_mode_selector.get_active_text ();
3373 Config->set_edit_mode (string_to_edit_mode (s));
3378 Editor::snap_type_selection_done ()
3380 string choice = snap_type_selector.get_active_text();
3381 SnapType snaptype = SnapToBeat;
3383 if (choice == _("Beats/2")) {
3384 snaptype = SnapToBeatDiv2;
3385 } else if (choice == _("Beats/3")) {
3386 snaptype = SnapToBeatDiv3;
3387 } else if (choice == _("Beats/4")) {
3388 snaptype = SnapToBeatDiv4;
3389 } else if (choice == _("Beats/5")) {
3390 snaptype = SnapToBeatDiv5;
3391 } else if (choice == _("Beats/6")) {
3392 snaptype = SnapToBeatDiv6;
3393 } else if (choice == _("Beats/7")) {
3394 snaptype = SnapToBeatDiv7;
3395 } else if (choice == _("Beats/8")) {
3396 snaptype = SnapToBeatDiv8;
3397 } else if (choice == _("Beats/10")) {
3398 snaptype = SnapToBeatDiv10;
3399 } else if (choice == _("Beats/12")) {
3400 snaptype = SnapToBeatDiv12;
3401 } else if (choice == _("Beats/14")) {
3402 snaptype = SnapToBeatDiv14;
3403 } else if (choice == _("Beats/16")) {
3404 snaptype = SnapToBeatDiv16;
3405 } else if (choice == _("Beats/20")) {
3406 snaptype = SnapToBeatDiv20;
3407 } else if (choice == _("Beats/24")) {
3408 snaptype = SnapToBeatDiv24;
3409 } else if (choice == _("Beats/28")) {
3410 snaptype = SnapToBeatDiv28;
3411 } else if (choice == _("Beats/32")) {
3412 snaptype = SnapToBeatDiv32;
3413 } else if (choice == _("Beats/64")) {
3414 snaptype = SnapToBeatDiv64;
3415 } else if (choice == _("Beats/128")) {
3416 snaptype = SnapToBeatDiv128;
3417 } else if (choice == _("Beats")) {
3418 snaptype = SnapToBeat;
3419 } else if (choice == _("Bars")) {
3420 snaptype = SnapToBar;
3421 } else if (choice == _("Marks")) {
3422 snaptype = SnapToMark;
3423 } else if (choice == _("Region starts")) {
3424 snaptype = SnapToRegionStart;
3425 } else if (choice == _("Region ends")) {
3426 snaptype = SnapToRegionEnd;
3427 } else if (choice == _("Region bounds")) {
3428 snaptype = SnapToRegionBoundary;
3429 } else if (choice == _("Region syncs")) {
3430 snaptype = SnapToRegionSync;
3431 } else if (choice == _("CD Frames")) {
3432 snaptype = SnapToCDFrame;
3433 } else if (choice == _("Timecode Frames")) {
3434 snaptype = SnapToTimecodeFrame;
3435 } else if (choice == _("Timecode Seconds")) {
3436 snaptype = SnapToTimecodeSeconds;
3437 } else if (choice == _("Timecode Minutes")) {
3438 snaptype = SnapToTimecodeMinutes;
3439 } else if (choice == _("Seconds")) {
3440 snaptype = SnapToSeconds;
3441 } else if (choice == _("Minutes")) {
3442 snaptype = SnapToMinutes;
3445 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3447 ract->set_active ();
3452 Editor::snap_mode_selection_done ()
3454 string choice = snap_mode_selector.get_active_text();
3455 SnapMode mode = SnapNormal;
3457 if (choice == _("No Grid")) {
3459 } else if (choice == _("Grid")) {
3461 } else if (choice == _("Magnetic")) {
3462 mode = SnapMagnetic;
3465 RefPtr<RadioAction> ract = snap_mode_action (mode);
3468 ract->set_active (true);
3473 Editor::cycle_edit_point (bool with_marker)
3475 switch (_edit_point) {
3477 set_edit_point_preference (EditAtPlayhead);
3479 case EditAtPlayhead:
3481 set_edit_point_preference (EditAtSelectedMarker);
3483 set_edit_point_preference (EditAtMouse);
3486 case EditAtSelectedMarker:
3487 set_edit_point_preference (EditAtMouse);
3493 Editor::edit_point_selection_done ()
3495 string choice = edit_point_selector.get_active_text();
3496 EditPoint ep = EditAtSelectedMarker;
3498 if (choice == _("Marker")) {
3499 set_edit_point_preference (EditAtSelectedMarker);
3500 } else if (choice == _("Playhead")) {
3501 set_edit_point_preference (EditAtPlayhead);
3503 set_edit_point_preference (EditAtMouse);
3506 RefPtr<RadioAction> ract = edit_point_action (ep);
3509 ract->set_active (true);
3514 Editor::zoom_focus_selection_done ()
3516 string choice = zoom_focus_selector.get_active_text();
3517 ZoomFocus focus_type = ZoomFocusLeft;
3519 if (choice == _("Left")) {
3520 focus_type = ZoomFocusLeft;
3521 } else if (choice == _("Right")) {
3522 focus_type = ZoomFocusRight;
3523 } else if (choice == _("Center")) {
3524 focus_type = ZoomFocusCenter;
3525 } else if (choice == _("Playhead")) {
3526 focus_type = ZoomFocusPlayhead;
3527 } else if (choice == _("Mouse")) {
3528 focus_type = ZoomFocusMouse;
3529 } else if (choice == _("Edit point")) {
3530 focus_type = ZoomFocusEdit;
3533 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3536 ract->set_active ();
3541 Editor::edit_controls_button_release (GdkEventButton* ev)
3543 if (Keyboard::is_context_menu_event (ev)) {
3544 ARDOUR_UI::instance()->add_route (this);
3545 } else if (ev->button == 1) {
3546 selection->clear_tracks ();
3553 Editor::mouse_select_button_release (GdkEventButton* ev)
3555 /* this handles just right-clicks */
3557 if (ev->button != 3) {
3565 Editor::set_zoom_focus (ZoomFocus f)
3567 string str = zoom_focus_strings[(int)f];
3569 if (str != zoom_focus_selector.get_active_text()) {
3570 zoom_focus_selector.set_active_text (str);
3573 if (zoom_focus != f) {
3580 Editor::cycle_zoom_focus ()
3582 switch (zoom_focus) {
3584 set_zoom_focus (ZoomFocusRight);
3586 case ZoomFocusRight:
3587 set_zoom_focus (ZoomFocusCenter);
3589 case ZoomFocusCenter:
3590 set_zoom_focus (ZoomFocusPlayhead);
3592 case ZoomFocusPlayhead:
3593 set_zoom_focus (ZoomFocusMouse);
3595 case ZoomFocusMouse:
3596 set_zoom_focus (ZoomFocusEdit);
3599 set_zoom_focus (ZoomFocusLeft);
3605 Editor::ensure_float (Window& win)
3607 win.set_transient_for (*this);
3611 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3613 /* recover or initialize pane positions. do this here rather than earlier because
3614 we don't want the positions to change the child allocations, which they seem to do.
3620 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3629 XMLNode* geometry = find_named_node (*node, "geometry");
3631 if (which == static_cast<Paned*> (&edit_pane)) {
3633 if (done & Horizontal) {
3637 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3638 _notebook_shrunk = string_is_affirmative (prop->value ());
3641 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3642 /* initial allocation is 90% to canvas, 10% to notebook */
3643 pos = (int) floor (alloc.get_width() * 0.90f);
3644 snprintf (buf, sizeof(buf), "%d", pos);
3646 pos = atoi (prop->value());
3649 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3650 edit_pane.set_position (pos);
3653 done = (Pane) (done | Horizontal);
3655 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3657 if (done & Vertical) {
3661 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3662 /* initial allocation is 90% to canvas, 10% to summary */
3663 pos = (int) floor (alloc.get_height() * 0.90f);
3664 snprintf (buf, sizeof(buf), "%d", pos);
3667 pos = atoi (prop->value());
3670 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3671 editor_summary_pane.set_position (pos);
3674 done = (Pane) (done | Vertical);
3679 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3681 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3682 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3683 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3684 top_hbox.remove (toolbar_frame);
3689 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3691 if (toolbar_frame.get_parent() == 0) {
3692 top_hbox.pack_end (toolbar_frame);
3697 Editor::set_show_measures (bool yn)
3699 if (_show_measures != yn) {
3702 if ((_show_measures = yn) == true) {
3704 tempo_lines->show();
3707 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3708 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3710 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3711 draw_measures (begin, end);
3719 Editor::toggle_follow_playhead ()
3721 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3723 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3724 set_follow_playhead (tact->get_active());
3728 /** @param yn true to follow playhead, otherwise false.
3729 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3732 Editor::set_follow_playhead (bool yn, bool catch_up)
3734 if (_follow_playhead != yn) {
3735 if ((_follow_playhead = yn) == true && catch_up) {
3737 reset_x_origin_to_follow_playhead ();
3744 Editor::toggle_stationary_playhead ()
3746 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3748 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3749 set_stationary_playhead (tact->get_active());
3754 Editor::set_stationary_playhead (bool yn)
3756 if (_stationary_playhead != yn) {
3757 if ((_stationary_playhead = yn) == true) {
3759 // FIXME need a 3.0 equivalent of this 2.X call
3760 // update_current_screen ();
3767 Editor::playlist_selector () const
3769 return *_playlist_selector;
3773 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3777 switch (_snap_type) {
3782 case SnapToBeatDiv128:
3785 case SnapToBeatDiv64:
3788 case SnapToBeatDiv32:
3791 case SnapToBeatDiv28:
3794 case SnapToBeatDiv24:
3797 case SnapToBeatDiv20:
3800 case SnapToBeatDiv16:
3803 case SnapToBeatDiv14:
3806 case SnapToBeatDiv12:
3809 case SnapToBeatDiv10:
3812 case SnapToBeatDiv8:
3815 case SnapToBeatDiv7:
3818 case SnapToBeatDiv6:
3821 case SnapToBeatDiv5:
3824 case SnapToBeatDiv4:
3827 case SnapToBeatDiv3:
3830 case SnapToBeatDiv2:
3836 return _session->tempo_map().meter_at (position).divisions_per_bar();
3841 case SnapToTimecodeFrame:
3842 case SnapToTimecodeSeconds:
3843 case SnapToTimecodeMinutes:
3846 case SnapToRegionStart:
3847 case SnapToRegionEnd:
3848 case SnapToRegionSync:
3849 case SnapToRegionBoundary:
3859 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3863 ret = nudge_clock->current_duration (pos);
3864 next = ret + 1; /* XXXX fix me */
3870 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3872 ArdourDialog dialog (_("Playlist Deletion"));
3873 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3874 "If it is kept, its audio files will not be cleaned.\n"
3875 "If it is deleted, audio files used by it alone will be cleaned."),
3878 dialog.set_position (WIN_POS_CENTER);
3879 dialog.get_vbox()->pack_start (label);
3883 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3884 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3885 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3887 switch (dialog.run ()) {
3888 case RESPONSE_ACCEPT:
3889 /* delete the playlist */
3893 case RESPONSE_REJECT:
3894 /* keep the playlist */
3906 Editor::audio_region_selection_covers (framepos_t where)
3908 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3909 if ((*a)->region()->covers (where)) {
3918 Editor::prepare_for_cleanup ()
3920 cut_buffer->clear_regions ();
3921 cut_buffer->clear_playlists ();
3923 selection->clear_regions ();
3924 selection->clear_playlists ();
3926 _regions->suspend_redisplay ();
3930 Editor::finish_cleanup ()
3932 _regions->resume_redisplay ();
3936 Editor::transport_loop_location()
3939 return _session->locations()->auto_loop_location();
3946 Editor::transport_punch_location()
3949 return _session->locations()->auto_punch_location();
3956 Editor::control_layout_scroll (GdkEventScroll* ev)
3958 if (Keyboard::some_magic_widget_has_focus()) {
3962 switch (ev->direction) {
3964 scroll_tracks_up_line ();
3968 case GDK_SCROLL_DOWN:
3969 scroll_tracks_down_line ();
3973 /* no left/right handling yet */
3981 Editor::session_state_saved (string)
3984 _snapshots->redisplay ();
3988 Editor::update_tearoff_visibility()
3990 bool visible = Config->get_keep_tearoffs();
3991 _mouse_mode_tearoff->set_visible (visible);
3992 _tools_tearoff->set_visible (visible);
3993 _zoom_tearoff->set_visible (visible);
3997 Editor::maximise_editing_space ()
4009 Editor::restore_editing_space ()
4021 * Make new playlists for a given track and also any others that belong
4022 * to the same active route group with the `select' property.
4027 Editor::new_playlists (TimeAxisView* v)
4029 begin_reversible_command (_("new playlists"));
4030 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4031 _session->playlists->get (playlists);
4032 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4033 commit_reversible_command ();
4037 * Use a copy of the current playlist for a given track and also any others that belong
4038 * to the same active route group with the `select' property.
4043 Editor::copy_playlists (TimeAxisView* v)
4045 begin_reversible_command (_("copy playlists"));
4046 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4047 _session->playlists->get (playlists);
4048 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4049 commit_reversible_command ();
4052 /** Clear the current playlist for a given track and also any others that belong
4053 * to the same active route group with the `select' property.
4058 Editor::clear_playlists (TimeAxisView* v)
4060 begin_reversible_command (_("clear playlists"));
4061 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4062 _session->playlists->get (playlists);
4063 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4064 commit_reversible_command ();
4068 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4070 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4074 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4076 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4080 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4082 atv.clear_playlist ();
4086 Editor::on_key_press_event (GdkEventKey* ev)
4088 return key_press_focus_accelerator_handler (*this, ev);
4092 Editor::on_key_release_event (GdkEventKey* ev)
4094 return Gtk::Window::on_key_release_event (ev);
4095 // return key_press_focus_accelerator_handler (*this, ev);
4098 /** Queue up a change to the viewport x origin.
4099 * @param frame New x origin.
4102 Editor::reset_x_origin (framepos_t frame)
4104 pending_visual_change.add (VisualChange::TimeOrigin);
4105 pending_visual_change.time_origin = frame;
4106 ensure_visual_change_idle_handler ();
4110 Editor::reset_y_origin (double y)
4112 pending_visual_change.add (VisualChange::YOrigin);
4113 pending_visual_change.y_origin = y;
4114 ensure_visual_change_idle_handler ();
4118 Editor::reset_zoom (double fpp)
4120 clamp_samples_per_pixel (fpp);
4122 if (fpp == samples_per_pixel) {
4126 pending_visual_change.add (VisualChange::ZoomLevel);
4127 pending_visual_change.samples_per_pixel = fpp;
4128 ensure_visual_change_idle_handler ();
4132 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4134 reset_x_origin (frame);
4137 if (!no_save_visual) {
4138 undo_visual_stack.push_back (current_visual_state(false));
4142 Editor::VisualState::VisualState (bool with_tracks)
4143 : gui_state (with_tracks ? new GUIObjectState : 0)
4147 Editor::VisualState::~VisualState ()
4152 Editor::VisualState*
4153 Editor::current_visual_state (bool with_tracks)
4155 VisualState* vs = new VisualState (with_tracks);
4156 vs->y_position = vertical_adjustment.get_value();
4157 vs->samples_per_pixel = samples_per_pixel;
4158 vs->leftmost_frame = leftmost_frame;
4159 vs->zoom_focus = zoom_focus;
4162 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4169 Editor::undo_visual_state ()
4171 if (undo_visual_stack.empty()) {
4175 VisualState* vs = undo_visual_stack.back();
4176 undo_visual_stack.pop_back();
4179 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4181 use_visual_state (*vs);
4185 Editor::redo_visual_state ()
4187 if (redo_visual_stack.empty()) {
4191 VisualState* vs = redo_visual_stack.back();
4192 redo_visual_stack.pop_back();
4194 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4196 use_visual_state (*vs);
4200 Editor::swap_visual_state ()
4202 if (undo_visual_stack.empty()) {
4203 redo_visual_state ();
4205 undo_visual_state ();
4210 Editor::use_visual_state (VisualState& vs)
4212 PBD::Unwinder<bool> nsv (no_save_visual, true);
4214 _routes->suspend_redisplay ();
4216 vertical_adjustment.set_value (vs.y_position);
4218 set_zoom_focus (vs.zoom_focus);
4219 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4222 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4224 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4225 (*i)->reset_visual_state ();
4229 _routes->update_visibility ();
4230 _routes->resume_redisplay ();
4233 /** This is the core function that controls the zoom level of the canvas. It is called
4234 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4235 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4238 Editor::set_samples_per_pixel (double fpp)
4241 tempo_lines->tempo_map_changed();
4244 samples_per_pixel = fpp;
4246 /* convert fpu to frame count */
4248 framepos_t frames = (framepos_t) floor (samples_per_pixel * _visible_canvas_width);
4250 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4251 zoom_range_clock->set (frames);
4254 bool const showing_time_selection = selection->time.length() > 0;
4256 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4257 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4258 (*i)->reshow_selection (selection->time);
4262 ZoomChanged (); /* EMIT_SIGNAL */
4264 //reset_scrolling_region ();
4266 if (playhead_cursor) {
4267 playhead_cursor->set_position (playhead_cursor->current_frame ());
4270 refresh_location_display();
4271 _summary->set_overlays_dirty ();
4273 update_marker_labels ();
4279 Editor::queue_visual_videotimeline_update ()
4282 * pending_visual_change.add (VisualChange::VideoTimeline);
4283 * or maybe even more specific: which videotimeline-image
4284 * currently it calls update_video_timeline() to update
4285 * _all outdated_ images on the video-timeline.
4286 * see 'exposeimg()' in video_image_frame.cc
4288 ensure_visual_change_idle_handler ();
4292 Editor::ensure_visual_change_idle_handler ()
4294 if (pending_visual_change.idle_handler_id < 0) {
4295 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4296 pending_visual_change.being_handled = false;
4301 Editor::_idle_visual_changer (void* arg)
4303 return static_cast<Editor*>(arg)->idle_visual_changer ();
4307 Editor::idle_visual_changer ()
4309 /* set_horizontal_position() below (and maybe other calls) call
4310 gtk_main_iteration(), so it's possible that a signal will be handled
4311 half-way through this method. If this signal wants an
4312 idle_visual_changer we must schedule another one after this one, so
4313 mark the idle_handler_id as -1 here to allow that. Also make a note
4314 that we are doing the visual change, so that changes in response to
4315 super-rapid-screen-update can be dropped if we are still processing
4319 pending_visual_change.idle_handler_id = -1;
4320 pending_visual_change.being_handled = true;
4322 VisualChange::Type p = pending_visual_change.pending;
4323 pending_visual_change.pending = (VisualChange::Type) 0;
4325 double const last_time_origin = horizontal_position ();
4327 if (p & VisualChange::ZoomLevel) {
4328 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4330 compute_fixed_ruler_scale ();
4332 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4333 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4335 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4336 current_bbt_points_begin, current_bbt_points_end);
4337 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4338 current_bbt_points_begin, current_bbt_points_end);
4339 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4342 if (p & VisualChange::ZoomLevel) {
4343 update_video_timeline();
4346 if (p & VisualChange::TimeOrigin) {
4347 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4350 if (p & VisualChange::YOrigin) {
4351 vertical_adjustment.set_value (pending_visual_change.y_origin);
4354 if (last_time_origin == horizontal_position ()) {
4355 /* changed signal not emitted */
4356 update_fixed_rulers ();
4357 redisplay_tempo (true);
4360 if (!(p & VisualChange::ZoomLevel)) {
4361 update_video_timeline();
4364 _summary->set_overlays_dirty ();
4366 pending_visual_change.being_handled = false;
4367 return 0; /* this is always a one-shot call */
4370 struct EditorOrderTimeAxisSorter {
4371 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4372 return a->order () < b->order ();
4377 Editor::sort_track_selection (TrackViewList& sel)
4379 EditorOrderTimeAxisSorter cmp;
4384 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4387 framepos_t where = 0;
4388 EditPoint ep = _edit_point;
4390 if (from_context_menu && (ep == EditAtMouse)) {
4391 return window_event_frame (&context_click_event, 0, 0);
4394 if (entered_marker) {
4395 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4396 return entered_marker->position();
4399 if (ignore_playhead && ep == EditAtPlayhead) {
4400 ep = EditAtSelectedMarker;
4404 case EditAtPlayhead:
4405 where = _session->audible_frame();
4406 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4409 case EditAtSelectedMarker:
4410 if (!selection->markers.empty()) {
4412 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4415 where = loc->start();
4419 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4427 if (!mouse_frame (where, ignored)) {
4428 /* XXX not right but what can we do ? */
4432 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4440 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4442 if (!_session) return;
4444 begin_reversible_command (cmd);
4448 if ((tll = transport_loop_location()) == 0) {
4449 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4450 XMLNode &before = _session->locations()->get_state();
4451 _session->locations()->add (loc, true);
4452 _session->set_auto_loop_location (loc);
4453 XMLNode &after = _session->locations()->get_state();
4454 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4456 XMLNode &before = tll->get_state();
4457 tll->set_hidden (false, this);
4458 tll->set (start, end);
4459 XMLNode &after = tll->get_state();
4460 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4463 commit_reversible_command ();
4467 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4469 if (!_session) return;
4471 begin_reversible_command (cmd);
4475 if ((tpl = transport_punch_location()) == 0) {
4476 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4477 XMLNode &before = _session->locations()->get_state();
4478 _session->locations()->add (loc, true);
4479 _session->set_auto_loop_location (loc);
4480 XMLNode &after = _session->locations()->get_state();
4481 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4484 XMLNode &before = tpl->get_state();
4485 tpl->set_hidden (false, this);
4486 tpl->set (start, end);
4487 XMLNode &after = tpl->get_state();
4488 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4491 commit_reversible_command ();
4494 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4495 * @param rs List to which found regions are added.
4496 * @param where Time to look at.
4497 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4500 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4502 const TrackViewList* tracks;
4505 tracks = &track_views;
4510 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4512 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4515 boost::shared_ptr<Track> tr;
4516 boost::shared_ptr<Playlist> pl;
4518 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4520 boost::shared_ptr<RegionList> regions = pl->regions_at (
4521 (framepos_t) floor ( (double) where * tr->speed()));
4523 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4524 RegionView* rv = rtv->view()->find_view (*i);
4535 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4537 const TrackViewList* tracks;
4540 tracks = &track_views;
4545 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4546 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4548 boost::shared_ptr<Track> tr;
4549 boost::shared_ptr<Playlist> pl;
4551 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4553 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4554 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4556 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4558 RegionView* rv = rtv->view()->find_view (*i);
4569 /** Get regions using the following method:
4571 * Make a region list using the selected regions, unless
4572 * the edit point is `mouse' and the mouse is over an unselected
4573 * region. In this case, use just that region.
4575 * If the edit point is not 'mouse', and there are no regions selected,
4576 * search the list of selected tracks and return regions that are under
4577 * the edit point on these tracks. If there are no selected tracks and
4578 * 'No Selection = All Tracks' is active, search all tracks,
4580 * The rationale here is that the mouse edit point is special in that
4581 * its position describes both a time and a track; the other edit
4582 * modes only describe a time. Hence if the edit point is `mouse' we
4583 * ignore selected tracks, as we assume the user means something by
4584 * pointing at a particular track. Also in this case we take note of
4585 * the region directly under the edit point, as there is always just one
4586 * (rather than possibly several with non-mouse edit points).
4590 Editor::get_regions_from_selection_and_edit_point ()
4592 RegionSelection regions;
4594 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4595 regions.add (entered_regionview);
4597 regions = selection->regions;
4601 if (regions.empty() && _edit_point != EditAtMouse) {
4602 TrackViewList tracks = selection->tracks;
4604 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4605 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4606 * is enabled, so consider all tracks
4608 tracks = track_views;
4611 if (!tracks.empty()) {
4612 /* no region selected or entered, but some selected tracks:
4613 * act on all regions on the selected tracks at the edit point
4615 framepos_t const where = get_preferred_edit_position ();
4616 get_regions_at(regions, where, tracks);
4622 /** Start with regions that are selected, or the entered regionview if none are selected.
4623 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4624 * of the regions that we started with.
4628 Editor::get_regions_from_selection_and_entered ()
4630 RegionSelection regions = selection->regions;
4632 if (regions.empty() && entered_regionview) {
4633 regions.add (entered_regionview);
4640 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4642 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4644 RouteTimeAxisView* tatv;
4646 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4648 boost::shared_ptr<Playlist> pl;
4649 vector<boost::shared_ptr<Region> > results;
4651 boost::shared_ptr<Track> tr;
4653 if ((tr = tatv->track()) == 0) {
4658 if ((pl = (tr->playlist())) != 0) {
4659 if (src_comparison) {
4660 pl->get_source_equivalent_regions (region, results);
4662 pl->get_region_list_equivalent_regions (region, results);
4666 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4667 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4668 regions.push_back (marv);
4677 Editor::show_rhythm_ferret ()
4679 if (rhythm_ferret == 0) {
4680 rhythm_ferret = new RhythmFerret(*this);
4683 rhythm_ferret->set_session (_session);
4684 rhythm_ferret->show ();
4685 rhythm_ferret->present ();
4689 Editor::first_idle ()
4691 MessageDialog* dialog = 0;
4693 if (track_views.size() > 1) {
4694 dialog = new MessageDialog (
4696 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4700 ARDOUR_UI::instance()->flush_pending ();
4703 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4707 // first idle adds route children (automation tracks), so we need to redisplay here
4708 _routes->redisplay ();
4715 Editor::_idle_resize (gpointer arg)
4717 return ((Editor*)arg)->idle_resize ();
4721 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4723 if (resize_idle_id < 0) {
4724 resize_idle_id = g_idle_add (_idle_resize, this);
4725 _pending_resize_amount = 0;
4728 /* make a note of the smallest resulting height, so that we can clamp the
4729 lower limit at TimeAxisView::hSmall */
4731 int32_t min_resulting = INT32_MAX;
4733 _pending_resize_amount += h;
4734 _pending_resize_view = view;
4736 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4738 if (selection->tracks.contains (_pending_resize_view)) {
4739 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4740 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4744 if (min_resulting < 0) {
4749 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4750 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4754 /** Handle pending resizing of tracks */
4756 Editor::idle_resize ()
4758 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4760 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4761 selection->tracks.contains (_pending_resize_view)) {
4763 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4764 if (*i != _pending_resize_view) {
4765 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4770 _pending_resize_amount = 0;
4771 _group_tabs->set_dirty ();
4772 resize_idle_id = -1;
4780 ENSURE_GUI_THREAD (*this, &Editor::located);
4783 playhead_cursor->set_position (_session->audible_frame ());
4784 if (_follow_playhead && !_pending_initial_locate) {
4785 reset_x_origin_to_follow_playhead ();
4789 _pending_locate_request = false;
4790 _pending_initial_locate = false;
4794 Editor::region_view_added (RegionView *)
4796 _summary->set_dirty ();
4800 Editor::region_view_removed ()
4802 _summary->set_dirty ();
4806 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4808 TrackViewList::const_iterator j = track_views.begin ();
4809 while (j != track_views.end()) {
4810 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4811 if (rtv && rtv->route() == r) {
4822 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4826 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4827 TimeAxisView* tv = axis_view_from_route (*i);
4837 Editor::add_routes (RouteList& routes)
4839 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4841 RouteTimeAxisView *rtv;
4842 list<RouteTimeAxisView*> new_views;
4844 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4845 boost::shared_ptr<Route> route = (*x);
4847 if (route->is_auditioner() || route->is_monitor()) {
4851 DataType dt = route->input()->default_type();
4853 if (dt == ARDOUR::DataType::AUDIO) {
4854 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4855 rtv->set_route (route);
4856 } else if (dt == ARDOUR::DataType::MIDI) {
4857 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4858 rtv->set_route (route);
4860 throw unknown_type();
4863 new_views.push_back (rtv);
4864 track_views.push_back (rtv);
4866 rtv->effective_gain_display ();
4868 if (internal_editing()) {
4869 rtv->enter_internal_edit_mode ();
4871 rtv->leave_internal_edit_mode ();
4874 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4875 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4878 _routes->routes_added (new_views);
4879 _summary->routes_added (new_views);
4881 if (show_editor_mixer_when_tracks_arrive) {
4882 show_editor_mixer (true);
4885 editor_list_button.set_sensitive (true);
4889 Editor::timeaxisview_deleted (TimeAxisView *tv)
4891 if (_session && _session->deletion_in_progress()) {
4892 /* the situation is under control */
4896 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4898 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4900 _routes->route_removed (tv);
4902 if (tv == entered_track) {
4906 TimeAxisView::Children c = tv->get_child_list ();
4907 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4908 if (entered_track == i->get()) {
4913 /* remove it from the list of track views */
4915 TrackViewList::iterator i;
4917 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4918 i = track_views.erase (i);
4921 /* update whatever the current mixer strip is displaying, if revelant */
4923 boost::shared_ptr<Route> route;
4926 route = rtav->route ();
4929 if (current_mixer_strip && current_mixer_strip->route() == route) {
4931 TimeAxisView* next_tv;
4933 if (track_views.empty()) {
4935 } else if (i == track_views.end()) {
4936 next_tv = track_views.front();
4943 set_selected_mixer_strip (*next_tv);
4945 /* make the editor mixer strip go away setting the
4946 * button to inactive (which also unticks the menu option)
4949 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4955 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4957 if (apply_to_selection) {
4958 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4960 TrackSelection::iterator j = i;
4963 hide_track_in_display (*i, false);
4968 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4970 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4971 // this will hide the mixer strip
4972 set_selected_mixer_strip (*tv);
4975 _routes->hide_track_in_display (*tv);
4980 Editor::sync_track_view_list_and_routes ()
4982 track_views = TrackViewList (_routes->views ());
4984 _summary->set_dirty ();
4985 _group_tabs->set_dirty ();
4987 return false; // do not call again (until needed)
4991 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4993 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4998 /** Find a RouteTimeAxisView by the ID of its route */
5000 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5002 RouteTimeAxisView* v;
5004 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5005 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5006 if(v->route()->id() == id) {
5016 Editor::fit_route_group (RouteGroup *g)
5018 TrackViewList ts = axis_views_from_routes (g->route_list ());
5023 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5025 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5028 _session->cancel_audition ();
5032 if (_session->is_auditioning()) {
5033 _session->cancel_audition ();
5034 if (r == last_audition_region) {
5039 _session->audition_region (r);
5040 last_audition_region = r;
5045 Editor::hide_a_region (boost::shared_ptr<Region> r)
5047 r->set_hidden (true);
5051 Editor::show_a_region (boost::shared_ptr<Region> r)
5053 r->set_hidden (false);
5057 Editor::audition_region_from_region_list ()
5059 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5063 Editor::hide_region_from_region_list ()
5065 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5069 Editor::show_region_in_region_list ()
5071 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5075 Editor::step_edit_status_change (bool yn)
5078 start_step_editing ();
5080 stop_step_editing ();
5085 Editor::start_step_editing ()
5087 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5091 Editor::stop_step_editing ()
5093 step_edit_connection.disconnect ();
5097 Editor::check_step_edit ()
5099 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5100 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5102 mtv->check_step_edit ();
5106 return true; // do it again, till we stop
5110 Editor::scroll_press (Direction dir)
5112 ++_scroll_callbacks;
5114 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5115 /* delay the first auto-repeat */
5121 scroll_backward (1);
5129 scroll_tracks_up_line ();
5133 scroll_tracks_down_line ();
5137 /* do hacky auto-repeat */
5138 if (!_scroll_connection.connected ()) {
5140 _scroll_connection = Glib::signal_timeout().connect (
5141 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5144 _scroll_callbacks = 0;
5151 Editor::scroll_release ()
5153 _scroll_connection.disconnect ();
5156 /** Queue a change for the Editor viewport x origin to follow the playhead */
5158 Editor::reset_x_origin_to_follow_playhead ()
5160 framepos_t const frame = playhead_cursor->current_frame ();
5162 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5164 if (_session->transport_speed() < 0) {
5166 if (frame > (current_page_samples() / 2)) {
5167 center_screen (frame-(current_page_samples()/2));
5169 center_screen (current_page_samples()/2);
5176 if (frame < leftmost_frame) {
5178 if (_session->transport_rolling()) {
5179 /* rolling; end up with the playhead at the right of the page */
5180 l = frame - current_page_samples ();
5182 /* not rolling: end up with the playhead 1/4 of the way along the page */
5183 l = frame - current_page_samples() / 4;
5187 if (_session->transport_rolling()) {
5188 /* rolling: end up with the playhead on the left of the page */
5191 /* not rolling: end up with the playhead 3/4 of the way along the page */
5192 l = frame - 3 * current_page_samples() / 4;
5200 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5206 Editor::super_rapid_screen_update ()
5208 if (!_session || !_session->engine().running()) {
5212 /* METERING / MIXER STRIPS */
5214 /* update track meters, if required */
5215 if (is_mapped() && meters_running) {
5216 RouteTimeAxisView* rtv;
5217 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5218 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5219 rtv->fast_update ();
5224 /* and any current mixer strip */
5225 if (current_mixer_strip) {
5226 current_mixer_strip->fast_update ();
5229 /* PLAYHEAD AND VIEWPORT */
5231 framepos_t const frame = _session->audible_frame();
5233 /* There are a few reasons why we might not update the playhead / viewport stuff:
5235 * 1. we don't update things when there's a pending locate request, otherwise
5236 * when the editor requests a locate there is a chance that this method
5237 * will move the playhead before the locate request is processed, causing
5239 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5240 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5243 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5245 last_update_frame = frame;
5247 if (!_dragging_playhead) {
5248 playhead_cursor->set_position (frame);
5251 if (!_stationary_playhead) {
5253 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5254 /* We only do this if we aren't already
5255 handling a visual change (ie if
5256 pending_visual_change.being_handled is
5257 false) so that these requests don't stack
5258 up there are too many of them to handle in
5261 reset_x_origin_to_follow_playhead ();
5266 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5270 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5271 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5272 if (target <= 0.0) {
5275 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5276 target = (target * 0.15) + (current * 0.85);
5282 set_horizontal_position (current);
5291 Editor::session_going_away ()
5293 _have_idled = false;
5295 _session_connections.drop_connections ();
5297 super_rapid_screen_update_connection.disconnect ();
5299 selection->clear ();
5300 cut_buffer->clear ();
5302 clicked_regionview = 0;
5303 clicked_axisview = 0;
5304 clicked_routeview = 0;
5305 entered_regionview = 0;
5307 last_update_frame = 0;
5310 playhead_cursor->hide ();
5312 /* rip everything out of the list displays */
5316 _route_groups->clear ();
5318 /* do this first so that deleting a track doesn't reset cms to null
5319 and thus cause a leak.
5322 if (current_mixer_strip) {
5323 if (current_mixer_strip->get_parent() != 0) {
5324 global_hpacker.remove (*current_mixer_strip);
5326 delete current_mixer_strip;
5327 current_mixer_strip = 0;
5330 /* delete all trackviews */
5332 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5335 track_views.clear ();
5337 zoom_range_clock->set_session (0);
5338 nudge_clock->set_session (0);
5340 editor_list_button.set_active(false);
5341 editor_list_button.set_sensitive(false);
5343 /* clear tempo/meter rulers */
5344 remove_metric_marks ();
5346 clear_marker_display ();
5348 stop_step_editing ();
5350 /* get rid of any existing editor mixer strip */
5352 WindowTitle title(Glib::get_application_name());
5353 title += _("Editor");
5355 set_title (title.get_string());
5357 SessionHandlePtr::session_going_away ();
5362 Editor::show_editor_list (bool yn)
5365 _the_notebook.show ();
5367 _the_notebook.hide ();
5372 Editor::change_region_layering_order (bool from_context_menu)
5374 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5376 if (!clicked_routeview) {
5377 if (layering_order_editor) {
5378 layering_order_editor->hide ();
5383 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5389 boost::shared_ptr<Playlist> pl = track->playlist();
5395 if (layering_order_editor == 0) {
5396 layering_order_editor = new RegionLayeringOrderEditor (*this);
5399 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5400 layering_order_editor->maybe_present ();
5404 Editor::update_region_layering_order_editor ()
5406 if (layering_order_editor && layering_order_editor->is_visible ()) {
5407 change_region_layering_order (true);
5412 Editor::setup_fade_images ()
5414 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5415 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5416 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5417 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5418 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5420 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5421 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5422 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5423 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5424 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5426 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5427 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5428 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5429 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5430 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5432 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5433 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5434 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5435 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5436 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5440 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5442 Editor::action_menu_item (std::string const & name)
5444 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5447 return *manage (a->create_menu_item ());
5451 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5453 EventBox* b = manage (new EventBox);
5454 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5455 Label* l = manage (new Label (name));
5459 _the_notebook.append_page (widget, *b);
5463 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5465 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5466 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5469 if (ev->type == GDK_2BUTTON_PRESS) {
5471 /* double-click on a notebook tab shrinks or expands the notebook */
5473 if (_notebook_shrunk) {
5474 if (pre_notebook_shrink_pane_width) {
5475 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5477 _notebook_shrunk = false;
5479 pre_notebook_shrink_pane_width = edit_pane.get_position();
5481 /* this expands the LHS of the edit pane to cover the notebook
5482 PAGE but leaves the tabs visible.
5484 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5485 _notebook_shrunk = true;
5493 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5495 using namespace Menu_Helpers;
5497 MenuList& items = _control_point_context_menu.items ();
5500 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5501 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5502 if (!can_remove_control_point (item)) {
5503 items.back().set_sensitive (false);
5506 _control_point_context_menu.popup (event->button.button, event->button.time);
5510 Editor::shift_key_released ()
5512 _stepping_axis_view = 0;