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 "control_protocol/control_protocol.h"
77 #include "analysis_window.h"
78 #include "audio_clock.h"
79 #include "audio_region_view.h"
80 #include "audio_streamview.h"
81 #include "audio_time_axis.h"
82 #include "automation_time_axis.h"
83 #include "bundle_manager.h"
84 #include "canvas-noevent-text.h"
85 #include "canvas_impl.h"
86 #include "crossfade_edit.h"
90 #include "editor_cursors.h"
91 #include "editor_drag.h"
92 #include "editor_group_tabs.h"
93 #include "editor_locations.h"
94 #include "editor_regions.h"
95 #include "editor_route_groups.h"
96 #include "editor_routes.h"
97 #include "editor_snapshots.h"
98 #include "editor_summary.h"
99 #include "global_port_matrix.h"
100 #include "gui_object.h"
101 #include "gui_thread.h"
102 #include "keyboard.h"
104 #include "midi_time_axis.h"
105 #include "mixer_strip.h"
106 #include "mixer_ui.h"
107 #include "mouse_cursors.h"
108 #include "playlist_selector.h"
109 #include "public_editor.h"
110 #include "region_layering_order_editor.h"
111 #include "rgb_macros.h"
112 #include "rhythm_ferret.h"
113 #include "selection.h"
115 #include "simpleline.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)
254 /* tool bar related */
256 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
258 , toolbar_selection_clock_table (2,3)
260 , automation_mode_button (_("mode"))
262 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
266 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
267 , meters_running(false)
268 , _pending_locate_request (false)
269 , _pending_initial_locate (false)
270 , _last_cut_copy_source_track (0)
272 , _region_selection_change_updates_region_list (true)
273 , _following_mixer_selection (false)
274 , _control_point_toggled_on_press (false)
275 , _stepping_axis_view (0)
279 /* we are a singleton */
281 PublicEditor::_instance = this;
285 selection = new Selection (this);
286 cut_buffer = new Selection (this);
288 clicked_regionview = 0;
289 clicked_axisview = 0;
290 clicked_routeview = 0;
291 clicked_control_point = 0;
292 last_update_frame = 0;
293 pre_press_cursor = 0;
294 _drags = new DragManager (this);
295 current_mixer_strip = 0;
298 snap_type_strings = I18N (_snap_type_strings);
299 snap_mode_strings = I18N (_snap_mode_strings);
300 zoom_focus_strings = I18N (_zoom_focus_strings);
301 edit_point_strings = I18N (_edit_point_strings);
302 #ifdef USE_RUBBERBAND
303 rb_opt_strings = I18N (_rb_opt_strings);
307 snap_threshold = 5.0;
308 bbt_beat_subdivision = 4;
311 last_autoscroll_x = 0;
312 last_autoscroll_y = 0;
313 autoscroll_active = false;
314 autoscroll_timeout_tag = -1;
319 current_interthread_info = 0;
320 _show_measures = true;
322 show_gain_after_trim = false;
324 have_pending_keyboard_selection = false;
325 _follow_playhead = true;
326 _stationary_playhead = false;
327 editor_ruler_menu = 0;
328 no_ruler_shown_update = false;
330 range_marker_menu = 0;
331 marker_menu_item = 0;
332 tempo_or_meter_marker_menu = 0;
333 transport_marker_menu = 0;
334 new_transport_marker_menu = 0;
335 editor_mixer_strip_width = Wide;
336 show_editor_mixer_when_tracks_arrive = false;
337 region_edit_menu_split_multichannel_item = 0;
338 region_edit_menu_split_item = 0;
341 current_stepping_trackview = 0;
343 entered_regionview = 0;
345 clear_entered_track = false;
348 button_release_can_deselect = true;
349 _dragging_playhead = false;
350 _dragging_edit_point = false;
351 select_new_marker = false;
353 layering_order_editor = 0;
354 no_save_visual = false;
356 within_track_canvas = false;
358 scrubbing_direction = 0;
362 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
363 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
364 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
365 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
366 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
368 zoom_focus = ZoomFocusLeft;
369 _edit_point = EditAtMouse;
370 _internal_editing = false;
371 current_canvas_cursor = 0;
373 frames_per_unit = 2048; /* too early to use reset_zoom () */
375 _scroll_callbacks = 0;
377 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
379 bbt_label.set_name ("EditorRulerLabel");
380 bbt_label.set_size_request (-1, (int)timebar_height);
381 bbt_label.set_alignment (1.0, 0.5);
382 bbt_label.set_padding (5,0);
384 bbt_label.set_no_show_all();
385 minsec_label.set_name ("EditorRulerLabel");
386 minsec_label.set_size_request (-1, (int)timebar_height);
387 minsec_label.set_alignment (1.0, 0.5);
388 minsec_label.set_padding (5,0);
389 minsec_label.hide ();
390 minsec_label.set_no_show_all();
391 timecode_label.set_name ("EditorRulerLabel");
392 timecode_label.set_size_request (-1, (int)timebar_height);
393 timecode_label.set_alignment (1.0, 0.5);
394 timecode_label.set_padding (5,0);
395 timecode_label.hide ();
396 timecode_label.set_no_show_all();
397 samples_label.set_name ("EditorRulerLabel");
398 samples_label.set_size_request (-1, (int)timebar_height);
399 samples_label.set_alignment (1.0, 0.5);
400 samples_label.set_padding (5,0);
401 samples_label.hide ();
402 samples_label.set_no_show_all();
404 tempo_label.set_name ("EditorRulerLabel");
405 tempo_label.set_size_request (-1, (int)timebar_height);
406 tempo_label.set_alignment (1.0, 0.5);
407 tempo_label.set_padding (5,0);
409 tempo_label.set_no_show_all();
411 meter_label.set_name ("EditorRulerLabel");
412 meter_label.set_size_request (-1, (int)timebar_height);
413 meter_label.set_alignment (1.0, 0.5);
414 meter_label.set_padding (5,0);
416 meter_label.set_no_show_all();
418 mark_label.set_name ("EditorRulerLabel");
419 mark_label.set_size_request (-1, (int)timebar_height);
420 mark_label.set_alignment (1.0, 0.5);
421 mark_label.set_padding (5,0);
423 mark_label.set_no_show_all();
425 cd_mark_label.set_name ("EditorRulerLabel");
426 cd_mark_label.set_size_request (-1, (int)timebar_height);
427 cd_mark_label.set_alignment (1.0, 0.5);
428 cd_mark_label.set_padding (5,0);
429 cd_mark_label.hide();
430 cd_mark_label.set_no_show_all();
432 videotl_bar_height = 4;
433 videotl_label.set_name ("EditorRulerLabel");
434 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
435 videotl_label.set_alignment (1.0, 0.5);
436 videotl_label.set_padding (5,0);
437 videotl_label.hide();
438 videotl_label.set_no_show_all();
440 range_mark_label.set_name ("EditorRulerLabel");
441 range_mark_label.set_size_request (-1, (int)timebar_height);
442 range_mark_label.set_alignment (1.0, 0.5);
443 range_mark_label.set_padding (5,0);
444 range_mark_label.hide();
445 range_mark_label.set_no_show_all();
447 transport_mark_label.set_name ("EditorRulerLabel");
448 transport_mark_label.set_size_request (-1, (int)timebar_height);
449 transport_mark_label.set_alignment (1.0, 0.5);
450 transport_mark_label.set_padding (5,0);
451 transport_mark_label.hide();
452 transport_mark_label.set_no_show_all();
454 initialize_rulers ();
455 initialize_canvas ();
457 _summary = new EditorSummary (this);
459 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
460 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
462 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
464 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
465 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
467 edit_controls_vbox.set_spacing (0);
468 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
469 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
471 HBox* h = manage (new HBox);
472 _group_tabs = new EditorGroupTabs (this);
473 h->pack_start (*_group_tabs, PACK_SHRINK);
474 h->pack_start (edit_controls_vbox);
475 controls_layout.add (*h);
477 controls_layout.set_name ("EditControlsBase");
478 controls_layout.add_events (Gdk::SCROLL_MASK);
479 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
481 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
482 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
484 _cursors = new MouseCursors;
486 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
487 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
488 0.0, 1.0, 100.0, 1.0));
490 pad_line_1->property_color_rgba() = 0xFF0000FF;
495 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
496 time_canvas_vbox.set_size_request (-1, -1);
498 ruler_label_event_box.add (ruler_label_vbox);
499 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
500 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
502 time_button_event_box.add (time_button_vbox);
503 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
504 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
506 /* these enable us to have a dedicated window (for cursor setting, etc.)
507 for the canvas areas.
510 track_canvas_event_box.add (*track_canvas);
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" */
524 edit_packer.attach (time_button_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);
530 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
532 bottom_hbox.set_border_width (2);
533 bottom_hbox.set_spacing (3);
535 _route_groups = new EditorRouteGroups (this);
536 _routes = new EditorRoutes (this);
537 _regions = new EditorRegions (this);
538 _snapshots = new EditorSnapshots (this);
539 _locations = new EditorLocations (this);
541 add_notebook_page (_("Regions"), _regions->widget ());
542 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
543 add_notebook_page (_("Snapshots"), _snapshots->widget ());
544 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
545 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
547 _the_notebook.set_show_tabs (true);
548 _the_notebook.set_scrollable (true);
549 _the_notebook.popup_disable ();
550 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
551 _the_notebook.show_all ();
553 _notebook_shrunk = false;
555 editor_summary_pane.pack1(edit_packer);
557 Button* summary_arrows_left_left = manage (new Button);
558 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
559 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
560 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
562 Button* summary_arrows_left_right = manage (new Button);
563 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
564 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
565 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
567 VBox* summary_arrows_left = manage (new VBox);
568 summary_arrows_left->pack_start (*summary_arrows_left_left);
569 summary_arrows_left->pack_start (*summary_arrows_left_right);
571 Button* summary_arrows_right_up = manage (new Button);
572 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
573 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
574 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 Button* summary_arrows_right_down = manage (new Button);
577 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
578 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
579 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
581 VBox* summary_arrows_right = manage (new VBox);
582 summary_arrows_right->pack_start (*summary_arrows_right_up);
583 summary_arrows_right->pack_start (*summary_arrows_right_down);
585 Frame* summary_frame = manage (new Frame);
586 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
588 summary_frame->add (*_summary);
589 summary_frame->show ();
591 _summary_hbox.pack_start (*summary_arrows_left, false, false);
592 _summary_hbox.pack_start (*summary_frame, true, true);
593 _summary_hbox.pack_start (*summary_arrows_right, false, false);
595 editor_summary_pane.pack2 (_summary_hbox);
597 edit_pane.pack1 (editor_summary_pane, true, true);
598 edit_pane.pack2 (_the_notebook, false, true);
600 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
602 /* XXX: editor_summary_pane might need similar to the edit_pane */
604 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
606 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
607 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
609 top_hbox.pack_start (toolbar_frame);
611 HBox *hbox = manage (new HBox);
612 hbox->pack_start (edit_pane, true, true);
614 global_vpacker.pack_start (top_hbox, false, false);
615 global_vpacker.pack_start (*hbox, true, true);
617 global_hpacker.pack_start (global_vpacker, true, true);
619 set_name ("EditorWindow");
620 add_accel_group (ActionManager::ui_manager->get_accel_group());
622 status_bar_hpacker.show ();
624 vpacker.pack_end (status_bar_hpacker, false, false);
625 vpacker.pack_end (global_hpacker, true, true);
627 /* register actions now so that set_state() can find them and set toggles/checks etc */
630 /* when we start using our own keybinding system for the editor, this
631 * will be uncommented
637 set_zoom_focus (zoom_focus);
638 _snap_type = SnapToBeat;
639 set_snap_to (_snap_type);
640 _snap_mode = SnapOff;
641 set_snap_mode (_snap_mode);
642 set_mouse_mode (MouseObject, true);
643 pre_internal_mouse_mode = MouseObject;
644 pre_internal_snap_type = _snap_type;
645 pre_internal_snap_mode = _snap_mode;
646 internal_snap_type = _snap_type;
647 internal_snap_mode = _snap_mode;
648 set_edit_point_preference (EditAtMouse, true);
650 _playlist_selector = new PlaylistSelector();
651 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
653 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
657 nudge_forward_button.set_name ("zoom button");
658 nudge_forward_button.add_elements (ArdourButton::FlatFace);
659 nudge_forward_button.set_image(::get_icon("nudge_right"));
661 nudge_backward_button.set_name ("zoom button");
662 nudge_backward_button.add_elements (ArdourButton::FlatFace);
663 nudge_backward_button.set_image(::get_icon("nudge_left"));
665 fade_context_menu.set_name ("ArdourContextMenu");
667 /* icons, titles, WM stuff */
669 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
670 Glib::RefPtr<Gdk::Pixbuf> icon;
672 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
673 window_icons.push_back (icon);
675 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
676 window_icons.push_back (icon);
678 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
679 window_icons.push_back (icon);
681 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
682 window_icons.push_back (icon);
684 if (!window_icons.empty()) {
685 // set_icon_list (window_icons);
686 set_default_icon_list (window_icons);
689 WindowTitle title(Glib::get_application_name());
690 title += _("Editor");
691 set_title (title.get_string());
692 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
695 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
697 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
698 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
700 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
702 /* allow external control surfaces/protocols to do various things */
704 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
705 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
706 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
707 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
708 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
709 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
710 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
711 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
712 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
713 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
714 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
715 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
716 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
717 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
719 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
720 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
721 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
722 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
723 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
725 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
727 /* problematic: has to return a value and thus cannot be x-thread */
729 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
731 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
733 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
735 _ignore_region_action = false;
736 _last_region_menu_was_main = false;
737 _popup_region_menu_item = 0;
739 _show_marker_lines = false;
740 _over_region_trim_target = false;
742 /* Button bindings */
744 button_bindings = new Bindings;
746 XMLNode* node = button_settings();
748 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
749 button_bindings->load (**i);
756 setup_fade_images ();
761 delete button_bindings;
763 delete _route_groups;
769 Editor::button_settings () const
771 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
772 XMLNode* node = find_named_node (*settings, X_("Buttons"));
775 node = new XMLNode (X_("Buttons"));
782 Editor::add_toplevel_controls (Container& cont)
784 vpacker.pack_start (cont, false, false);
789 Editor::get_smart_mode () const
791 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
795 Editor::catch_vanishing_regionview (RegionView *rv)
797 /* note: the selection will take care of the vanishing
798 audioregionview by itself.
801 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
805 if (clicked_regionview == rv) {
806 clicked_regionview = 0;
809 if (entered_regionview == rv) {
810 set_entered_regionview (0);
813 if (!_all_region_actions_sensitized) {
814 sensitize_all_region_actions (true);
817 _over_region_trim_target = false;
821 Editor::set_entered_regionview (RegionView* rv)
823 if (rv == entered_regionview) {
827 if (entered_regionview) {
828 entered_regionview->exited ();
831 if ((entered_regionview = rv) != 0) {
832 entered_regionview->entered (internal_editing ());
835 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
836 /* This RegionView entry might have changed what region actions
837 are allowed, so sensitize them all in case a key is pressed.
839 sensitize_all_region_actions (true);
844 Editor::set_entered_track (TimeAxisView* tav)
847 entered_track->exited ();
850 if ((entered_track = tav) != 0) {
851 entered_track->entered ();
856 Editor::show_window ()
858 if (!is_visible ()) {
861 /* XXX: this is a bit unfortunate; it would probably
862 be nicer if we could just call show () above rather
863 than needing the show_all ()
866 /* re-hide stuff if necessary */
867 editor_list_button_toggled ();
868 parameter_changed ("show-summary");
869 parameter_changed ("show-group-tabs");
870 parameter_changed ("show-zoom-tools");
872 /* now reset all audio_time_axis heights, because widgets might need
878 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
879 tv = (static_cast<TimeAxisView*>(*i));
883 if (current_mixer_strip) {
884 current_mixer_strip->hide_things ();
885 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
893 Editor::instant_save ()
895 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
900 _session->add_instant_xml(get_state());
902 Config->add_instant_xml(get_state());
907 Editor::zoom_adjustment_changed ()
913 double fpu = zoom_range_clock->current_duration() / _canvas_width;
914 bool clamped = clamp_frames_per_unit (fpu);
917 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
924 Editor::control_vertical_zoom_in_all ()
926 tav_zoom_smooth (false, true);
930 Editor::control_vertical_zoom_out_all ()
932 tav_zoom_smooth (true, true);
936 Editor::control_vertical_zoom_in_selected ()
938 tav_zoom_smooth (false, false);
942 Editor::control_vertical_zoom_out_selected ()
944 tav_zoom_smooth (true, false);
948 Editor::control_view (uint32_t view)
950 goto_visual_state (view);
954 Editor::control_unselect ()
956 selection->clear_tracks ();
960 Editor::control_select (uint32_t rid, Selection::Operation op)
962 /* handles the (static) signal from the ControlProtocol class that
963 * requests setting the selected track to a given RID
970 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
976 TimeAxisView* tav = axis_view_from_route (r);
981 selection->add (tav);
983 case Selection::Toggle:
984 selection->toggle (tav);
986 case Selection::Extend:
989 selection->set (tav);
993 selection->clear_tracks ();
998 Editor::control_step_tracks_up ()
1000 scroll_tracks_up_line ();
1004 Editor::control_step_tracks_down ()
1006 scroll_tracks_down_line ();
1010 Editor::control_scroll (float fraction)
1012 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1018 double step = fraction * current_page_frames();
1021 _control_scroll_target is an optional<T>
1023 it acts like a pointer to an framepos_t, with
1024 a operator conversion to boolean to check
1025 that it has a value could possibly use
1026 playhead_cursor->current_frame to store the
1027 value and a boolean in the class to know
1028 when it's out of date
1031 if (!_control_scroll_target) {
1032 _control_scroll_target = _session->transport_frame();
1033 _dragging_playhead = true;
1036 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1037 *_control_scroll_target = 0;
1038 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1039 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1041 *_control_scroll_target += (framepos_t) floor (step);
1044 /* move visuals, we'll catch up with it later */
1046 playhead_cursor->set_position (*_control_scroll_target);
1047 UpdateAllTransportClocks (*_control_scroll_target);
1049 if (*_control_scroll_target > (current_page_frames() / 2)) {
1050 /* try to center PH in window */
1051 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1057 Now we do a timeout to actually bring the session to the right place
1058 according to the playhead. This is to avoid reading disk buffers on every
1059 call to control_scroll, which is driven by ScrollTimeline and therefore
1060 probably by a control surface wheel which can generate lots of events.
1062 /* cancel the existing timeout */
1064 control_scroll_connection.disconnect ();
1066 /* add the next timeout */
1068 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1072 Editor::deferred_control_scroll (framepos_t /*target*/)
1074 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1075 // reset for next stream
1076 _control_scroll_target = boost::none;
1077 _dragging_playhead = false;
1082 Editor::access_action (std::string action_group, std::string action_item)
1088 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1091 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1099 Editor::on_realize ()
1101 Window::on_realize ();
1106 Editor::map_position_change (framepos_t frame)
1108 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1110 if (_session == 0) {
1114 if (_follow_playhead) {
1115 center_screen (frame);
1118 playhead_cursor->set_position (frame);
1122 Editor::center_screen (framepos_t frame)
1124 double page = _canvas_width * frames_per_unit;
1126 /* if we're off the page, then scroll.
1129 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1130 center_screen_internal (frame, page);
1135 Editor::center_screen_internal (framepos_t frame, float page)
1140 frame -= (framepos_t) page;
1145 reset_x_origin (frame);
1150 Editor::update_title ()
1152 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1155 bool dirty = _session->dirty();
1157 string session_name;
1159 if (_session->snap_name() != _session->name()) {
1160 session_name = _session->snap_name();
1162 session_name = _session->name();
1166 session_name = "*" + session_name;
1169 WindowTitle title(session_name);
1170 title += Glib::get_application_name();
1171 set_title (title.get_string());
1173 /* ::session_going_away() will have taken care of it */
1178 Editor::set_session (Session *t)
1180 SessionHandlePtr::set_session (t);
1186 zoom_range_clock->set_session (_session);
1187 _playlist_selector->set_session (_session);
1188 nudge_clock->set_session (_session);
1189 _summary->set_session (_session);
1190 _group_tabs->set_session (_session);
1191 _route_groups->set_session (_session);
1192 _regions->set_session (_session);
1193 _snapshots->set_session (_session);
1194 _routes->set_session (_session);
1195 _locations->set_session (_session);
1197 if (rhythm_ferret) {
1198 rhythm_ferret->set_session (_session);
1201 if (analysis_window) {
1202 analysis_window->set_session (_session);
1206 sfbrowser->set_session (_session);
1209 compute_fixed_ruler_scale ();
1211 /* Make sure we have auto loop and auto punch ranges */
1213 Location* loc = _session->locations()->auto_loop_location();
1215 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1217 if (loc->start() == loc->end()) {
1218 loc->set_end (loc->start() + 1);
1221 _session->locations()->add (loc, false);
1222 _session->set_auto_loop_location (loc);
1225 loc->set_name (_("Loop"));
1228 loc = _session->locations()->auto_punch_location();
1231 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1233 if (loc->start() == loc->end()) {
1234 loc->set_end (loc->start() + 1);
1237 _session->locations()->add (loc, false);
1238 _session->set_auto_punch_location (loc);
1241 loc->set_name (_("Punch"));
1244 refresh_location_display ();
1246 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1247 the selected Marker; this needs the LocationMarker list to be available.
1249 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1250 set_state (*node, Stateful::loading_state_version);
1252 /* catch up with the playhead */
1254 _session->request_locate (playhead_cursor->current_frame);
1255 _pending_initial_locate = true;
1259 /* These signals can all be emitted by a non-GUI thread. Therefore the
1260 handlers for them must not attempt to directly interact with the GUI,
1261 but use PBD::Signal<T>::connect() which accepts an event loop
1262 ("context") where the handler will be asked to run.
1265 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1266 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1267 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1268 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1269 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1270 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1271 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1272 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1273 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1274 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1275 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1276 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1277 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1278 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1280 playhead_cursor->canvas_item.show ();
1282 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1283 Config->map_parameters (pc);
1284 _session->config.map_parameters (pc);
1286 restore_ruler_visibility ();
1287 //tempo_map_changed (PropertyChange (0));
1288 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1290 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1291 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1294 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1295 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1298 switch (_snap_type) {
1299 case SnapToRegionStart:
1300 case SnapToRegionEnd:
1301 case SnapToRegionSync:
1302 case SnapToRegionBoundary:
1303 build_region_boundary_cache ();
1310 /* register for undo history */
1311 _session->register_with_memento_command_factory(id(), this);
1313 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1315 start_updating_meters ();
1319 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1321 if (a->get_name() == "RegionMenu") {
1322 /* When the main menu's region menu is opened, we setup the actions so that they look right
1323 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1324 so we resensitize all region actions when the entered regionview or the region selection
1325 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1326 happens after the region context menu is opened. So we set a flag here, too.
1330 sensitize_the_right_region_actions ();
1331 _last_region_menu_was_main = true;
1336 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1338 using namespace Menu_Helpers;
1340 void (Editor::*emf)(FadeShape);
1341 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1344 images = &_xfade_in_images;
1345 emf = &Editor::set_fade_in_shape;
1347 images = &_xfade_out_images;
1348 emf = &Editor::set_fade_out_shape;
1353 _("Linear (for highly correlated material)"),
1354 *(*images)[FadeLinear],
1355 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1359 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1363 _("Constant power"),
1364 *(*images)[FadeConstantPower],
1365 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1368 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1373 *(*images)[FadeSymmetric],
1374 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1378 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1383 *(*images)[FadeSlow],
1384 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1387 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1392 *(*images)[FadeFast],
1393 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1396 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 /** Pop up a context menu for when the user clicks on a start crossfade */
1401 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1403 using namespace Menu_Helpers;
1405 MenuList& items (xfade_in_context_menu.items());
1407 if (items.empty()) {
1408 fill_xfade_menu (items, true);
1411 xfade_in_context_menu.popup (button, time);
1414 /** Pop up a context menu for when the user clicks on an end crossfade */
1416 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1418 using namespace Menu_Helpers;
1420 MenuList& items (xfade_out_context_menu.items());
1422 if (items.empty()) {
1423 fill_xfade_menu (items, false);
1426 xfade_out_context_menu.popup (button, time);
1430 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1432 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1434 using namespace Menu_Helpers;
1435 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1438 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1442 MenuList& items (fade_context_menu.items());
1445 switch (item_type) {
1447 case FadeInHandleItem:
1448 if (arv->audio_region()->fade_in_active()) {
1449 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1451 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1454 items.push_back (SeparatorElem());
1456 if (Profile->get_sae()) {
1458 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1459 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1466 *_fade_in_images[FadeLinear],
1467 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1471 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1476 *_fade_in_images[FadeSlow],
1477 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *_fade_in_images[FadeFast],
1486 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *_fade_in_images[FadeSymmetric],
1495 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1500 _("Constant power"),
1501 *_fade_in_images[FadeConstantPower],
1502 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1505 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1511 case FadeOutHandleItem:
1512 if (arv->audio_region()->fade_out_active()) {
1513 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1515 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1518 items.push_back (SeparatorElem());
1520 if (Profile->get_sae()) {
1521 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1522 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1528 *_fade_out_images[FadeLinear],
1529 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1533 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1538 *_fade_out_images[FadeSlow],
1539 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1542 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1547 *_fade_out_images[FadeFast],
1548 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1551 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1556 *_fade_out_images[FadeSymmetric],
1557 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1562 _("Constant power"),
1563 *_fade_out_images[FadeConstantPower],
1564 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1567 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1573 fatal << _("programming error: ")
1574 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1579 fade_context_menu.popup (button, time);
1583 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1585 using namespace Menu_Helpers;
1586 Menu* (Editor::*build_menu_function)();
1589 switch (item_type) {
1591 case RegionViewName:
1592 case RegionViewNameHighlight:
1593 case LeftFrameHandle:
1594 case RightFrameHandle:
1595 if (with_selection) {
1596 build_menu_function = &Editor::build_track_selection_context_menu;
1598 build_menu_function = &Editor::build_track_region_context_menu;
1603 if (with_selection) {
1604 build_menu_function = &Editor::build_track_selection_context_menu;
1606 build_menu_function = &Editor::build_track_context_menu;
1611 if (clicked_routeview->track()) {
1612 build_menu_function = &Editor::build_track_context_menu;
1614 build_menu_function = &Editor::build_track_bus_context_menu;
1619 /* probably shouldn't happen but if it does, we don't care */
1623 menu = (this->*build_menu_function)();
1624 menu->set_name ("ArdourContextMenu");
1626 /* now handle specific situations */
1628 switch (item_type) {
1630 case RegionViewName:
1631 case RegionViewNameHighlight:
1632 case LeftFrameHandle:
1633 case RightFrameHandle:
1634 if (!with_selection) {
1635 if (region_edit_menu_split_item) {
1636 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1637 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1639 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1642 if (region_edit_menu_split_multichannel_item) {
1643 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1644 region_edit_menu_split_multichannel_item->set_sensitive (true);
1646 region_edit_menu_split_multichannel_item->set_sensitive (false);
1659 /* probably shouldn't happen but if it does, we don't care */
1663 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1665 /* Bounce to disk */
1667 using namespace Menu_Helpers;
1668 MenuList& edit_items = menu->items();
1670 edit_items.push_back (SeparatorElem());
1672 switch (clicked_routeview->audio_track()->freeze_state()) {
1673 case AudioTrack::NoFreeze:
1674 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1677 case AudioTrack::Frozen:
1678 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1681 case AudioTrack::UnFrozen:
1682 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1688 if (item_type == StreamItem && clicked_routeview) {
1689 clicked_routeview->build_underlay_menu(menu);
1692 /* When the region menu is opened, we setup the actions so that they look right
1695 sensitize_the_right_region_actions ();
1696 _last_region_menu_was_main = false;
1698 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1699 menu->popup (button, time);
1703 Editor::build_track_context_menu ()
1705 using namespace Menu_Helpers;
1707 MenuList& edit_items = track_context_menu.items();
1710 add_dstream_context_items (edit_items);
1711 return &track_context_menu;
1715 Editor::build_track_bus_context_menu ()
1717 using namespace Menu_Helpers;
1719 MenuList& edit_items = track_context_menu.items();
1722 add_bus_context_items (edit_items);
1723 return &track_context_menu;
1727 Editor::build_track_region_context_menu ()
1729 using namespace Menu_Helpers;
1730 MenuList& edit_items = track_region_context_menu.items();
1733 /* we've just cleared the track region context menu, so the menu that these
1734 two items were on will have disappeared; stop them dangling.
1736 region_edit_menu_split_item = 0;
1737 region_edit_menu_split_multichannel_item = 0;
1739 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1742 boost::shared_ptr<Track> tr;
1743 boost::shared_ptr<Playlist> pl;
1745 if ((tr = rtv->track())) {
1746 add_region_context_items (edit_items, tr);
1750 add_dstream_context_items (edit_items);
1752 return &track_region_context_menu;
1756 Editor::analyze_region_selection ()
1758 if (analysis_window == 0) {
1759 analysis_window = new AnalysisWindow();
1762 analysis_window->set_session(_session);
1764 analysis_window->show_all();
1767 analysis_window->set_regionmode();
1768 analysis_window->analyze();
1770 analysis_window->present();
1774 Editor::analyze_range_selection()
1776 if (analysis_window == 0) {
1777 analysis_window = new AnalysisWindow();
1780 analysis_window->set_session(_session);
1782 analysis_window->show_all();
1785 analysis_window->set_rangemode();
1786 analysis_window->analyze();
1788 analysis_window->present();
1792 Editor::build_track_selection_context_menu ()
1794 using namespace Menu_Helpers;
1795 MenuList& edit_items = track_selection_context_menu.items();
1796 edit_items.clear ();
1798 add_selection_context_items (edit_items);
1799 // edit_items.push_back (SeparatorElem());
1800 // add_dstream_context_items (edit_items);
1802 return &track_selection_context_menu;
1806 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1808 using namespace Menu_Helpers;
1810 /* OK, stick the region submenu at the top of the list, and then add
1814 RegionSelection rs = get_regions_from_selection_and_entered ();
1816 string::size_type pos = 0;
1817 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1819 /* we have to hack up the region name because "_" has a special
1820 meaning for menu titles.
1823 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1824 menu_item_name.replace (pos, 1, "__");
1828 if (_popup_region_menu_item == 0) {
1829 _popup_region_menu_item = new MenuItem (menu_item_name);
1830 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1831 _popup_region_menu_item->show ();
1833 _popup_region_menu_item->set_label (menu_item_name);
1836 const framepos_t position = get_preferred_edit_position (false, true);
1838 edit_items.push_back (*_popup_region_menu_item);
1839 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1840 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1842 edit_items.push_back (SeparatorElem());
1845 /** Add context menu items relevant to selection ranges.
1846 * @param edit_items List to add the items to.
1849 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1851 using namespace Menu_Helpers;
1853 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1854 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1856 edit_items.push_back (SeparatorElem());
1857 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1859 edit_items.push_back (SeparatorElem());
1861 edit_items.push_back (
1863 _("Move Range Start to Previous Region Boundary"),
1864 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1868 edit_items.push_back (
1870 _("Move Range Start to Next Region Boundary"),
1871 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1875 edit_items.push_back (
1877 _("Move Range End to Previous Region Boundary"),
1878 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1882 edit_items.push_back (
1884 _("Move Range End to Next Region Boundary"),
1885 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1889 edit_items.push_back (SeparatorElem());
1890 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1891 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1893 edit_items.push_back (SeparatorElem());
1894 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1898 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1900 edit_items.push_back (SeparatorElem());
1901 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1905 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1906 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1908 edit_items.push_back (SeparatorElem());
1909 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1910 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1911 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1912 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1913 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1918 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1920 using namespace Menu_Helpers;
1924 Menu *play_menu = manage (new Menu);
1925 MenuList& play_items = play_menu->items();
1926 play_menu->set_name ("ArdourContextMenu");
1928 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1929 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1930 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1931 play_items.push_back (SeparatorElem());
1932 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1934 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1938 Menu *select_menu = manage (new Menu);
1939 MenuList& select_items = select_menu->items();
1940 select_menu->set_name ("ArdourContextMenu");
1942 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1943 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1944 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1945 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1946 select_items.push_back (SeparatorElem());
1947 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1948 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1949 select_items.push_back (SeparatorElem());
1950 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1951 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1952 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1953 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1954 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1955 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1956 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1958 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1962 Menu *cutnpaste_menu = manage (new Menu);
1963 MenuList& cutnpaste_items = cutnpaste_menu->items();
1964 cutnpaste_menu->set_name ("ArdourContextMenu");
1966 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1967 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1968 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1970 cutnpaste_items.push_back (SeparatorElem());
1972 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1973 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1975 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1977 /* Adding new material */
1979 edit_items.push_back (SeparatorElem());
1980 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1981 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1985 Menu *nudge_menu = manage (new Menu());
1986 MenuList& nudge_items = nudge_menu->items();
1987 nudge_menu->set_name ("ArdourContextMenu");
1989 edit_items.push_back (SeparatorElem());
1990 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1991 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1992 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1993 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1995 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1999 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2001 using namespace Menu_Helpers;
2005 Menu *play_menu = manage (new Menu);
2006 MenuList& play_items = play_menu->items();
2007 play_menu->set_name ("ArdourContextMenu");
2009 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2010 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2011 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2015 Menu *select_menu = manage (new Menu);
2016 MenuList& select_items = select_menu->items();
2017 select_menu->set_name ("ArdourContextMenu");
2019 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2020 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2021 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2022 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2023 select_items.push_back (SeparatorElem());
2024 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2025 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2026 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2027 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2029 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2033 Menu *cutnpaste_menu = manage (new Menu);
2034 MenuList& cutnpaste_items = cutnpaste_menu->items();
2035 cutnpaste_menu->set_name ("ArdourContextMenu");
2037 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2038 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2039 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2041 Menu *nudge_menu = manage (new Menu());
2042 MenuList& nudge_items = nudge_menu->items();
2043 nudge_menu->set_name ("ArdourContextMenu");
2045 edit_items.push_back (SeparatorElem());
2046 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2047 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2048 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2049 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2051 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2055 Editor::snap_type() const
2061 Editor::snap_mode() const
2067 Editor::set_snap_to (SnapType st)
2069 unsigned int snap_ind = (unsigned int)st;
2073 if (snap_ind > snap_type_strings.size() - 1) {
2075 _snap_type = (SnapType)snap_ind;
2078 string str = snap_type_strings[snap_ind];
2080 if (str != snap_type_selector.get_active_text()) {
2081 snap_type_selector.set_active_text (str);
2086 switch (_snap_type) {
2087 case SnapToBeatDiv128:
2088 case SnapToBeatDiv64:
2089 case SnapToBeatDiv32:
2090 case SnapToBeatDiv28:
2091 case SnapToBeatDiv24:
2092 case SnapToBeatDiv20:
2093 case SnapToBeatDiv16:
2094 case SnapToBeatDiv14:
2095 case SnapToBeatDiv12:
2096 case SnapToBeatDiv10:
2097 case SnapToBeatDiv8:
2098 case SnapToBeatDiv7:
2099 case SnapToBeatDiv6:
2100 case SnapToBeatDiv5:
2101 case SnapToBeatDiv4:
2102 case SnapToBeatDiv3:
2103 case SnapToBeatDiv2: {
2104 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2105 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2107 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2108 current_bbt_points_begin, current_bbt_points_end);
2109 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2110 current_bbt_points_begin, current_bbt_points_end);
2111 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2115 case SnapToRegionStart:
2116 case SnapToRegionEnd:
2117 case SnapToRegionSync:
2118 case SnapToRegionBoundary:
2119 build_region_boundary_cache ();
2127 SnapChanged (); /* EMIT SIGNAL */
2131 Editor::set_snap_mode (SnapMode mode)
2133 string str = snap_mode_strings[(int)mode];
2135 if (_internal_editing) {
2136 internal_snap_mode = mode;
2138 pre_internal_snap_mode = mode;
2143 if (str != snap_mode_selector.get_active_text ()) {
2144 snap_mode_selector.set_active_text (str);
2150 Editor::set_edit_point_preference (EditPoint ep, bool force)
2152 bool changed = (_edit_point != ep);
2155 string str = edit_point_strings[(int)ep];
2157 if (str != edit_point_selector.get_active_text ()) {
2158 edit_point_selector.set_active_text (str);
2161 set_canvas_cursor ();
2163 if (!force && !changed) {
2167 const char* action=NULL;
2169 switch (_edit_point) {
2170 case EditAtPlayhead:
2171 action = "edit-at-playhead";
2173 case EditAtSelectedMarker:
2174 action = "edit-at-marker";
2177 action = "edit-at-mouse";
2181 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2183 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2187 bool in_track_canvas;
2189 if (!mouse_frame (foo, in_track_canvas)) {
2190 in_track_canvas = false;
2193 reset_canvas_action_sensitivity (in_track_canvas);
2199 Editor::set_state (const XMLNode& node, int /*version*/)
2201 const XMLProperty* prop;
2208 g.base_width = default_width;
2209 g.base_height = default_height;
2213 if ((geometry = find_named_node (node, "geometry")) != 0) {
2217 if ((prop = geometry->property("x_size")) == 0) {
2218 prop = geometry->property ("x-size");
2221 g.base_width = atoi(prop->value());
2223 if ((prop = geometry->property("y_size")) == 0) {
2224 prop = geometry->property ("y-size");
2227 g.base_height = atoi(prop->value());
2230 if ((prop = geometry->property ("x_pos")) == 0) {
2231 prop = geometry->property ("x-pos");
2234 x = atoi (prop->value());
2237 if ((prop = geometry->property ("y_pos")) == 0) {
2238 prop = geometry->property ("y-pos");
2241 y = atoi (prop->value());
2245 set_default_size (g.base_width, g.base_height);
2248 if (_session && (prop = node.property ("playhead"))) {
2250 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2251 playhead_cursor->set_position (pos);
2253 playhead_cursor->set_position (0);
2256 if ((prop = node.property ("mixer-width"))) {
2257 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2260 if ((prop = node.property ("zoom-focus"))) {
2261 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2264 if ((prop = node.property ("zoom"))) {
2265 reset_zoom (PBD::atof (prop->value()));
2267 reset_zoom (frames_per_unit);
2270 if ((prop = node.property ("snap-to"))) {
2271 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2274 if ((prop = node.property ("snap-mode"))) {
2275 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2278 if ((prop = node.property ("internal-snap-to"))) {
2279 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2282 if ((prop = node.property ("internal-snap-mode"))) {
2283 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2286 if ((prop = node.property ("pre-internal-snap-to"))) {
2287 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2291 if ((prop = node.property ("pre-internal-snap-mode"))) {
2292 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2295 if ((prop = node.property ("mouse-mode"))) {
2296 MouseMode m = str2mousemode(prop->value());
2297 set_mouse_mode (m, true);
2299 set_mouse_mode (MouseObject, true);
2302 if ((prop = node.property ("left-frame")) != 0) {
2304 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2308 reset_x_origin (pos);
2312 if ((prop = node.property ("y-origin")) != 0) {
2313 reset_y_origin (atof (prop->value ()));
2316 if ((prop = node.property ("internal-edit"))) {
2317 bool yn = string_is_affirmative (prop->value());
2318 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2320 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2321 tact->set_active (!yn);
2322 tact->set_active (yn);
2326 if ((prop = node.property ("join-object-range"))) {
2327 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2328 bool yn = string_is_affirmative (prop->value());
2330 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2331 tact->set_active (!yn);
2332 tact->set_active (yn);
2334 set_mouse_mode(mouse_mode, true);
2337 if ((prop = node.property ("edit-point"))) {
2338 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2341 if ((prop = node.property ("show-measures"))) {
2342 bool yn = string_is_affirmative (prop->value());
2343 _show_measures = yn;
2344 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2346 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2347 /* do it twice to force the change */
2348 tact->set_active (!yn);
2349 tact->set_active (yn);
2353 if ((prop = node.property ("follow-playhead"))) {
2354 bool yn = string_is_affirmative (prop->value());
2355 set_follow_playhead (yn);
2356 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2358 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2359 if (tact->get_active() != yn) {
2360 tact->set_active (yn);
2365 if ((prop = node.property ("stationary-playhead"))) {
2366 bool yn = string_is_affirmative (prop->value());
2367 set_stationary_playhead (yn);
2368 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2370 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2371 if (tact->get_active() != yn) {
2372 tact->set_active (yn);
2377 if ((prop = node.property ("region-list-sort-type"))) {
2378 RegionListSortType st;
2379 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2382 if ((prop = node.property ("show-editor-mixer"))) {
2384 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2387 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2388 bool yn = string_is_affirmative (prop->value());
2390 /* do it twice to force the change */
2392 tact->set_active (!yn);
2393 tact->set_active (yn);
2396 if ((prop = node.property ("show-editor-list"))) {
2398 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2401 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2402 bool yn = string_is_affirmative (prop->value());
2404 /* do it twice to force the change */
2406 tact->set_active (!yn);
2407 tact->set_active (yn);
2410 if ((prop = node.property (X_("editor-list-page")))) {
2411 _the_notebook.set_current_page (atoi (prop->value ()));
2414 if ((prop = node.property (X_("show-marker-lines")))) {
2415 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2417 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2418 bool yn = string_is_affirmative (prop->value ());
2420 tact->set_active (!yn);
2421 tact->set_active (yn);
2424 XMLNodeList children = node.children ();
2425 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2426 selection->set_state (**i, Stateful::current_state_version);
2427 _regions->set_state (**i);
2430 if ((prop = node.property ("maximised"))) {
2431 bool yn = string_is_affirmative (prop->value());
2433 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2437 if ((prop = node.property ("nudge-clock-value"))) {
2439 sscanf (prop->value().c_str(), "%" PRId64, &f);
2440 nudge_clock->set (f);
2442 nudge_clock->set_mode (AudioClock::Timecode);
2443 nudge_clock->set (_session->frame_rate() * 5, true);
2450 Editor::get_state ()
2452 XMLNode* node = new XMLNode ("Editor");
2455 id().print (buf, sizeof (buf));
2456 node->add_property ("id", buf);
2458 if (is_realized()) {
2459 Glib::RefPtr<Gdk::Window> win = get_window();
2461 int x, y, width, height;
2462 win->get_root_origin(x, y);
2463 win->get_size(width, height);
2465 XMLNode* geometry = new XMLNode ("geometry");
2467 snprintf(buf, sizeof(buf), "%d", width);
2468 geometry->add_property("x-size", string(buf));
2469 snprintf(buf, sizeof(buf), "%d", height);
2470 geometry->add_property("y-size", string(buf));
2471 snprintf(buf, sizeof(buf), "%d", x);
2472 geometry->add_property("x-pos", string(buf));
2473 snprintf(buf, sizeof(buf), "%d", y);
2474 geometry->add_property("y-pos", string(buf));
2475 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2476 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2477 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2478 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2479 geometry->add_property("edit-vertical-pane-pos", string(buf));
2481 node->add_child_nocopy (*geometry);
2484 maybe_add_mixer_strip_width (*node);
2486 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2487 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2488 node->add_property ("zoom", buf);
2489 node->add_property ("snap-to", enum_2_string (_snap_type));
2490 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2491 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2492 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2493 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2494 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2495 node->add_property ("edit-point", enum_2_string (_edit_point));
2497 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2498 node->add_property ("playhead", buf);
2499 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2500 node->add_property ("left-frame", buf);
2501 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2502 node->add_property ("y-origin", buf);
2504 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2505 node->add_property ("maximised", _maximised ? "yes" : "no");
2506 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2507 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2508 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2509 node->add_property ("mouse-mode", enum2str(mouse_mode));
2510 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2511 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2513 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2515 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2516 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2519 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2521 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2522 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2525 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2526 node->add_property (X_("editor-list-page"), buf);
2528 if (button_bindings) {
2529 XMLNode* bb = new XMLNode (X_("Buttons"));
2530 button_bindings->save (*bb);
2531 node->add_child_nocopy (*bb);
2534 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2536 node->add_child_nocopy (selection->get_state ());
2537 node->add_child_nocopy (_regions->get_state ());
2539 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2540 node->add_property ("nudge-clock-value", buf);
2547 /** @param y y offset from the top of all trackviews.
2548 * @return pair: TimeAxisView that y is over, layer index.
2549 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2550 * in stacked or expanded region display mode, otherwise 0.
2552 std::pair<TimeAxisView *, double>
2553 Editor::trackview_by_y_position (double y)
2555 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2557 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2563 return std::make_pair ( (TimeAxisView *) 0, 0);
2566 /** Snap a position to the grid, if appropriate, taking into account current
2567 * grid settings and also the state of any snap modifier keys that may be pressed.
2568 * @param start Position to snap.
2569 * @param event Event to get current key modifier information from, or 0.
2572 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2574 if (!_session || !event) {
2578 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2579 if (_snap_mode == SnapOff) {
2580 snap_to_internal (start, direction, for_mark);
2583 if (_snap_mode != SnapOff) {
2584 snap_to_internal (start, direction, for_mark);
2590 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2592 if (!_session || _snap_mode == SnapOff) {
2596 snap_to_internal (start, direction, for_mark);
2600 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2602 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2603 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2605 switch (_snap_type) {
2606 case SnapToTimecodeFrame:
2607 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2608 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2610 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2614 case SnapToTimecodeSeconds:
2615 if (_session->config.get_timecode_offset_negative()) {
2616 start += _session->config.get_timecode_offset ();
2618 start -= _session->config.get_timecode_offset ();
2620 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2621 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2623 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2626 if (_session->config.get_timecode_offset_negative()) {
2627 start -= _session->config.get_timecode_offset ();
2629 start += _session->config.get_timecode_offset ();
2633 case SnapToTimecodeMinutes:
2634 if (_session->config.get_timecode_offset_negative()) {
2635 start += _session->config.get_timecode_offset ();
2637 start -= _session->config.get_timecode_offset ();
2639 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2640 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2642 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2644 if (_session->config.get_timecode_offset_negative()) {
2645 start -= _session->config.get_timecode_offset ();
2647 start += _session->config.get_timecode_offset ();
2651 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2657 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2659 const framepos_t one_second = _session->frame_rate();
2660 const framepos_t one_minute = _session->frame_rate() * 60;
2661 framepos_t presnap = start;
2665 switch (_snap_type) {
2666 case SnapToTimecodeFrame:
2667 case SnapToTimecodeSeconds:
2668 case SnapToTimecodeMinutes:
2669 return timecode_snap_to_internal (start, direction, for_mark);
2672 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2673 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2675 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2680 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2681 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2683 start = (framepos_t) floor ((double) start / one_second) * one_second;
2688 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2689 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2691 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2696 start = _session->tempo_map().round_to_bar (start, direction);
2700 start = _session->tempo_map().round_to_beat (start, direction);
2703 case SnapToBeatDiv128:
2704 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2706 case SnapToBeatDiv64:
2707 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2709 case SnapToBeatDiv32:
2710 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2712 case SnapToBeatDiv28:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2715 case SnapToBeatDiv24:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2718 case SnapToBeatDiv20:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2721 case SnapToBeatDiv16:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2724 case SnapToBeatDiv14:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2727 case SnapToBeatDiv12:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2730 case SnapToBeatDiv10:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2733 case SnapToBeatDiv8:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2736 case SnapToBeatDiv7:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2739 case SnapToBeatDiv6:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2742 case SnapToBeatDiv5:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2745 case SnapToBeatDiv4:
2746 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2748 case SnapToBeatDiv3:
2749 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2751 case SnapToBeatDiv2:
2752 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2760 _session->locations()->marks_either_side (start, before, after);
2762 if (before == max_framepos && after == max_framepos) {
2763 /* No marks to snap to, so just don't snap */
2765 } else if (before == max_framepos) {
2767 } else if (after == max_framepos) {
2769 } else if (before != max_framepos && after != max_framepos) {
2770 /* have before and after */
2771 if ((start - before) < (after - start)) {
2780 case SnapToRegionStart:
2781 case SnapToRegionEnd:
2782 case SnapToRegionSync:
2783 case SnapToRegionBoundary:
2784 if (!region_boundary_cache.empty()) {
2786 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2787 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2789 if (direction > 0) {
2790 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2792 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2795 if (next != region_boundary_cache.begin ()) {
2800 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2801 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2803 if (start > (p + n) / 2) {
2812 switch (_snap_mode) {
2818 if (presnap > start) {
2819 if (presnap > (start + unit_to_frame(snap_threshold))) {
2823 } else if (presnap < start) {
2824 if (presnap < (start - unit_to_frame(snap_threshold))) {
2830 /* handled at entry */
2838 Editor::setup_toolbar ()
2840 HBox* mode_box = manage(new HBox);
2841 mode_box->set_border_width (2);
2842 mode_box->set_spacing(4);
2844 HBox* mouse_mode_box = manage (new HBox);
2845 HBox* mouse_mode_hbox = manage (new HBox);
2846 VBox* mouse_mode_vbox = manage (new VBox);
2847 Alignment* mouse_mode_align = manage (new Alignment);
2849 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2850 // mouse_mode_size_group->add_widget (smart_mode_button);
2851 mouse_mode_size_group->add_widget (mouse_move_button);
2852 mouse_mode_size_group->add_widget (mouse_select_button);
2853 mouse_mode_size_group->add_widget (mouse_zoom_button);
2854 mouse_mode_size_group->add_widget (mouse_gain_button);
2855 mouse_mode_size_group->add_widget (mouse_timefx_button);
2856 mouse_mode_size_group->add_widget (mouse_audition_button);
2857 mouse_mode_size_group->add_widget (mouse_draw_button);
2858 mouse_mode_size_group->add_widget (internal_edit_button);
2860 /* make them just a bit bigger */
2861 mouse_move_button.set_size_request (-1, 30);
2863 mouse_mode_hbox->set_spacing (2);
2865 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2866 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2867 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2868 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2872 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2873 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2875 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2877 mouse_mode_align->add (*mouse_mode_vbox);
2878 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2880 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2882 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2883 if (!Profile->get_sae()) {
2884 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2886 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2888 edit_mode_selector.set_name ("EditModeSelector");
2889 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2890 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2892 mode_box->pack_start (edit_mode_selector, false, false);
2893 mode_box->pack_start (*mouse_mode_box, false, false);
2895 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2896 _mouse_mode_tearoff->set_name ("MouseModeBase");
2897 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2899 if (Profile->get_sae()) {
2900 _mouse_mode_tearoff->set_can_be_torn_off (false);
2903 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2904 &_mouse_mode_tearoff->tearoff_window()));
2905 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2906 &_mouse_mode_tearoff->tearoff_window(), 1));
2907 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2908 &_mouse_mode_tearoff->tearoff_window()));
2909 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2910 &_mouse_mode_tearoff->tearoff_window(), 1));
2914 _zoom_box.set_spacing (2);
2915 _zoom_box.set_border_width (2);
2919 zoom_in_button.set_name ("zoom button");
2920 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2921 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2922 zoom_in_button.set_image(::get_icon ("zoom_in"));
2923 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2924 zoom_in_button.set_related_action (act);
2926 zoom_out_button.set_name ("zoom button");
2927 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2928 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2929 zoom_out_button.set_image(::get_icon ("zoom_out"));
2930 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2931 zoom_out_button.set_related_action (act);
2933 zoom_out_full_button.set_name ("zoom button");
2934 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2935 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2936 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2937 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2938 zoom_out_full_button.set_related_action (act);
2940 zoom_focus_selector.set_name ("ZoomFocusSelector");
2941 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2942 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2944 _zoom_box.pack_start (zoom_out_button, false, false);
2945 _zoom_box.pack_start (zoom_in_button, false, false);
2946 _zoom_box.pack_start (zoom_out_full_button, false, false);
2948 _zoom_box.pack_start (zoom_focus_selector, false, false);
2950 /* Track zoom buttons */
2951 tav_expand_button.set_name ("zoom button");
2952 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2953 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2954 tav_expand_button.set_size_request (-1, 20);
2955 tav_expand_button.set_image(::get_icon ("tav_exp"));
2956 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2957 tav_expand_button.set_related_action (act);
2959 tav_shrink_button.set_name ("zoom button");
2960 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2961 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2962 tav_shrink_button.set_size_request (-1, 20);
2963 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2964 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2965 tav_shrink_button.set_related_action (act);
2967 _zoom_box.pack_start (tav_shrink_button);
2968 _zoom_box.pack_start (tav_expand_button);
2970 _zoom_tearoff = manage (new TearOff (_zoom_box));
2972 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2973 &_zoom_tearoff->tearoff_window()));
2974 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2975 &_zoom_tearoff->tearoff_window(), 0));
2976 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2977 &_zoom_tearoff->tearoff_window()));
2978 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2979 &_zoom_tearoff->tearoff_window(), 0));
2981 snap_box.set_spacing (2);
2982 snap_box.set_border_width (2);
2984 snap_type_selector.set_name ("SnapTypeSelector");
2985 set_popdown_strings (snap_type_selector, snap_type_strings);
2986 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2988 snap_mode_selector.set_name ("SnapModeSelector");
2989 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2990 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2992 edit_point_selector.set_name ("EditPointSelector");
2993 set_popdown_strings (edit_point_selector, edit_point_strings);
2994 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2996 snap_box.pack_start (snap_mode_selector, false, false);
2997 snap_box.pack_start (snap_type_selector, false, false);
2998 snap_box.pack_start (edit_point_selector, false, false);
3002 HBox *nudge_box = manage (new HBox);
3003 nudge_box->set_spacing (2);
3004 nudge_box->set_border_width (2);
3006 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3007 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3009 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3010 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3012 nudge_box->pack_start (nudge_backward_button, false, false);
3013 nudge_box->pack_start (nudge_forward_button, false, false);
3014 nudge_box->pack_start (*nudge_clock, false, false);
3017 /* Pack everything in... */
3019 HBox* hbox = manage (new HBox);
3020 hbox->set_spacing(10);
3022 _tools_tearoff = manage (new TearOff (*hbox));
3023 _tools_tearoff->set_name ("MouseModeBase");
3024 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3026 if (Profile->get_sae()) {
3027 _tools_tearoff->set_can_be_torn_off (false);
3030 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3031 &_tools_tearoff->tearoff_window()));
3032 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3033 &_tools_tearoff->tearoff_window(), 0));
3034 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3035 &_tools_tearoff->tearoff_window()));
3036 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3037 &_tools_tearoff->tearoff_window(), 0));
3039 toolbar_hbox.set_spacing (10);
3040 toolbar_hbox.set_border_width (1);
3042 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3043 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3044 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3046 hbox->pack_start (snap_box, false, false);
3047 if (!Profile->get_small_screen()) {
3048 hbox->pack_start (*nudge_box, false, false);
3050 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3052 hbox->pack_start (panic_box, false, false);
3056 toolbar_base.set_name ("ToolBarBase");
3057 toolbar_base.add (toolbar_hbox);
3059 _toolbar_viewport.add (toolbar_base);
3060 /* stick to the required height but allow width to vary if there's not enough room */
3061 _toolbar_viewport.set_size_request (1, -1);
3063 toolbar_frame.set_shadow_type (SHADOW_OUT);
3064 toolbar_frame.set_name ("BaseFrame");
3065 toolbar_frame.add (_toolbar_viewport);
3069 Editor::setup_tooltips ()
3071 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3072 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3073 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3074 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3075 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3076 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3077 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3078 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3079 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3080 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3081 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3082 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3083 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3084 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3085 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3086 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3087 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3088 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3089 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3090 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3091 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3092 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3093 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3097 Editor::convert_drop_to_paths (
3098 vector<string>& paths,
3099 const RefPtr<Gdk::DragContext>& /*context*/,
3102 const SelectionData& data,
3106 if (_session == 0) {
3110 vector<string> uris = data.get_uris();
3114 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3115 are actually URI lists. So do it by hand.
3118 if (data.get_target() != "text/plain") {
3122 /* Parse the "uri-list" format that Nautilus provides,
3123 where each pathname is delimited by \r\n.
3125 THERE MAY BE NO NULL TERMINATING CHAR!!!
3128 string txt = data.get_text();
3132 p = (char *) malloc (txt.length() + 1);
3133 txt.copy (p, txt.length(), 0);
3134 p[txt.length()] = '\0';
3140 while (g_ascii_isspace (*p))
3144 while (*q && (*q != '\n') && (*q != '\r')) {
3151 while (q > p && g_ascii_isspace (*q))
3156 uris.push_back (string (p, q - p + 1));
3160 p = strchr (p, '\n');
3172 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3174 if ((*i).substr (0,7) == "file://") {
3176 string const p = PBD::url_decode (*i);
3178 // scan forward past three slashes
3180 string::size_type slashcnt = 0;
3181 string::size_type n = 0;
3182 string::const_iterator x = p.begin();
3184 while (slashcnt < 3 && x != p.end()) {
3187 } else if (slashcnt == 3) {
3194 if (slashcnt != 3 || x == p.end()) {
3195 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3199 paths.push_back (p.substr (n - 1));
3207 Editor::new_tempo_section ()
3213 Editor::map_transport_state ()
3215 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3217 if (_session && _session->transport_stopped()) {
3218 have_pending_keyboard_selection = false;
3221 update_loop_range_view (true);
3227 Editor::begin_reversible_command (string name)
3230 _session->begin_reversible_command (name);
3235 Editor::begin_reversible_command (GQuark q)
3238 _session->begin_reversible_command (q);
3243 Editor::commit_reversible_command ()
3246 _session->commit_reversible_command ();
3251 Editor::history_changed ()
3255 if (undo_action && _session) {
3256 if (_session->undo_depth() == 0) {
3257 label = S_("Command|Undo");
3259 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3261 undo_action->property_label() = label;
3264 if (redo_action && _session) {
3265 if (_session->redo_depth() == 0) {
3268 label = string_compose(_("Redo (%1)"), _session->next_redo());
3270 redo_action->property_label() = label;
3275 Editor::duplicate_range (bool with_dialog)
3279 RegionSelection rs = get_regions_from_selection_and_entered ();
3281 if ( selection->time.length() == 0 && rs.empty()) {
3287 ArdourDialog win (_("Duplicate"));
3288 Label label (_("Number of duplications:"));
3289 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3290 SpinButton spinner (adjustment, 0.0, 1);
3293 win.get_vbox()->set_spacing (12);
3294 win.get_vbox()->pack_start (hbox);
3295 hbox.set_border_width (6);
3296 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3298 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3299 place, visually. so do this by hand.
3302 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3303 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3304 spinner.grab_focus();
3310 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3311 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3312 win.set_default_response (RESPONSE_ACCEPT);
3314 spinner.grab_focus ();
3316 switch (win.run ()) {
3317 case RESPONSE_ACCEPT:
3323 times = adjustment.get_value();
3326 if ((current_mouse_mode() == Editing::MouseRange)) {
3327 if (selection->time.length()) {
3328 duplicate_selection (times);
3330 } else if (get_smart_mode()) {
3331 if (selection->time.length()) {
3332 duplicate_selection (times);
3334 duplicate_some_regions (rs, times);
3336 duplicate_some_regions (rs, times);
3341 Editor::set_edit_mode (EditMode m)
3343 Config->set_edit_mode (m);
3347 Editor::cycle_edit_mode ()
3349 switch (Config->get_edit_mode()) {
3351 if (Profile->get_sae()) {
3352 Config->set_edit_mode (Lock);
3354 Config->set_edit_mode (Splice);
3358 Config->set_edit_mode (Lock);
3361 Config->set_edit_mode (Slide);
3367 Editor::edit_mode_selection_done ()
3369 string s = edit_mode_selector.get_active_text ();
3372 Config->set_edit_mode (string_to_edit_mode (s));
3377 Editor::snap_type_selection_done ()
3379 string choice = snap_type_selector.get_active_text();
3380 SnapType snaptype = SnapToBeat;
3382 if (choice == _("Beats/2")) {
3383 snaptype = SnapToBeatDiv2;
3384 } else if (choice == _("Beats/3")) {
3385 snaptype = SnapToBeatDiv3;
3386 } else if (choice == _("Beats/4")) {
3387 snaptype = SnapToBeatDiv4;
3388 } else if (choice == _("Beats/5")) {
3389 snaptype = SnapToBeatDiv5;
3390 } else if (choice == _("Beats/6")) {
3391 snaptype = SnapToBeatDiv6;
3392 } else if (choice == _("Beats/7")) {
3393 snaptype = SnapToBeatDiv7;
3394 } else if (choice == _("Beats/8")) {
3395 snaptype = SnapToBeatDiv8;
3396 } else if (choice == _("Beats/10")) {
3397 snaptype = SnapToBeatDiv10;
3398 } else if (choice == _("Beats/12")) {
3399 snaptype = SnapToBeatDiv12;
3400 } else if (choice == _("Beats/14")) {
3401 snaptype = SnapToBeatDiv14;
3402 } else if (choice == _("Beats/16")) {
3403 snaptype = SnapToBeatDiv16;
3404 } else if (choice == _("Beats/20")) {
3405 snaptype = SnapToBeatDiv20;
3406 } else if (choice == _("Beats/24")) {
3407 snaptype = SnapToBeatDiv24;
3408 } else if (choice == _("Beats/28")) {
3409 snaptype = SnapToBeatDiv28;
3410 } else if (choice == _("Beats/32")) {
3411 snaptype = SnapToBeatDiv32;
3412 } else if (choice == _("Beats/64")) {
3413 snaptype = SnapToBeatDiv64;
3414 } else if (choice == _("Beats/128")) {
3415 snaptype = SnapToBeatDiv128;
3416 } else if (choice == _("Beats")) {
3417 snaptype = SnapToBeat;
3418 } else if (choice == _("Bars")) {
3419 snaptype = SnapToBar;
3420 } else if (choice == _("Marks")) {
3421 snaptype = SnapToMark;
3422 } else if (choice == _("Region starts")) {
3423 snaptype = SnapToRegionStart;
3424 } else if (choice == _("Region ends")) {
3425 snaptype = SnapToRegionEnd;
3426 } else if (choice == _("Region bounds")) {
3427 snaptype = SnapToRegionBoundary;
3428 } else if (choice == _("Region syncs")) {
3429 snaptype = SnapToRegionSync;
3430 } else if (choice == _("CD Frames")) {
3431 snaptype = SnapToCDFrame;
3432 } else if (choice == _("Timecode Frames")) {
3433 snaptype = SnapToTimecodeFrame;
3434 } else if (choice == _("Timecode Seconds")) {
3435 snaptype = SnapToTimecodeSeconds;
3436 } else if (choice == _("Timecode Minutes")) {
3437 snaptype = SnapToTimecodeMinutes;
3438 } else if (choice == _("Seconds")) {
3439 snaptype = SnapToSeconds;
3440 } else if (choice == _("Minutes")) {
3441 snaptype = SnapToMinutes;
3444 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3446 ract->set_active ();
3451 Editor::snap_mode_selection_done ()
3453 string choice = snap_mode_selector.get_active_text();
3454 SnapMode mode = SnapNormal;
3456 if (choice == _("No Grid")) {
3458 } else if (choice == _("Grid")) {
3460 } else if (choice == _("Magnetic")) {
3461 mode = SnapMagnetic;
3464 RefPtr<RadioAction> ract = snap_mode_action (mode);
3467 ract->set_active (true);
3472 Editor::cycle_edit_point (bool with_marker)
3474 switch (_edit_point) {
3476 set_edit_point_preference (EditAtPlayhead);
3478 case EditAtPlayhead:
3480 set_edit_point_preference (EditAtSelectedMarker);
3482 set_edit_point_preference (EditAtMouse);
3485 case EditAtSelectedMarker:
3486 set_edit_point_preference (EditAtMouse);
3492 Editor::edit_point_selection_done ()
3494 string choice = edit_point_selector.get_active_text();
3495 EditPoint ep = EditAtSelectedMarker;
3497 if (choice == _("Marker")) {
3498 set_edit_point_preference (EditAtSelectedMarker);
3499 } else if (choice == _("Playhead")) {
3500 set_edit_point_preference (EditAtPlayhead);
3502 set_edit_point_preference (EditAtMouse);
3505 RefPtr<RadioAction> ract = edit_point_action (ep);
3508 ract->set_active (true);
3513 Editor::zoom_focus_selection_done ()
3515 string choice = zoom_focus_selector.get_active_text();
3516 ZoomFocus focus_type = ZoomFocusLeft;
3518 if (choice == _("Left")) {
3519 focus_type = ZoomFocusLeft;
3520 } else if (choice == _("Right")) {
3521 focus_type = ZoomFocusRight;
3522 } else if (choice == _("Center")) {
3523 focus_type = ZoomFocusCenter;
3524 } else if (choice == _("Playhead")) {
3525 focus_type = ZoomFocusPlayhead;
3526 } else if (choice == _("Mouse")) {
3527 focus_type = ZoomFocusMouse;
3528 } else if (choice == _("Edit point")) {
3529 focus_type = ZoomFocusEdit;
3532 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3535 ract->set_active ();
3540 Editor::edit_controls_button_release (GdkEventButton* ev)
3542 if (Keyboard::is_context_menu_event (ev)) {
3543 ARDOUR_UI::instance()->add_route (this);
3544 } else if (ev->button == 1) {
3545 selection->clear_tracks ();
3552 Editor::mouse_select_button_release (GdkEventButton* ev)
3554 /* this handles just right-clicks */
3556 if (ev->button != 3) {
3564 Editor::set_zoom_focus (ZoomFocus f)
3566 string str = zoom_focus_strings[(int)f];
3568 if (str != zoom_focus_selector.get_active_text()) {
3569 zoom_focus_selector.set_active_text (str);
3572 if (zoom_focus != f) {
3579 Editor::cycle_zoom_focus ()
3581 switch (zoom_focus) {
3583 set_zoom_focus (ZoomFocusRight);
3585 case ZoomFocusRight:
3586 set_zoom_focus (ZoomFocusCenter);
3588 case ZoomFocusCenter:
3589 set_zoom_focus (ZoomFocusPlayhead);
3591 case ZoomFocusPlayhead:
3592 set_zoom_focus (ZoomFocusMouse);
3594 case ZoomFocusMouse:
3595 set_zoom_focus (ZoomFocusEdit);
3598 set_zoom_focus (ZoomFocusLeft);
3604 Editor::ensure_float (Window& win)
3606 win.set_transient_for (*this);
3610 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3612 /* recover or initialize pane positions. do this here rather than earlier because
3613 we don't want the positions to change the child allocations, which they seem to do.
3619 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3628 XMLNode* geometry = find_named_node (*node, "geometry");
3630 if (which == static_cast<Paned*> (&edit_pane)) {
3632 if (done & Horizontal) {
3636 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3637 _notebook_shrunk = string_is_affirmative (prop->value ());
3640 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3641 /* initial allocation is 90% to canvas, 10% to notebook */
3642 pos = (int) floor (alloc.get_width() * 0.90f);
3643 snprintf (buf, sizeof(buf), "%d", pos);
3645 pos = atoi (prop->value());
3648 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3649 edit_pane.set_position (pos);
3652 done = (Pane) (done | Horizontal);
3654 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3656 if (done & Vertical) {
3660 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3661 /* initial allocation is 90% to canvas, 10% to summary */
3662 pos = (int) floor (alloc.get_height() * 0.90f);
3663 snprintf (buf, sizeof(buf), "%d", pos);
3666 pos = atoi (prop->value());
3669 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3670 editor_summary_pane.set_position (pos);
3673 done = (Pane) (done | Vertical);
3678 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3680 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3681 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3682 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3683 top_hbox.remove (toolbar_frame);
3688 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3690 if (toolbar_frame.get_parent() == 0) {
3691 top_hbox.pack_end (toolbar_frame);
3696 Editor::set_show_measures (bool yn)
3698 if (_show_measures != yn) {
3701 if ((_show_measures = yn) == true) {
3703 tempo_lines->show();
3705 (void) redraw_measures ();
3712 Editor::toggle_follow_playhead ()
3714 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3716 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3717 set_follow_playhead (tact->get_active());
3721 /** @param yn true to follow playhead, otherwise false.
3722 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3725 Editor::set_follow_playhead (bool yn, bool catch_up)
3727 if (_follow_playhead != yn) {
3728 if ((_follow_playhead = yn) == true && catch_up) {
3730 reset_x_origin_to_follow_playhead ();
3737 Editor::toggle_stationary_playhead ()
3739 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3741 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3742 set_stationary_playhead (tact->get_active());
3747 Editor::set_stationary_playhead (bool yn)
3749 if (_stationary_playhead != yn) {
3750 if ((_stationary_playhead = yn) == true) {
3752 // FIXME need a 3.0 equivalent of this 2.X call
3753 // update_current_screen ();
3760 Editor::playlist_selector () const
3762 return *_playlist_selector;
3766 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3770 switch (_snap_type) {
3775 case SnapToBeatDiv128:
3778 case SnapToBeatDiv64:
3781 case SnapToBeatDiv32:
3784 case SnapToBeatDiv28:
3787 case SnapToBeatDiv24:
3790 case SnapToBeatDiv20:
3793 case SnapToBeatDiv16:
3796 case SnapToBeatDiv14:
3799 case SnapToBeatDiv12:
3802 case SnapToBeatDiv10:
3805 case SnapToBeatDiv8:
3808 case SnapToBeatDiv7:
3811 case SnapToBeatDiv6:
3814 case SnapToBeatDiv5:
3817 case SnapToBeatDiv4:
3820 case SnapToBeatDiv3:
3823 case SnapToBeatDiv2:
3829 return _session->tempo_map().meter_at (position).divisions_per_bar();
3834 case SnapToTimecodeFrame:
3835 case SnapToTimecodeSeconds:
3836 case SnapToTimecodeMinutes:
3839 case SnapToRegionStart:
3840 case SnapToRegionEnd:
3841 case SnapToRegionSync:
3842 case SnapToRegionBoundary:
3852 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3856 ret = nudge_clock->current_duration (pos);
3857 next = ret + 1; /* XXXX fix me */
3863 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3865 ArdourDialog dialog (_("Playlist Deletion"));
3866 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3867 "If it is kept, its audio files will not be cleaned.\n"
3868 "If it is deleted, audio files used by it alone will be cleaned."),
3871 dialog.set_position (WIN_POS_CENTER);
3872 dialog.get_vbox()->pack_start (label);
3876 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3877 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3878 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3880 switch (dialog.run ()) {
3881 case RESPONSE_ACCEPT:
3882 /* delete the playlist */
3886 case RESPONSE_REJECT:
3887 /* keep the playlist */
3899 Editor::audio_region_selection_covers (framepos_t where)
3901 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3902 if ((*a)->region()->covers (where)) {
3911 Editor::prepare_for_cleanup ()
3913 cut_buffer->clear_regions ();
3914 cut_buffer->clear_playlists ();
3916 selection->clear_regions ();
3917 selection->clear_playlists ();
3919 _regions->suspend_redisplay ();
3923 Editor::finish_cleanup ()
3925 _regions->resume_redisplay ();
3929 Editor::transport_loop_location()
3932 return _session->locations()->auto_loop_location();
3939 Editor::transport_punch_location()
3942 return _session->locations()->auto_punch_location();
3949 Editor::control_layout_scroll (GdkEventScroll* ev)
3951 if (Keyboard::some_magic_widget_has_focus()) {
3955 switch (ev->direction) {
3957 scroll_tracks_up_line ();
3961 case GDK_SCROLL_DOWN:
3962 scroll_tracks_down_line ();
3966 /* no left/right handling yet */
3974 Editor::session_state_saved (string)
3977 _snapshots->redisplay ();
3981 Editor::update_tearoff_visibility()
3983 bool visible = Config->get_keep_tearoffs();
3984 _mouse_mode_tearoff->set_visible (visible);
3985 _tools_tearoff->set_visible (visible);
3986 _zoom_tearoff->set_visible (visible);
3990 Editor::maximise_editing_space ()
4002 Editor::restore_editing_space ()
4014 * Make new playlists for a given track and also any others that belong
4015 * to the same active route group with the `select' property.
4020 Editor::new_playlists (TimeAxisView* v)
4022 begin_reversible_command (_("new playlists"));
4023 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4024 _session->playlists->get (playlists);
4025 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4026 commit_reversible_command ();
4030 * Use a copy of the current playlist for a given track and also any others that belong
4031 * to the same active route group with the `select' property.
4036 Editor::copy_playlists (TimeAxisView* v)
4038 begin_reversible_command (_("copy playlists"));
4039 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4040 _session->playlists->get (playlists);
4041 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4042 commit_reversible_command ();
4045 /** Clear the current playlist for a given track and also any others that belong
4046 * to the same active route group with the `select' property.
4051 Editor::clear_playlists (TimeAxisView* v)
4053 begin_reversible_command (_("clear playlists"));
4054 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4055 _session->playlists->get (playlists);
4056 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4057 commit_reversible_command ();
4061 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4063 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4067 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4069 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4073 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4075 atv.clear_playlist ();
4079 Editor::on_key_press_event (GdkEventKey* ev)
4081 return key_press_focus_accelerator_handler (*this, ev);
4085 Editor::on_key_release_event (GdkEventKey* ev)
4087 return Gtk::Window::on_key_release_event (ev);
4088 // return key_press_focus_accelerator_handler (*this, ev);
4091 /** Queue up a change to the viewport x origin.
4092 * @param frame New x origin.
4095 Editor::reset_x_origin (framepos_t frame)
4097 pending_visual_change.add (VisualChange::TimeOrigin);
4098 pending_visual_change.time_origin = frame;
4099 ensure_visual_change_idle_handler ();
4103 Editor::reset_y_origin (double y)
4105 pending_visual_change.add (VisualChange::YOrigin);
4106 pending_visual_change.y_origin = y;
4107 ensure_visual_change_idle_handler ();
4111 Editor::reset_zoom (double fpu)
4113 clamp_frames_per_unit (fpu);
4115 if (fpu == frames_per_unit) {
4119 pending_visual_change.add (VisualChange::ZoomLevel);
4120 pending_visual_change.frames_per_unit = fpu;
4121 ensure_visual_change_idle_handler ();
4125 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4127 reset_x_origin (frame);
4130 if (!no_save_visual) {
4131 undo_visual_stack.push_back (current_visual_state(false));
4135 Editor::VisualState::VisualState (bool with_tracks)
4136 : gui_state (with_tracks ? new GUIObjectState : 0)
4140 Editor::VisualState::~VisualState ()
4145 Editor::VisualState*
4146 Editor::current_visual_state (bool with_tracks)
4148 VisualState* vs = new VisualState (with_tracks);
4149 vs->y_position = vertical_adjustment.get_value();
4150 vs->frames_per_unit = frames_per_unit;
4151 vs->leftmost_frame = leftmost_frame;
4152 vs->zoom_focus = zoom_focus;
4155 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4162 Editor::undo_visual_state ()
4164 if (undo_visual_stack.empty()) {
4168 VisualState* vs = undo_visual_stack.back();
4169 undo_visual_stack.pop_back();
4172 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4174 use_visual_state (*vs);
4178 Editor::redo_visual_state ()
4180 if (redo_visual_stack.empty()) {
4184 VisualState* vs = redo_visual_stack.back();
4185 redo_visual_stack.pop_back();
4187 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4189 use_visual_state (*vs);
4193 Editor::swap_visual_state ()
4195 if (undo_visual_stack.empty()) {
4196 redo_visual_state ();
4198 undo_visual_state ();
4203 Editor::use_visual_state (VisualState& vs)
4205 PBD::Unwinder<bool> nsv (no_save_visual, true);
4207 _routes->suspend_redisplay ();
4209 vertical_adjustment.set_value (vs.y_position);
4211 set_zoom_focus (vs.zoom_focus);
4212 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4215 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4217 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4218 (*i)->reset_visual_state ();
4222 _routes->update_visibility ();
4223 _routes->resume_redisplay ();
4226 /** This is the core function that controls the zoom level of the canvas. It is called
4227 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4228 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4231 Editor::set_frames_per_unit (double fpu)
4234 tempo_lines->tempo_map_changed();
4237 frames_per_unit = fpu;
4239 /* convert fpu to frame count */
4241 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4243 if (frames_per_unit != zoom_range_clock->current_duration()) {
4244 zoom_range_clock->set (frames);
4247 bool const showing_time_selection = selection->time.length() > 0;
4249 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4250 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4251 (*i)->reshow_selection (selection->time);
4255 ZoomChanged (); /* EMIT_SIGNAL */
4257 //reset_scrolling_region ();
4259 if (playhead_cursor) {
4260 playhead_cursor->set_position (playhead_cursor->current_frame);
4263 refresh_location_display();
4264 _summary->set_overlays_dirty ();
4266 update_marker_labels ();
4272 Editor::queue_visual_videotimeline_update ()
4275 * pending_visual_change.add (VisualChange::VideoTimeline);
4276 * or maybe even more specific: which videotimeline-image
4277 * currently it calls update_video_timeline() to update
4278 * _all outdated_ images on the video-timeline.
4279 * see 'exposeimg()' in video_image_frame.cc
4281 ensure_visual_change_idle_handler ();
4285 Editor::ensure_visual_change_idle_handler ()
4287 if (pending_visual_change.idle_handler_id < 0) {
4288 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4293 Editor::_idle_visual_changer (void* arg)
4295 return static_cast<Editor*>(arg)->idle_visual_changer ();
4299 Editor::idle_visual_changer ()
4301 /* set_horizontal_position() below (and maybe other calls) call
4302 gtk_main_iteration(), so it's possible that a signal will be handled
4303 half-way through this method. If this signal wants an
4304 idle_visual_changer we must schedule another one after this one, so
4305 mark the idle_handler_id as -1 here to allow that. Also make a note
4306 that we are doing the visual change, so that changes in response to
4307 super-rapid-screen-update can be dropped if we are still processing
4311 pending_visual_change.idle_handler_id = -1;
4312 pending_visual_change.being_handled = true;
4314 VisualChange::Type p = pending_visual_change.pending;
4315 pending_visual_change.pending = (VisualChange::Type) 0;
4317 double const last_time_origin = horizontal_position ();
4319 if (p & VisualChange::ZoomLevel) {
4320 set_frames_per_unit (pending_visual_change.frames_per_unit);
4322 compute_fixed_ruler_scale ();
4324 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4325 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4327 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4328 current_bbt_points_begin, current_bbt_points_end);
4329 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4330 current_bbt_points_begin, current_bbt_points_end);
4331 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4334 if (p & VisualChange::ZoomLevel) {
4335 update_video_timeline();
4338 if (p & VisualChange::TimeOrigin) {
4339 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4342 if (p & VisualChange::YOrigin) {
4343 vertical_adjustment.set_value (pending_visual_change.y_origin);
4346 if (last_time_origin == horizontal_position ()) {
4347 /* changed signal not emitted */
4348 update_fixed_rulers ();
4349 redisplay_tempo (true);
4352 if (!(p & VisualChange::ZoomLevel)) {
4353 update_video_timeline();
4356 _summary->set_overlays_dirty ();
4358 pending_visual_change.being_handled = false;
4359 return 0; /* this is always a one-shot call */
4362 struct EditorOrderTimeAxisSorter {
4363 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4364 return a->order () < b->order ();
4369 Editor::sort_track_selection (TrackViewList& sel)
4371 EditorOrderTimeAxisSorter cmp;
4376 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4379 framepos_t where = 0;
4380 EditPoint ep = _edit_point;
4382 if (from_context_menu && (ep == EditAtMouse)) {
4383 return event_frame (&context_click_event, 0, 0);
4386 if (entered_marker) {
4387 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4388 return entered_marker->position();
4391 if (ignore_playhead && ep == EditAtPlayhead) {
4392 ep = EditAtSelectedMarker;
4396 case EditAtPlayhead:
4397 where = _session->audible_frame();
4398 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4401 case EditAtSelectedMarker:
4402 if (!selection->markers.empty()) {
4404 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4407 where = loc->start();
4411 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4419 if (!mouse_frame (where, ignored)) {
4420 /* XXX not right but what can we do ? */
4424 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4432 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4434 if (!_session) return;
4436 begin_reversible_command (cmd);
4440 if ((tll = transport_loop_location()) == 0) {
4441 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4442 XMLNode &before = _session->locations()->get_state();
4443 _session->locations()->add (loc, true);
4444 _session->set_auto_loop_location (loc);
4445 XMLNode &after = _session->locations()->get_state();
4446 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4448 XMLNode &before = tll->get_state();
4449 tll->set_hidden (false, this);
4450 tll->set (start, end);
4451 XMLNode &after = tll->get_state();
4452 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4455 commit_reversible_command ();
4459 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4461 if (!_session) return;
4463 begin_reversible_command (cmd);
4467 if ((tpl = transport_punch_location()) == 0) {
4468 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4469 XMLNode &before = _session->locations()->get_state();
4470 _session->locations()->add (loc, true);
4471 _session->set_auto_loop_location (loc);
4472 XMLNode &after = _session->locations()->get_state();
4473 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4476 XMLNode &before = tpl->get_state();
4477 tpl->set_hidden (false, this);
4478 tpl->set (start, end);
4479 XMLNode &after = tpl->get_state();
4480 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4483 commit_reversible_command ();
4486 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4487 * @param rs List to which found regions are added.
4488 * @param where Time to look at.
4489 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4492 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4494 const TrackViewList* tracks;
4497 tracks = &track_views;
4502 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4504 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4507 boost::shared_ptr<Track> tr;
4508 boost::shared_ptr<Playlist> pl;
4510 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4512 boost::shared_ptr<RegionList> regions = pl->regions_at (
4513 (framepos_t) floor ( (double) where * tr->speed()));
4515 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4516 RegionView* rv = rtv->view()->find_view (*i);
4527 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4529 const TrackViewList* tracks;
4532 tracks = &track_views;
4537 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4538 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4540 boost::shared_ptr<Track> tr;
4541 boost::shared_ptr<Playlist> pl;
4543 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4545 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4546 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4548 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4550 RegionView* rv = rtv->view()->find_view (*i);
4561 /** Get regions using the following method:
4563 * Make a region list using the selected regions, unless
4564 * the edit point is `mouse' and the mouse is over an unselected
4565 * region. In this case, use just that region.
4567 * If the edit point is not 'mouse', and there are no regions selected,
4568 * search the list of selected tracks and return regions that are under
4569 * the edit point on these tracks. If there are no selected tracks and
4570 * 'No Selection = All Tracks' is active, search all tracks,
4572 * The rationale here is that the mouse edit point is special in that
4573 * its position describes both a time and a track; the other edit
4574 * modes only describe a time. Hence if the edit point is `mouse' we
4575 * ignore selected tracks, as we assume the user means something by
4576 * pointing at a particular track. Also in this case we take note of
4577 * the region directly under the edit point, as there is always just one
4578 * (rather than possibly several with non-mouse edit points).
4582 Editor::get_regions_from_selection_and_edit_point ()
4584 RegionSelection regions;
4586 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4587 regions.add (entered_regionview);
4589 regions = selection->regions;
4593 if (regions.empty() && _edit_point != EditAtMouse) {
4594 TrackViewList tracks = selection->tracks;
4596 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4597 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4598 * is enabled, so consider all tracks
4600 tracks = track_views;
4603 if (!tracks.empty()) {
4604 /* no region selected or entered, but some selected tracks:
4605 * act on all regions on the selected tracks at the edit point
4607 framepos_t const where = get_preferred_edit_position ();
4608 get_regions_at(regions, where, tracks);
4614 /** Start with regions that are selected, or the entered regionview if none are selected.
4615 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4616 * of the regions that we started with.
4620 Editor::get_regions_from_selection_and_entered ()
4622 RegionSelection regions = selection->regions;
4624 if (regions.empty() && entered_regionview) {
4625 regions.add (entered_regionview);
4632 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4634 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4636 RouteTimeAxisView* tatv;
4638 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4640 boost::shared_ptr<Playlist> pl;
4641 vector<boost::shared_ptr<Region> > results;
4643 boost::shared_ptr<Track> tr;
4645 if ((tr = tatv->track()) == 0) {
4650 if ((pl = (tr->playlist())) != 0) {
4651 if (src_comparison) {
4652 pl->get_source_equivalent_regions (region, results);
4654 pl->get_region_list_equivalent_regions (region, results);
4658 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4659 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4660 regions.push_back (marv);
4669 Editor::show_rhythm_ferret ()
4671 if (rhythm_ferret == 0) {
4672 rhythm_ferret = new RhythmFerret(*this);
4675 rhythm_ferret->set_session (_session);
4676 rhythm_ferret->show ();
4677 rhythm_ferret->present ();
4681 Editor::first_idle ()
4683 MessageDialog* dialog = 0;
4685 if (track_views.size() > 1) {
4686 dialog = new MessageDialog (
4688 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4692 ARDOUR_UI::instance()->flush_pending ();
4695 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4699 // first idle adds route children (automation tracks), so we need to redisplay here
4700 _routes->redisplay ();
4707 Editor::_idle_resize (gpointer arg)
4709 return ((Editor*)arg)->idle_resize ();
4713 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4715 if (resize_idle_id < 0) {
4716 resize_idle_id = g_idle_add (_idle_resize, this);
4717 _pending_resize_amount = 0;
4720 /* make a note of the smallest resulting height, so that we can clamp the
4721 lower limit at TimeAxisView::hSmall */
4723 int32_t min_resulting = INT32_MAX;
4725 _pending_resize_amount += h;
4726 _pending_resize_view = view;
4728 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4730 if (selection->tracks.contains (_pending_resize_view)) {
4731 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4732 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4736 if (min_resulting < 0) {
4741 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4742 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4746 /** Handle pending resizing of tracks */
4748 Editor::idle_resize ()
4750 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4752 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4753 selection->tracks.contains (_pending_resize_view)) {
4755 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4756 if (*i != _pending_resize_view) {
4757 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4762 _pending_resize_amount = 0;
4764 _group_tabs->set_dirty ();
4765 resize_idle_id = -1;
4773 ENSURE_GUI_THREAD (*this, &Editor::located);
4776 playhead_cursor->set_position (_session->audible_frame ());
4777 if (_follow_playhead && !_pending_initial_locate) {
4778 reset_x_origin_to_follow_playhead ();
4782 _pending_locate_request = false;
4783 _pending_initial_locate = false;
4787 Editor::region_view_added (RegionView *)
4789 _summary->set_dirty ();
4793 Editor::region_view_removed ()
4795 _summary->set_dirty ();
4799 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4801 TrackViewList::const_iterator j = track_views.begin ();
4802 while (j != track_views.end()) {
4803 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4804 if (rtv && rtv->route() == r) {
4815 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4819 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4820 TimeAxisView* tv = axis_view_from_route (*i);
4830 Editor::add_routes (RouteList& routes)
4832 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4834 RouteTimeAxisView *rtv;
4835 list<RouteTimeAxisView*> new_views;
4837 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4838 boost::shared_ptr<Route> route = (*x);
4840 if (route->is_auditioner() || route->is_monitor()) {
4844 DataType dt = route->input()->default_type();
4846 if (dt == ARDOUR::DataType::AUDIO) {
4847 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4848 rtv->set_route (route);
4849 } else if (dt == ARDOUR::DataType::MIDI) {
4850 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4851 rtv->set_route (route);
4853 throw unknown_type();
4856 new_views.push_back (rtv);
4857 track_views.push_back (rtv);
4859 rtv->effective_gain_display ();
4861 if (internal_editing()) {
4862 rtv->enter_internal_edit_mode ();
4864 rtv->leave_internal_edit_mode ();
4867 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4868 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4871 _routes->routes_added (new_views);
4872 _summary->routes_added (new_views);
4874 if (show_editor_mixer_when_tracks_arrive) {
4875 show_editor_mixer (true);
4878 editor_list_button.set_sensitive (true);
4882 Editor::timeaxisview_deleted (TimeAxisView *tv)
4884 if (_session && _session->deletion_in_progress()) {
4885 /* the situation is under control */
4889 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4891 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4893 _routes->route_removed (tv);
4895 if (tv == entered_track) {
4899 TimeAxisView::Children c = tv->get_child_list ();
4900 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4901 if (entered_track == i->get()) {
4906 /* remove it from the list of track views */
4908 TrackViewList::iterator i;
4910 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4911 i = track_views.erase (i);
4914 /* update whatever the current mixer strip is displaying, if revelant */
4916 boost::shared_ptr<Route> route;
4919 route = rtav->route ();
4922 if (current_mixer_strip && current_mixer_strip->route() == route) {
4924 TimeAxisView* next_tv;
4926 if (track_views.empty()) {
4928 } else if (i == track_views.end()) {
4929 next_tv = track_views.front();
4936 set_selected_mixer_strip (*next_tv);
4938 /* make the editor mixer strip go away setting the
4939 * button to inactive (which also unticks the menu option)
4942 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4948 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4950 if (apply_to_selection) {
4951 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4953 TrackSelection::iterator j = i;
4956 hide_track_in_display (*i, false);
4961 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4963 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4964 // this will hide the mixer strip
4965 set_selected_mixer_strip (*tv);
4968 _routes->hide_track_in_display (*tv);
4973 Editor::sync_track_view_list_and_routes ()
4975 track_views = TrackViewList (_routes->views ());
4977 _summary->set_dirty ();
4978 _group_tabs->set_dirty ();
4980 return false; // do not call again (until needed)
4984 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4986 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4991 /** Find a RouteTimeAxisView by the ID of its route */
4993 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4995 RouteTimeAxisView* v;
4997 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4998 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4999 if(v->route()->id() == id) {
5009 Editor::fit_route_group (RouteGroup *g)
5011 TrackViewList ts = axis_views_from_routes (g->route_list ());
5016 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5018 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5021 _session->cancel_audition ();
5025 if (_session->is_auditioning()) {
5026 _session->cancel_audition ();
5027 if (r == last_audition_region) {
5032 _session->audition_region (r);
5033 last_audition_region = r;
5038 Editor::hide_a_region (boost::shared_ptr<Region> r)
5040 r->set_hidden (true);
5044 Editor::show_a_region (boost::shared_ptr<Region> r)
5046 r->set_hidden (false);
5050 Editor::audition_region_from_region_list ()
5052 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5056 Editor::hide_region_from_region_list ()
5058 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5062 Editor::show_region_in_region_list ()
5064 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5068 Editor::step_edit_status_change (bool yn)
5071 start_step_editing ();
5073 stop_step_editing ();
5078 Editor::start_step_editing ()
5080 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5084 Editor::stop_step_editing ()
5086 step_edit_connection.disconnect ();
5090 Editor::check_step_edit ()
5092 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5093 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5095 mtv->check_step_edit ();
5099 return true; // do it again, till we stop
5103 Editor::scroll_press (Direction dir)
5105 ++_scroll_callbacks;
5107 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5108 /* delay the first auto-repeat */
5114 scroll_backward (1);
5122 scroll_tracks_up_line ();
5126 scroll_tracks_down_line ();
5130 /* do hacky auto-repeat */
5131 if (!_scroll_connection.connected ()) {
5133 _scroll_connection = Glib::signal_timeout().connect (
5134 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5137 _scroll_callbacks = 0;
5144 Editor::scroll_release ()
5146 _scroll_connection.disconnect ();
5149 /** Queue a change for the Editor viewport x origin to follow the playhead */
5151 Editor::reset_x_origin_to_follow_playhead ()
5153 framepos_t const frame = playhead_cursor->current_frame;
5155 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5157 if (_session->transport_speed() < 0) {
5159 if (frame > (current_page_frames() / 2)) {
5160 center_screen (frame-(current_page_frames()/2));
5162 center_screen (current_page_frames()/2);
5169 if (frame < leftmost_frame) {
5171 if (_session->transport_rolling()) {
5172 /* rolling; end up with the playhead at the right of the page */
5173 l = frame - current_page_frames ();
5175 /* not rolling: end up with the playhead 1/4 of the way along the page */
5176 l = frame - current_page_frames() / 4;
5180 if (_session->transport_rolling()) {
5181 /* rolling: end up with the playhead on the left of the page */
5184 /* not rolling: end up with the playhead 3/4 of the way along the page */
5185 l = frame - 3 * current_page_frames() / 4;
5193 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5199 Editor::super_rapid_screen_update ()
5201 if (!_session || !_session->engine().running()) {
5205 /* METERING / MIXER STRIPS */
5207 /* update track meters, if required */
5208 if (is_mapped() && meters_running) {
5209 RouteTimeAxisView* rtv;
5210 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5211 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5212 rtv->fast_update ();
5217 /* and any current mixer strip */
5218 if (current_mixer_strip) {
5219 current_mixer_strip->fast_update ();
5222 /* PLAYHEAD AND VIEWPORT */
5224 framepos_t const frame = _session->audible_frame();
5226 /* There are a few reasons why we might not update the playhead / viewport stuff:
5228 * 1. we don't update things when there's a pending locate request, otherwise
5229 * when the editor requests a locate there is a chance that this method
5230 * will move the playhead before the locate request is processed, causing
5232 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5233 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5236 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5238 last_update_frame = frame;
5240 if (!_dragging_playhead) {
5241 playhead_cursor->set_position (frame);
5244 if (!_stationary_playhead) {
5246 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5247 /* We only do this if we aren't already
5248 handling a visual change (ie if
5249 pending_visual_change.being_handled is
5250 false) so that these requests don't stack
5251 up there are too many of them to handle in
5254 reset_x_origin_to_follow_playhead ();
5259 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5263 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5264 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5265 if (target <= 0.0) {
5268 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5269 target = (target * 0.15) + (current * 0.85);
5275 set_horizontal_position (current);
5284 Editor::session_going_away ()
5286 _have_idled = false;
5288 _session_connections.drop_connections ();
5290 super_rapid_screen_update_connection.disconnect ();
5292 selection->clear ();
5293 cut_buffer->clear ();
5295 clicked_regionview = 0;
5296 clicked_axisview = 0;
5297 clicked_routeview = 0;
5298 entered_regionview = 0;
5300 last_update_frame = 0;
5303 playhead_cursor->canvas_item.hide ();
5305 /* rip everything out of the list displays */
5309 _route_groups->clear ();
5311 /* do this first so that deleting a track doesn't reset cms to null
5312 and thus cause a leak.
5315 if (current_mixer_strip) {
5316 if (current_mixer_strip->get_parent() != 0) {
5317 global_hpacker.remove (*current_mixer_strip);
5319 delete current_mixer_strip;
5320 current_mixer_strip = 0;
5323 /* delete all trackviews */
5325 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5328 track_views.clear ();
5330 zoom_range_clock->set_session (0);
5331 nudge_clock->set_session (0);
5333 editor_list_button.set_active(false);
5334 editor_list_button.set_sensitive(false);
5336 /* clear tempo/meter rulers */
5337 remove_metric_marks ();
5339 clear_marker_display ();
5341 stop_step_editing ();
5343 /* get rid of any existing editor mixer strip */
5345 WindowTitle title(Glib::get_application_name());
5346 title += _("Editor");
5348 set_title (title.get_string());
5350 SessionHandlePtr::session_going_away ();
5355 Editor::show_editor_list (bool yn)
5358 _the_notebook.show ();
5360 _the_notebook.hide ();
5365 Editor::change_region_layering_order (bool from_context_menu)
5367 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5369 if (!clicked_routeview) {
5370 if (layering_order_editor) {
5371 layering_order_editor->hide ();
5376 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5382 boost::shared_ptr<Playlist> pl = track->playlist();
5388 if (layering_order_editor == 0) {
5389 layering_order_editor = new RegionLayeringOrderEditor (*this);
5392 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5393 layering_order_editor->maybe_present ();
5397 Editor::update_region_layering_order_editor ()
5399 if (layering_order_editor && layering_order_editor->is_visible ()) {
5400 change_region_layering_order (true);
5405 Editor::setup_fade_images ()
5407 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5408 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5409 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5410 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5411 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5413 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5414 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5415 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5416 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5417 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5419 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5420 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5421 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5422 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5423 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5425 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5426 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5427 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5428 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5429 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5433 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5435 Editor::action_menu_item (std::string const & name)
5437 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5440 return *manage (a->create_menu_item ());
5444 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5446 EventBox* b = manage (new EventBox);
5447 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5448 Label* l = manage (new Label (name));
5452 _the_notebook.append_page (widget, *b);
5456 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5458 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5459 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5462 if (ev->type == GDK_2BUTTON_PRESS) {
5464 /* double-click on a notebook tab shrinks or expands the notebook */
5466 if (_notebook_shrunk) {
5467 if (pre_notebook_shrink_pane_width) {
5468 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5470 _notebook_shrunk = false;
5472 pre_notebook_shrink_pane_width = edit_pane.get_position();
5474 /* this expands the LHS of the edit pane to cover the notebook
5475 PAGE but leaves the tabs visible.
5477 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5478 _notebook_shrunk = true;
5486 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5488 using namespace Menu_Helpers;
5490 MenuList& items = _control_point_context_menu.items ();
5493 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5494 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5495 if (!can_remove_control_point (item)) {
5496 items.back().set_sensitive (false);
5499 _control_point_context_menu.popup (event->button.button, event->button.time);
5503 Editor::zoom_vertical_modifier_released()
5505 _stepping_axis_view = 0;