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 _edit_point = EditAtMouse;
369 _internal_editing = false;
370 current_canvas_cursor = 0;
372 frames_per_unit = 2048; /* too early to use reset_zoom () */
374 _scroll_callbacks = 0;
376 zoom_focus = ZoomFocusLeft;
377 set_zoom_focus (ZoomFocusLeft);
378 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
380 bbt_label.set_name ("EditorRulerLabel");
381 bbt_label.set_size_request (-1, (int)timebar_height);
382 bbt_label.set_alignment (1.0, 0.5);
383 bbt_label.set_padding (5,0);
385 bbt_label.set_no_show_all();
386 minsec_label.set_name ("EditorRulerLabel");
387 minsec_label.set_size_request (-1, (int)timebar_height);
388 minsec_label.set_alignment (1.0, 0.5);
389 minsec_label.set_padding (5,0);
390 minsec_label.hide ();
391 minsec_label.set_no_show_all();
392 timecode_label.set_name ("EditorRulerLabel");
393 timecode_label.set_size_request (-1, (int)timebar_height);
394 timecode_label.set_alignment (1.0, 0.5);
395 timecode_label.set_padding (5,0);
396 timecode_label.hide ();
397 timecode_label.set_no_show_all();
398 samples_label.set_name ("EditorRulerLabel");
399 samples_label.set_size_request (-1, (int)timebar_height);
400 samples_label.set_alignment (1.0, 0.5);
401 samples_label.set_padding (5,0);
402 samples_label.hide ();
403 samples_label.set_no_show_all();
405 tempo_label.set_name ("EditorRulerLabel");
406 tempo_label.set_size_request (-1, (int)timebar_height);
407 tempo_label.set_alignment (1.0, 0.5);
408 tempo_label.set_padding (5,0);
410 tempo_label.set_no_show_all();
412 meter_label.set_name ("EditorRulerLabel");
413 meter_label.set_size_request (-1, (int)timebar_height);
414 meter_label.set_alignment (1.0, 0.5);
415 meter_label.set_padding (5,0);
417 meter_label.set_no_show_all();
419 mark_label.set_name ("EditorRulerLabel");
420 mark_label.set_size_request (-1, (int)timebar_height);
421 mark_label.set_alignment (1.0, 0.5);
422 mark_label.set_padding (5,0);
424 mark_label.set_no_show_all();
426 cd_mark_label.set_name ("EditorRulerLabel");
427 cd_mark_label.set_size_request (-1, (int)timebar_height);
428 cd_mark_label.set_alignment (1.0, 0.5);
429 cd_mark_label.set_padding (5,0);
430 cd_mark_label.hide();
431 cd_mark_label.set_no_show_all();
433 videotl_bar_height = 4;
434 videotl_label.set_name ("EditorRulerLabel");
435 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
436 videotl_label.set_alignment (1.0, 0.5);
437 videotl_label.set_padding (5,0);
438 videotl_label.hide();
439 videotl_label.set_no_show_all();
441 range_mark_label.set_name ("EditorRulerLabel");
442 range_mark_label.set_size_request (-1, (int)timebar_height);
443 range_mark_label.set_alignment (1.0, 0.5);
444 range_mark_label.set_padding (5,0);
445 range_mark_label.hide();
446 range_mark_label.set_no_show_all();
448 transport_mark_label.set_name ("EditorRulerLabel");
449 transport_mark_label.set_size_request (-1, (int)timebar_height);
450 transport_mark_label.set_alignment (1.0, 0.5);
451 transport_mark_label.set_padding (5,0);
452 transport_mark_label.hide();
453 transport_mark_label.set_no_show_all();
455 initialize_rulers ();
456 initialize_canvas ();
458 _summary = new EditorSummary (this);
460 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
461 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
463 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
465 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
466 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
468 edit_controls_vbox.set_spacing (0);
469 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
470 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
472 HBox* h = manage (new HBox);
473 _group_tabs = new EditorGroupTabs (this);
474 h->pack_start (*_group_tabs, PACK_SHRINK);
475 h->pack_start (edit_controls_vbox);
476 controls_layout.add (*h);
478 controls_layout.set_name ("EditControlsBase");
479 controls_layout.add_events (Gdk::SCROLL_MASK);
480 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
482 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
483 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
485 _cursors = new MouseCursors;
487 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
488 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
489 0.0, 1.0, 100.0, 1.0));
491 pad_line_1->property_color_rgba() = 0xFF0000FF;
496 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
497 time_canvas_vbox.set_size_request (-1, -1);
499 ruler_label_event_box.add (ruler_label_vbox);
500 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
501 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
503 time_button_event_box.add (time_button_vbox);
504 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
505 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
507 /* these enable us to have a dedicated window (for cursor setting, etc.)
508 for the canvas areas.
511 track_canvas_event_box.add (*track_canvas);
513 time_canvas_event_box.add (time_canvas_vbox);
514 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
516 edit_packer.set_col_spacings (0);
517 edit_packer.set_row_spacings (0);
518 edit_packer.set_homogeneous (false);
519 edit_packer.set_border_width (0);
520 edit_packer.set_name ("EditorWindow");
522 /* labels for the rulers */
523 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
524 /* labels for the marker "tracks" */
525 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
527 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
529 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
531 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
533 bottom_hbox.set_border_width (2);
534 bottom_hbox.set_spacing (3);
536 _route_groups = new EditorRouteGroups (this);
537 _routes = new EditorRoutes (this);
538 _regions = new EditorRegions (this);
539 _snapshots = new EditorSnapshots (this);
540 _locations = new EditorLocations (this);
542 add_notebook_page (_("Regions"), _regions->widget ());
543 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
544 add_notebook_page (_("Snapshots"), _snapshots->widget ());
545 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
546 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
548 _the_notebook.set_show_tabs (true);
549 _the_notebook.set_scrollable (true);
550 _the_notebook.popup_disable ();
551 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
552 _the_notebook.show_all ();
554 _notebook_shrunk = false;
556 editor_summary_pane.pack1(edit_packer);
558 Button* summary_arrows_left_left = manage (new Button);
559 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
560 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
561 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
563 Button* summary_arrows_left_right = manage (new Button);
564 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
565 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
566 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
568 VBox* summary_arrows_left = manage (new VBox);
569 summary_arrows_left->pack_start (*summary_arrows_left_left);
570 summary_arrows_left->pack_start (*summary_arrows_left_right);
572 Button* summary_arrows_right_up = manage (new Button);
573 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
574 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
575 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 Button* summary_arrows_right_down = manage (new Button);
578 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
579 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
580 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 VBox* summary_arrows_right = manage (new VBox);
583 summary_arrows_right->pack_start (*summary_arrows_right_up);
584 summary_arrows_right->pack_start (*summary_arrows_right_down);
586 Frame* summary_frame = manage (new Frame);
587 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
589 summary_frame->add (*_summary);
590 summary_frame->show ();
592 _summary_hbox.pack_start (*summary_arrows_left, false, false);
593 _summary_hbox.pack_start (*summary_frame, true, true);
594 _summary_hbox.pack_start (*summary_arrows_right, false, false);
596 editor_summary_pane.pack2 (_summary_hbox);
598 edit_pane.pack1 (editor_summary_pane, true, true);
599 edit_pane.pack2 (_the_notebook, false, true);
601 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
603 /* XXX: editor_summary_pane might need similar to the edit_pane */
605 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
607 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
608 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
610 top_hbox.pack_start (toolbar_frame);
612 HBox *hbox = manage (new HBox);
613 hbox->pack_start (edit_pane, true, true);
615 global_vpacker.pack_start (top_hbox, false, false);
616 global_vpacker.pack_start (*hbox, true, true);
618 global_hpacker.pack_start (global_vpacker, true, true);
620 set_name ("EditorWindow");
621 add_accel_group (ActionManager::ui_manager->get_accel_group());
623 status_bar_hpacker.show ();
625 vpacker.pack_end (status_bar_hpacker, false, false);
626 vpacker.pack_end (global_hpacker, true, true);
628 /* register actions now so that set_state() can find them and set toggles/checks etc */
631 /* when we start using our own keybinding system for the editor, this
632 * will be uncommented
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().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_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 Gtkmm2ext::UI::instance()->call_slot();
1264 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1265 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1266 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1267 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1268 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1269 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1270 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1271 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1272 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1273 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1274 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1275 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1276 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1277 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1279 playhead_cursor->canvas_item.show ();
1281 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1282 Config->map_parameters (pc);
1283 _session->config.map_parameters (pc);
1285 restore_ruler_visibility ();
1286 //tempo_map_changed (PropertyChange (0));
1287 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1289 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1290 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1293 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1294 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1297 switch (_snap_type) {
1298 case SnapToRegionStart:
1299 case SnapToRegionEnd:
1300 case SnapToRegionSync:
1301 case SnapToRegionBoundary:
1302 build_region_boundary_cache ();
1309 /* register for undo history */
1310 _session->register_with_memento_command_factory(id(), this);
1312 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1314 start_updating_meters ();
1318 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1320 if (a->get_name() == "RegionMenu") {
1321 /* When the main menu's region menu is opened, we setup the actions so that they look right
1322 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1323 so we resensitize all region actions when the entered regionview or the region selection
1324 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1325 happens after the region context menu is opened. So we set a flag here, too.
1329 sensitize_the_right_region_actions ();
1330 _last_region_menu_was_main = true;
1335 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1337 using namespace Menu_Helpers;
1339 void (Editor::*emf)(FadeShape);
1340 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1343 images = &_xfade_in_images;
1344 emf = &Editor::set_fade_in_shape;
1346 images = &_xfade_out_images;
1347 emf = &Editor::set_fade_out_shape;
1352 _("Linear (for highly correlated material)"),
1353 *(*images)[FadeLinear],
1354 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1358 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1362 _("Constant power"),
1363 *(*images)[FadeConstantPower],
1364 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1367 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1372 *(*images)[FadeSymmetric],
1373 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1377 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1382 *(*images)[FadeSlow],
1383 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1386 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1391 *(*images)[FadeFast],
1392 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1395 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1398 /** Pop up a context menu for when the user clicks on a start crossfade */
1400 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1402 using namespace Menu_Helpers;
1404 MenuList& items (xfade_in_context_menu.items());
1406 if (items.empty()) {
1407 fill_xfade_menu (items, true);
1410 xfade_in_context_menu.popup (button, time);
1413 /** Pop up a context menu for when the user clicks on an end crossfade */
1415 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1417 using namespace Menu_Helpers;
1419 MenuList& items (xfade_out_context_menu.items());
1421 if (items.empty()) {
1422 fill_xfade_menu (items, false);
1425 xfade_out_context_menu.popup (button, time);
1429 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1431 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1433 using namespace Menu_Helpers;
1434 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1437 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1441 MenuList& items (fade_context_menu.items());
1444 switch (item_type) {
1446 case FadeInHandleItem:
1447 if (arv->audio_region()->fade_in_active()) {
1448 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1450 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1453 items.push_back (SeparatorElem());
1455 if (Profile->get_sae()) {
1457 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1458 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1465 *_fade_in_images[FadeLinear],
1466 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1470 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1475 *_fade_in_images[FadeSlow],
1476 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1479 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1484 *_fade_in_images[FadeFast],
1485 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1493 *_fade_in_images[FadeSymmetric],
1494 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1499 _("Constant power"),
1500 *_fade_in_images[FadeConstantPower],
1501 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1504 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1510 case FadeOutHandleItem:
1511 if (arv->audio_region()->fade_out_active()) {
1512 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1514 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1517 items.push_back (SeparatorElem());
1519 if (Profile->get_sae()) {
1520 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1521 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1527 *_fade_out_images[FadeLinear],
1528 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1532 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1537 *_fade_out_images[FadeSlow],
1538 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1541 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1546 *_fade_out_images[FadeFast],
1547 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1550 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1555 *_fade_out_images[FadeSymmetric],
1556 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1561 _("Constant power"),
1562 *_fade_out_images[FadeConstantPower],
1563 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1566 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1572 fatal << _("programming error: ")
1573 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1578 fade_context_menu.popup (button, time);
1582 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1584 using namespace Menu_Helpers;
1585 Menu* (Editor::*build_menu_function)();
1588 switch (item_type) {
1590 case RegionViewName:
1591 case RegionViewNameHighlight:
1592 case LeftFrameHandle:
1593 case RightFrameHandle:
1594 if (with_selection) {
1595 build_menu_function = &Editor::build_track_selection_context_menu;
1597 build_menu_function = &Editor::build_track_region_context_menu;
1602 if (with_selection) {
1603 build_menu_function = &Editor::build_track_selection_context_menu;
1605 build_menu_function = &Editor::build_track_context_menu;
1610 if (clicked_routeview->track()) {
1611 build_menu_function = &Editor::build_track_context_menu;
1613 build_menu_function = &Editor::build_track_bus_context_menu;
1618 /* probably shouldn't happen but if it does, we don't care */
1622 menu = (this->*build_menu_function)();
1623 menu->set_name ("ArdourContextMenu");
1625 /* now handle specific situations */
1627 switch (item_type) {
1629 case RegionViewName:
1630 case RegionViewNameHighlight:
1631 case LeftFrameHandle:
1632 case RightFrameHandle:
1633 if (!with_selection) {
1634 if (region_edit_menu_split_item) {
1635 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1636 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1638 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1641 if (region_edit_menu_split_multichannel_item) {
1642 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1643 region_edit_menu_split_multichannel_item->set_sensitive (true);
1645 region_edit_menu_split_multichannel_item->set_sensitive (false);
1658 /* probably shouldn't happen but if it does, we don't care */
1662 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1664 /* Bounce to disk */
1666 using namespace Menu_Helpers;
1667 MenuList& edit_items = menu->items();
1669 edit_items.push_back (SeparatorElem());
1671 switch (clicked_routeview->audio_track()->freeze_state()) {
1672 case AudioTrack::NoFreeze:
1673 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1676 case AudioTrack::Frozen:
1677 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1680 case AudioTrack::UnFrozen:
1681 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1687 if (item_type == StreamItem && clicked_routeview) {
1688 clicked_routeview->build_underlay_menu(menu);
1691 /* When the region menu is opened, we setup the actions so that they look right
1694 sensitize_the_right_region_actions ();
1695 _last_region_menu_was_main = false;
1697 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1698 menu->popup (button, time);
1702 Editor::build_track_context_menu ()
1704 using namespace Menu_Helpers;
1706 MenuList& edit_items = track_context_menu.items();
1709 add_dstream_context_items (edit_items);
1710 return &track_context_menu;
1714 Editor::build_track_bus_context_menu ()
1716 using namespace Menu_Helpers;
1718 MenuList& edit_items = track_context_menu.items();
1721 add_bus_context_items (edit_items);
1722 return &track_context_menu;
1726 Editor::build_track_region_context_menu ()
1728 using namespace Menu_Helpers;
1729 MenuList& edit_items = track_region_context_menu.items();
1732 /* we've just cleared the track region context menu, so the menu that these
1733 two items were on will have disappeared; stop them dangling.
1735 region_edit_menu_split_item = 0;
1736 region_edit_menu_split_multichannel_item = 0;
1738 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1741 boost::shared_ptr<Track> tr;
1742 boost::shared_ptr<Playlist> pl;
1744 if ((tr = rtv->track())) {
1745 add_region_context_items (edit_items, tr);
1749 add_dstream_context_items (edit_items);
1751 return &track_region_context_menu;
1755 Editor::analyze_region_selection ()
1757 if (analysis_window == 0) {
1758 analysis_window = new AnalysisWindow();
1761 analysis_window->set_session(_session);
1763 analysis_window->show_all();
1766 analysis_window->set_regionmode();
1767 analysis_window->analyze();
1769 analysis_window->present();
1773 Editor::analyze_range_selection()
1775 if (analysis_window == 0) {
1776 analysis_window = new AnalysisWindow();
1779 analysis_window->set_session(_session);
1781 analysis_window->show_all();
1784 analysis_window->set_rangemode();
1785 analysis_window->analyze();
1787 analysis_window->present();
1791 Editor::build_track_selection_context_menu ()
1793 using namespace Menu_Helpers;
1794 MenuList& edit_items = track_selection_context_menu.items();
1795 edit_items.clear ();
1797 add_selection_context_items (edit_items);
1798 // edit_items.push_back (SeparatorElem());
1799 // add_dstream_context_items (edit_items);
1801 return &track_selection_context_menu;
1805 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1807 using namespace Menu_Helpers;
1809 /* OK, stick the region submenu at the top of the list, and then add
1813 RegionSelection rs = get_regions_from_selection_and_entered ();
1815 string::size_type pos = 0;
1816 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1818 /* we have to hack up the region name because "_" has a special
1819 meaning for menu titles.
1822 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1823 menu_item_name.replace (pos, 1, "__");
1827 if (_popup_region_menu_item == 0) {
1828 _popup_region_menu_item = new MenuItem (menu_item_name);
1829 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1830 _popup_region_menu_item->show ();
1832 _popup_region_menu_item->set_label (menu_item_name);
1835 const framepos_t position = get_preferred_edit_position (false, true);
1837 edit_items.push_back (*_popup_region_menu_item);
1838 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1839 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1841 edit_items.push_back (SeparatorElem());
1844 /** Add context menu items relevant to selection ranges.
1845 * @param edit_items List to add the items to.
1848 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1850 using namespace Menu_Helpers;
1852 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1853 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1855 edit_items.push_back (SeparatorElem());
1856 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1858 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (
1862 _("Move Range Start to Previous Region Boundary"),
1863 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1867 edit_items.push_back (
1869 _("Move Range Start to Next Region Boundary"),
1870 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1874 edit_items.push_back (
1876 _("Move Range End to Previous Region Boundary"),
1877 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1881 edit_items.push_back (
1883 _("Move Range End to Next Region Boundary"),
1884 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1888 edit_items.push_back (SeparatorElem());
1889 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1890 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1892 edit_items.push_back (SeparatorElem());
1893 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1895 edit_items.push_back (SeparatorElem());
1896 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1897 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1899 edit_items.push_back (SeparatorElem());
1900 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1904 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1905 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1907 edit_items.push_back (SeparatorElem());
1908 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1909 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1910 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1911 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1912 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1917 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1919 using namespace Menu_Helpers;
1923 Menu *play_menu = manage (new Menu);
1924 MenuList& play_items = play_menu->items();
1925 play_menu->set_name ("ArdourContextMenu");
1927 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1928 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1929 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1930 play_items.push_back (SeparatorElem());
1931 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1933 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1937 Menu *select_menu = manage (new Menu);
1938 MenuList& select_items = select_menu->items();
1939 select_menu->set_name ("ArdourContextMenu");
1941 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1942 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1943 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1944 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1945 select_items.push_back (SeparatorElem());
1946 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1947 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1948 select_items.push_back (SeparatorElem());
1949 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1950 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1951 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1952 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1953 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1954 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1955 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1957 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1961 Menu *cutnpaste_menu = manage (new Menu);
1962 MenuList& cutnpaste_items = cutnpaste_menu->items();
1963 cutnpaste_menu->set_name ("ArdourContextMenu");
1965 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1966 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1967 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1969 cutnpaste_items.push_back (SeparatorElem());
1971 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1972 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1974 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1976 /* Adding new material */
1978 edit_items.push_back (SeparatorElem());
1979 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1980 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1984 Menu *nudge_menu = manage (new Menu());
1985 MenuList& nudge_items = nudge_menu->items();
1986 nudge_menu->set_name ("ArdourContextMenu");
1988 edit_items.push_back (SeparatorElem());
1989 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1990 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1991 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1992 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1994 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1998 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2000 using namespace Menu_Helpers;
2004 Menu *play_menu = manage (new Menu);
2005 MenuList& play_items = play_menu->items();
2006 play_menu->set_name ("ArdourContextMenu");
2008 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2009 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2010 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2014 Menu *select_menu = manage (new Menu);
2015 MenuList& select_items = select_menu->items();
2016 select_menu->set_name ("ArdourContextMenu");
2018 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2019 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2020 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2021 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2022 select_items.push_back (SeparatorElem());
2023 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2024 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2025 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2026 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2028 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2032 Menu *cutnpaste_menu = manage (new Menu);
2033 MenuList& cutnpaste_items = cutnpaste_menu->items();
2034 cutnpaste_menu->set_name ("ArdourContextMenu");
2036 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2037 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2038 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2040 Menu *nudge_menu = manage (new Menu());
2041 MenuList& nudge_items = nudge_menu->items();
2042 nudge_menu->set_name ("ArdourContextMenu");
2044 edit_items.push_back (SeparatorElem());
2045 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2046 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2047 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2048 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2050 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2054 Editor::snap_type() const
2060 Editor::snap_mode() const
2066 Editor::set_snap_to (SnapType st)
2068 unsigned int snap_ind = (unsigned int)st;
2072 if (snap_ind > snap_type_strings.size() - 1) {
2074 _snap_type = (SnapType)snap_ind;
2077 string str = snap_type_strings[snap_ind];
2079 if (str != snap_type_selector.get_active_text()) {
2080 snap_type_selector.set_active_text (str);
2085 switch (_snap_type) {
2086 case SnapToBeatDiv128:
2087 case SnapToBeatDiv64:
2088 case SnapToBeatDiv32:
2089 case SnapToBeatDiv28:
2090 case SnapToBeatDiv24:
2091 case SnapToBeatDiv20:
2092 case SnapToBeatDiv16:
2093 case SnapToBeatDiv14:
2094 case SnapToBeatDiv12:
2095 case SnapToBeatDiv10:
2096 case SnapToBeatDiv8:
2097 case SnapToBeatDiv7:
2098 case SnapToBeatDiv6:
2099 case SnapToBeatDiv5:
2100 case SnapToBeatDiv4:
2101 case SnapToBeatDiv3:
2102 case SnapToBeatDiv2: {
2103 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2104 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2106 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2107 current_bbt_points_begin, current_bbt_points_end);
2108 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2109 current_bbt_points_begin, current_bbt_points_end);
2110 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2114 case SnapToRegionStart:
2115 case SnapToRegionEnd:
2116 case SnapToRegionSync:
2117 case SnapToRegionBoundary:
2118 build_region_boundary_cache ();
2126 SnapChanged (); /* EMIT SIGNAL */
2130 Editor::set_snap_mode (SnapMode mode)
2132 string str = snap_mode_strings[(int)mode];
2134 if (_internal_editing) {
2135 internal_snap_mode = mode;
2137 pre_internal_snap_mode = mode;
2142 if (str != snap_mode_selector.get_active_text ()) {
2143 snap_mode_selector.set_active_text (str);
2149 Editor::set_edit_point_preference (EditPoint ep, bool force)
2151 bool changed = (_edit_point != ep);
2154 string str = edit_point_strings[(int)ep];
2156 if (str != edit_point_selector.get_active_text ()) {
2157 edit_point_selector.set_active_text (str);
2160 set_canvas_cursor ();
2162 if (!force && !changed) {
2166 const char* action=NULL;
2168 switch (_edit_point) {
2169 case EditAtPlayhead:
2170 action = "edit-at-playhead";
2172 case EditAtSelectedMarker:
2173 action = "edit-at-marker";
2176 action = "edit-at-mouse";
2180 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2182 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2186 bool in_track_canvas;
2188 if (!mouse_frame (foo, in_track_canvas)) {
2189 in_track_canvas = false;
2192 reset_canvas_action_sensitivity (in_track_canvas);
2198 Editor::set_state (const XMLNode& node, int /*version*/)
2200 const XMLProperty* prop;
2207 g.base_width = default_width;
2208 g.base_height = default_height;
2212 if ((geometry = find_named_node (node, "geometry")) != 0) {
2216 if ((prop = geometry->property("x_size")) == 0) {
2217 prop = geometry->property ("x-size");
2220 g.base_width = atoi(prop->value());
2222 if ((prop = geometry->property("y_size")) == 0) {
2223 prop = geometry->property ("y-size");
2226 g.base_height = atoi(prop->value());
2229 if ((prop = geometry->property ("x_pos")) == 0) {
2230 prop = geometry->property ("x-pos");
2233 x = atoi (prop->value());
2236 if ((prop = geometry->property ("y_pos")) == 0) {
2237 prop = geometry->property ("y-pos");
2240 y = atoi (prop->value());
2244 set_default_size (g.base_width, g.base_height);
2247 if (_session && (prop = node.property ("playhead"))) {
2249 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2250 playhead_cursor->set_position (pos);
2252 playhead_cursor->set_position (0);
2255 if ((prop = node.property ("mixer-width"))) {
2256 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2259 if ((prop = node.property ("zoom-focus"))) {
2260 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2263 if ((prop = node.property ("zoom"))) {
2264 reset_zoom (PBD::atof (prop->value()));
2266 reset_zoom (frames_per_unit);
2269 if ((prop = node.property ("snap-to"))) {
2270 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2273 if ((prop = node.property ("snap-mode"))) {
2274 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2277 if ((prop = node.property ("internal-snap-to"))) {
2278 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2281 if ((prop = node.property ("internal-snap-mode"))) {
2282 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2285 if ((prop = node.property ("pre-internal-snap-to"))) {
2286 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2290 if ((prop = node.property ("pre-internal-snap-mode"))) {
2291 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2294 if ((prop = node.property ("mouse-mode"))) {
2295 MouseMode m = str2mousemode(prop->value());
2296 set_mouse_mode (m, true);
2298 set_mouse_mode (MouseObject, true);
2301 if ((prop = node.property ("left-frame")) != 0) {
2303 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2307 reset_x_origin (pos);
2311 if ((prop = node.property ("y-origin")) != 0) {
2312 reset_y_origin (atof (prop->value ()));
2315 if ((prop = node.property ("internal-edit"))) {
2316 bool yn = string_is_affirmative (prop->value());
2317 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2319 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2320 tact->set_active (!yn);
2321 tact->set_active (yn);
2325 if ((prop = node.property ("join-object-range"))) {
2326 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2327 bool yn = string_is_affirmative (prop->value());
2329 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2330 tact->set_active (!yn);
2331 tact->set_active (yn);
2333 set_mouse_mode(mouse_mode, true);
2336 if ((prop = node.property ("edit-point"))) {
2337 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2340 if ((prop = node.property ("show-measures"))) {
2341 bool yn = string_is_affirmative (prop->value());
2342 _show_measures = yn;
2343 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2345 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2346 /* do it twice to force the change */
2347 tact->set_active (!yn);
2348 tact->set_active (yn);
2352 if ((prop = node.property ("follow-playhead"))) {
2353 bool yn = string_is_affirmative (prop->value());
2354 set_follow_playhead (yn);
2355 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2357 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2358 if (tact->get_active() != yn) {
2359 tact->set_active (yn);
2364 if ((prop = node.property ("stationary-playhead"))) {
2365 bool yn = string_is_affirmative (prop->value());
2366 set_stationary_playhead (yn);
2367 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2369 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2370 if (tact->get_active() != yn) {
2371 tact->set_active (yn);
2376 if ((prop = node.property ("region-list-sort-type"))) {
2377 RegionListSortType st;
2378 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2381 if ((prop = node.property ("show-editor-mixer"))) {
2383 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2386 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2387 bool yn = string_is_affirmative (prop->value());
2389 /* do it twice to force the change */
2391 tact->set_active (!yn);
2392 tact->set_active (yn);
2395 if ((prop = node.property ("show-editor-list"))) {
2397 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2400 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2401 bool yn = string_is_affirmative (prop->value());
2403 /* do it twice to force the change */
2405 tact->set_active (!yn);
2406 tact->set_active (yn);
2409 if ((prop = node.property (X_("editor-list-page")))) {
2410 _the_notebook.set_current_page (atoi (prop->value ()));
2413 if ((prop = node.property (X_("show-marker-lines")))) {
2414 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2416 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2417 bool yn = string_is_affirmative (prop->value ());
2419 tact->set_active (!yn);
2420 tact->set_active (yn);
2423 XMLNodeList children = node.children ();
2424 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2425 selection->set_state (**i, Stateful::current_state_version);
2426 _regions->set_state (**i);
2429 if ((prop = node.property ("maximised"))) {
2430 bool yn = string_is_affirmative (prop->value());
2432 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2436 if ((prop = node.property ("nudge-clock-value"))) {
2438 sscanf (prop->value().c_str(), "%" PRId64, &f);
2439 nudge_clock->set (f);
2441 nudge_clock->set_mode (AudioClock::Timecode);
2442 nudge_clock->set (_session->frame_rate() * 5, true);
2449 Editor::get_state ()
2451 XMLNode* node = new XMLNode ("Editor");
2454 id().print (buf, sizeof (buf));
2455 node->add_property ("id", buf);
2457 if (is_realized()) {
2458 Glib::RefPtr<Gdk::Window> win = get_window();
2460 int x, y, width, height;
2461 win->get_root_origin(x, y);
2462 win->get_size(width, height);
2464 XMLNode* geometry = new XMLNode ("geometry");
2466 snprintf(buf, sizeof(buf), "%d", width);
2467 geometry->add_property("x-size", string(buf));
2468 snprintf(buf, sizeof(buf), "%d", height);
2469 geometry->add_property("y-size", string(buf));
2470 snprintf(buf, sizeof(buf), "%d", x);
2471 geometry->add_property("x-pos", string(buf));
2472 snprintf(buf, sizeof(buf), "%d", y);
2473 geometry->add_property("y-pos", string(buf));
2474 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2475 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2476 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2477 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2478 geometry->add_property("edit-vertical-pane-pos", string(buf));
2480 node->add_child_nocopy (*geometry);
2483 maybe_add_mixer_strip_width (*node);
2485 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2486 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2487 node->add_property ("zoom", buf);
2488 node->add_property ("snap-to", enum_2_string (_snap_type));
2489 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2490 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2491 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2492 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2493 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2494 node->add_property ("edit-point", enum_2_string (_edit_point));
2496 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2497 node->add_property ("playhead", buf);
2498 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2499 node->add_property ("left-frame", buf);
2500 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2501 node->add_property ("y-origin", buf);
2503 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2504 node->add_property ("maximised", _maximised ? "yes" : "no");
2505 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2506 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2507 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2508 node->add_property ("mouse-mode", enum2str(mouse_mode));
2509 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2510 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2512 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2514 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2515 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2518 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2520 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2521 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2524 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2525 node->add_property (X_("editor-list-page"), buf);
2527 if (button_bindings) {
2528 XMLNode* bb = new XMLNode (X_("Buttons"));
2529 button_bindings->save (*bb);
2530 node->add_child_nocopy (*bb);
2533 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2535 node->add_child_nocopy (selection->get_state ());
2536 node->add_child_nocopy (_regions->get_state ());
2538 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2539 node->add_property ("nudge-clock-value", buf);
2546 /** @param y y offset from the top of all trackviews.
2547 * @return pair: TimeAxisView that y is over, layer index.
2548 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2549 * in stacked or expanded region display mode, otherwise 0.
2551 std::pair<TimeAxisView *, double>
2552 Editor::trackview_by_y_position (double y)
2554 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2556 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2562 return std::make_pair ( (TimeAxisView *) 0, 0);
2565 /** Snap a position to the grid, if appropriate, taking into account current
2566 * grid settings and also the state of any snap modifier keys that may be pressed.
2567 * @param start Position to snap.
2568 * @param event Event to get current key modifier information from, or 0.
2571 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2573 if (!_session || !event) {
2577 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2578 if (_snap_mode == SnapOff) {
2579 snap_to_internal (start, direction, for_mark);
2582 if (_snap_mode != SnapOff) {
2583 snap_to_internal (start, direction, for_mark);
2589 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2591 if (!_session || _snap_mode == SnapOff) {
2595 snap_to_internal (start, direction, for_mark);
2599 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2601 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2602 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2604 switch (_snap_type) {
2605 case SnapToTimecodeFrame:
2606 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2607 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2609 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2613 case SnapToTimecodeSeconds:
2614 if (_session->config.get_timecode_offset_negative()) {
2615 start += _session->config.get_timecode_offset ();
2617 start -= _session->config.get_timecode_offset ();
2619 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2620 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2622 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2625 if (_session->config.get_timecode_offset_negative()) {
2626 start -= _session->config.get_timecode_offset ();
2628 start += _session->config.get_timecode_offset ();
2632 case SnapToTimecodeMinutes:
2633 if (_session->config.get_timecode_offset_negative()) {
2634 start += _session->config.get_timecode_offset ();
2636 start -= _session->config.get_timecode_offset ();
2638 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2639 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2641 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2643 if (_session->config.get_timecode_offset_negative()) {
2644 start -= _session->config.get_timecode_offset ();
2646 start += _session->config.get_timecode_offset ();
2650 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2656 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2658 const framepos_t one_second = _session->frame_rate();
2659 const framepos_t one_minute = _session->frame_rate() * 60;
2660 framepos_t presnap = start;
2664 switch (_snap_type) {
2665 case SnapToTimecodeFrame:
2666 case SnapToTimecodeSeconds:
2667 case SnapToTimecodeMinutes:
2668 return timecode_snap_to_internal (start, direction, for_mark);
2671 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2672 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2674 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2679 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2680 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2682 start = (framepos_t) floor ((double) start / one_second) * one_second;
2687 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2688 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2690 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2695 start = _session->tempo_map().round_to_bar (start, direction);
2699 start = _session->tempo_map().round_to_beat (start, direction);
2702 case SnapToBeatDiv128:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2705 case SnapToBeatDiv64:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2708 case SnapToBeatDiv32:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2711 case SnapToBeatDiv28:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2714 case SnapToBeatDiv24:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2717 case SnapToBeatDiv20:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2720 case SnapToBeatDiv16:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2723 case SnapToBeatDiv14:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2726 case SnapToBeatDiv12:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2729 case SnapToBeatDiv10:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2732 case SnapToBeatDiv8:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2735 case SnapToBeatDiv7:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2738 case SnapToBeatDiv6:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2741 case SnapToBeatDiv5:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2744 case SnapToBeatDiv4:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2747 case SnapToBeatDiv3:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2750 case SnapToBeatDiv2:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2759 _session->locations()->marks_either_side (start, before, after);
2761 if (before == max_framepos && after == max_framepos) {
2762 /* No marks to snap to, so just don't snap */
2764 } else if (before == max_framepos) {
2766 } else if (after == max_framepos) {
2768 } else if (before != max_framepos && after != max_framepos) {
2769 /* have before and after */
2770 if ((start - before) < (after - start)) {
2779 case SnapToRegionStart:
2780 case SnapToRegionEnd:
2781 case SnapToRegionSync:
2782 case SnapToRegionBoundary:
2783 if (!region_boundary_cache.empty()) {
2785 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2786 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2788 if (direction > 0) {
2789 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2791 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2794 if (next != region_boundary_cache.begin ()) {
2799 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2800 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2802 if (start > (p + n) / 2) {
2811 switch (_snap_mode) {
2817 if (presnap > start) {
2818 if (presnap > (start + unit_to_frame(snap_threshold))) {
2822 } else if (presnap < start) {
2823 if (presnap < (start - unit_to_frame(snap_threshold))) {
2829 /* handled at entry */
2837 Editor::setup_toolbar ()
2839 HBox* mode_box = manage(new HBox);
2840 mode_box->set_border_width (2);
2841 mode_box->set_spacing(4);
2843 HBox* mouse_mode_box = manage (new HBox);
2844 HBox* mouse_mode_hbox = manage (new HBox);
2845 VBox* mouse_mode_vbox = manage (new VBox);
2846 Alignment* mouse_mode_align = manage (new Alignment);
2848 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2849 // mouse_mode_size_group->add_widget (smart_mode_button);
2850 mouse_mode_size_group->add_widget (mouse_move_button);
2851 mouse_mode_size_group->add_widget (mouse_select_button);
2852 mouse_mode_size_group->add_widget (mouse_zoom_button);
2853 mouse_mode_size_group->add_widget (mouse_gain_button);
2854 mouse_mode_size_group->add_widget (mouse_timefx_button);
2855 mouse_mode_size_group->add_widget (mouse_audition_button);
2856 mouse_mode_size_group->add_widget (mouse_draw_button);
2857 mouse_mode_size_group->add_widget (internal_edit_button);
2859 /* make them just a bit bigger */
2860 mouse_move_button.set_size_request (-1, 30);
2862 mouse_mode_hbox->set_spacing (2);
2864 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2865 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2866 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2867 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2868 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2869 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2870 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2871 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2872 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2874 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2876 mouse_mode_align->add (*mouse_mode_vbox);
2877 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2879 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2881 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2882 if (!Profile->get_sae()) {
2883 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2885 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2887 edit_mode_selector.set_name ("EditModeSelector");
2888 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2889 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2891 mode_box->pack_start (edit_mode_selector, false, false);
2892 mode_box->pack_start (*mouse_mode_box, false, false);
2894 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2895 _mouse_mode_tearoff->set_name ("MouseModeBase");
2896 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2898 if (Profile->get_sae()) {
2899 _mouse_mode_tearoff->set_can_be_torn_off (false);
2902 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2903 &_mouse_mode_tearoff->tearoff_window()));
2904 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2905 &_mouse_mode_tearoff->tearoff_window(), 1));
2906 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2907 &_mouse_mode_tearoff->tearoff_window()));
2908 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2909 &_mouse_mode_tearoff->tearoff_window(), 1));
2913 _zoom_box.set_spacing (2);
2914 _zoom_box.set_border_width (2);
2918 zoom_in_button.set_name ("zoom button");
2919 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2920 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2921 zoom_in_button.set_image(::get_icon ("zoom_in"));
2922 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2923 zoom_in_button.set_related_action (act);
2925 zoom_out_button.set_name ("zoom button");
2926 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2927 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2928 zoom_out_button.set_image(::get_icon ("zoom_out"));
2929 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2930 zoom_out_button.set_related_action (act);
2932 zoom_out_full_button.set_name ("zoom button");
2933 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2934 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2935 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2936 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2937 zoom_out_full_button.set_related_action (act);
2939 zoom_focus_selector.set_name ("ZoomFocusSelector");
2940 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2941 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2943 _zoom_box.pack_start (zoom_out_button, false, false);
2944 _zoom_box.pack_start (zoom_in_button, false, false);
2945 _zoom_box.pack_start (zoom_out_full_button, false, false);
2947 _zoom_box.pack_start (zoom_focus_selector, false, false);
2949 /* Track zoom buttons */
2950 tav_expand_button.set_name ("zoom button");
2951 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2952 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2953 tav_expand_button.set_size_request (-1, 20);
2954 tav_expand_button.set_image(::get_icon ("tav_exp"));
2955 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2956 tav_expand_button.set_related_action (act);
2958 tav_shrink_button.set_name ("zoom button");
2959 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2960 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2961 tav_shrink_button.set_size_request (-1, 20);
2962 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2963 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2964 tav_shrink_button.set_related_action (act);
2966 _zoom_box.pack_start (tav_shrink_button);
2967 _zoom_box.pack_start (tav_expand_button);
2969 _zoom_tearoff = manage (new TearOff (_zoom_box));
2971 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2972 &_zoom_tearoff->tearoff_window()));
2973 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2974 &_zoom_tearoff->tearoff_window(), 0));
2975 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2976 &_zoom_tearoff->tearoff_window()));
2977 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2978 &_zoom_tearoff->tearoff_window(), 0));
2980 snap_box.set_spacing (2);
2981 snap_box.set_border_width (2);
2983 snap_type_selector.set_name ("SnapTypeSelector");
2984 set_popdown_strings (snap_type_selector, snap_type_strings);
2985 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2987 snap_mode_selector.set_name ("SnapModeSelector");
2988 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2989 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2991 edit_point_selector.set_name ("EditPointSelector");
2992 set_popdown_strings (edit_point_selector, edit_point_strings);
2993 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2995 snap_box.pack_start (snap_mode_selector, false, false);
2996 snap_box.pack_start (snap_type_selector, false, false);
2997 snap_box.pack_start (edit_point_selector, false, false);
3001 HBox *nudge_box = manage (new HBox);
3002 nudge_box->set_spacing (2);
3003 nudge_box->set_border_width (2);
3005 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3006 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3008 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3009 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3011 nudge_box->pack_start (nudge_backward_button, false, false);
3012 nudge_box->pack_start (nudge_forward_button, false, false);
3013 nudge_box->pack_start (*nudge_clock, false, false);
3016 /* Pack everything in... */
3018 HBox* hbox = manage (new HBox);
3019 hbox->set_spacing(10);
3021 _tools_tearoff = manage (new TearOff (*hbox));
3022 _tools_tearoff->set_name ("MouseModeBase");
3023 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3025 if (Profile->get_sae()) {
3026 _tools_tearoff->set_can_be_torn_off (false);
3029 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3030 &_tools_tearoff->tearoff_window()));
3031 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3032 &_tools_tearoff->tearoff_window(), 0));
3033 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3034 &_tools_tearoff->tearoff_window()));
3035 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3036 &_tools_tearoff->tearoff_window(), 0));
3038 toolbar_hbox.set_spacing (10);
3039 toolbar_hbox.set_border_width (1);
3041 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3042 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3043 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3045 hbox->pack_start (snap_box, false, false);
3046 if (!Profile->get_small_screen()) {
3047 hbox->pack_start (*nudge_box, false, false);
3049 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3051 hbox->pack_start (panic_box, false, false);
3055 toolbar_base.set_name ("ToolBarBase");
3056 toolbar_base.add (toolbar_hbox);
3058 _toolbar_viewport.add (toolbar_base);
3059 /* stick to the required height but allow width to vary if there's not enough room */
3060 _toolbar_viewport.set_size_request (1, -1);
3062 toolbar_frame.set_shadow_type (SHADOW_OUT);
3063 toolbar_frame.set_name ("BaseFrame");
3064 toolbar_frame.add (_toolbar_viewport);
3068 Editor::setup_tooltips ()
3070 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3071 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3072 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3073 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3074 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3075 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3076 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3077 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3078 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3079 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3080 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3081 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3082 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3083 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3084 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3085 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3086 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3087 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3088 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3089 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3090 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3091 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3092 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3096 Editor::convert_drop_to_paths (
3097 vector<string>& paths,
3098 const RefPtr<Gdk::DragContext>& /*context*/,
3101 const SelectionData& data,
3105 if (_session == 0) {
3109 vector<string> uris = data.get_uris();
3113 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3114 are actually URI lists. So do it by hand.
3117 if (data.get_target() != "text/plain") {
3121 /* Parse the "uri-list" format that Nautilus provides,
3122 where each pathname is delimited by \r\n.
3124 THERE MAY BE NO NULL TERMINATING CHAR!!!
3127 string txt = data.get_text();
3131 p = (const char *) malloc (txt.length() + 1);
3132 txt.copy (const_cast<char *> (p), txt.length(), 0);
3133 const_cast<char*>(p)[txt.length()] = '\0';
3139 while (g_ascii_isspace (*p))
3143 while (*q && (*q != '\n') && (*q != '\r')) {
3150 while (q > p && g_ascii_isspace (*q))
3155 uris.push_back (string (p, q - p + 1));
3159 p = strchr (p, '\n');
3171 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3173 if ((*i).substr (0,7) == "file://") {
3175 string const p = PBD::url_decode (*i);
3177 // scan forward past three slashes
3179 string::size_type slashcnt = 0;
3180 string::size_type n = 0;
3181 string::const_iterator x = p.begin();
3183 while (slashcnt < 3 && x != p.end()) {
3186 } else if (slashcnt == 3) {
3193 if (slashcnt != 3 || x == p.end()) {
3194 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3198 paths.push_back (p.substr (n - 1));
3206 Editor::new_tempo_section ()
3212 Editor::map_transport_state ()
3214 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3216 if (_session && _session->transport_stopped()) {
3217 have_pending_keyboard_selection = false;
3220 update_loop_range_view (true);
3226 Editor::begin_reversible_command (string name)
3229 _session->begin_reversible_command (name);
3234 Editor::begin_reversible_command (GQuark q)
3237 _session->begin_reversible_command (q);
3242 Editor::commit_reversible_command ()
3245 _session->commit_reversible_command ();
3250 Editor::history_changed ()
3254 if (undo_action && _session) {
3255 if (_session->undo_depth() == 0) {
3256 label = S_("Command|Undo");
3258 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3260 undo_action->property_label() = label;
3263 if (redo_action && _session) {
3264 if (_session->redo_depth() == 0) {
3267 label = string_compose(_("Redo (%1)"), _session->next_redo());
3269 redo_action->property_label() = label;
3274 Editor::duplicate_range (bool with_dialog)
3278 RegionSelection rs = get_regions_from_selection_and_entered ();
3280 if ( selection->time.length() == 0 && rs.empty()) {
3286 ArdourDialog win (_("Duplicate"));
3287 Label label (_("Number of duplications:"));
3288 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3289 SpinButton spinner (adjustment, 0.0, 1);
3292 win.get_vbox()->set_spacing (12);
3293 win.get_vbox()->pack_start (hbox);
3294 hbox.set_border_width (6);
3295 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3297 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3298 place, visually. so do this by hand.
3301 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3302 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3303 spinner.grab_focus();
3309 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3310 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3311 win.set_default_response (RESPONSE_ACCEPT);
3313 spinner.grab_focus ();
3315 switch (win.run ()) {
3316 case RESPONSE_ACCEPT:
3322 times = adjustment.get_value();
3325 if ((current_mouse_mode() == Editing::MouseRange)) {
3326 if (selection->time.length()) {
3327 duplicate_selection (times);
3329 } else if (get_smart_mode()) {
3330 if (selection->time.length()) {
3331 duplicate_selection (times);
3333 duplicate_some_regions (rs, times);
3335 duplicate_some_regions (rs, times);
3340 Editor::set_edit_mode (EditMode m)
3342 Config->set_edit_mode (m);
3346 Editor::cycle_edit_mode ()
3348 switch (Config->get_edit_mode()) {
3350 if (Profile->get_sae()) {
3351 Config->set_edit_mode (Lock);
3353 Config->set_edit_mode (Splice);
3357 Config->set_edit_mode (Lock);
3360 Config->set_edit_mode (Slide);
3366 Editor::edit_mode_selection_done ()
3368 string s = edit_mode_selector.get_active_text ();
3371 Config->set_edit_mode (string_to_edit_mode (s));
3376 Editor::snap_type_selection_done ()
3378 string choice = snap_type_selector.get_active_text();
3379 SnapType snaptype = SnapToBeat;
3381 if (choice == _("Beats/2")) {
3382 snaptype = SnapToBeatDiv2;
3383 } else if (choice == _("Beats/3")) {
3384 snaptype = SnapToBeatDiv3;
3385 } else if (choice == _("Beats/4")) {
3386 snaptype = SnapToBeatDiv4;
3387 } else if (choice == _("Beats/5")) {
3388 snaptype = SnapToBeatDiv5;
3389 } else if (choice == _("Beats/6")) {
3390 snaptype = SnapToBeatDiv6;
3391 } else if (choice == _("Beats/7")) {
3392 snaptype = SnapToBeatDiv7;
3393 } else if (choice == _("Beats/8")) {
3394 snaptype = SnapToBeatDiv8;
3395 } else if (choice == _("Beats/10")) {
3396 snaptype = SnapToBeatDiv10;
3397 } else if (choice == _("Beats/12")) {
3398 snaptype = SnapToBeatDiv12;
3399 } else if (choice == _("Beats/14")) {
3400 snaptype = SnapToBeatDiv14;
3401 } else if (choice == _("Beats/16")) {
3402 snaptype = SnapToBeatDiv16;
3403 } else if (choice == _("Beats/20")) {
3404 snaptype = SnapToBeatDiv20;
3405 } else if (choice == _("Beats/24")) {
3406 snaptype = SnapToBeatDiv24;
3407 } else if (choice == _("Beats/28")) {
3408 snaptype = SnapToBeatDiv28;
3409 } else if (choice == _("Beats/32")) {
3410 snaptype = SnapToBeatDiv32;
3411 } else if (choice == _("Beats/64")) {
3412 snaptype = SnapToBeatDiv64;
3413 } else if (choice == _("Beats/128")) {
3414 snaptype = SnapToBeatDiv128;
3415 } else if (choice == _("Beats")) {
3416 snaptype = SnapToBeat;
3417 } else if (choice == _("Bars")) {
3418 snaptype = SnapToBar;
3419 } else if (choice == _("Marks")) {
3420 snaptype = SnapToMark;
3421 } else if (choice == _("Region starts")) {
3422 snaptype = SnapToRegionStart;
3423 } else if (choice == _("Region ends")) {
3424 snaptype = SnapToRegionEnd;
3425 } else if (choice == _("Region bounds")) {
3426 snaptype = SnapToRegionBoundary;
3427 } else if (choice == _("Region syncs")) {
3428 snaptype = SnapToRegionSync;
3429 } else if (choice == _("CD Frames")) {
3430 snaptype = SnapToCDFrame;
3431 } else if (choice == _("Timecode Frames")) {
3432 snaptype = SnapToTimecodeFrame;
3433 } else if (choice == _("Timecode Seconds")) {
3434 snaptype = SnapToTimecodeSeconds;
3435 } else if (choice == _("Timecode Minutes")) {
3436 snaptype = SnapToTimecodeMinutes;
3437 } else if (choice == _("Seconds")) {
3438 snaptype = SnapToSeconds;
3439 } else if (choice == _("Minutes")) {
3440 snaptype = SnapToMinutes;
3443 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3445 ract->set_active ();
3450 Editor::snap_mode_selection_done ()
3452 string choice = snap_mode_selector.get_active_text();
3453 SnapMode mode = SnapNormal;
3455 if (choice == _("No Grid")) {
3457 } else if (choice == _("Grid")) {
3459 } else if (choice == _("Magnetic")) {
3460 mode = SnapMagnetic;
3463 RefPtr<RadioAction> ract = snap_mode_action (mode);
3466 ract->set_active (true);
3471 Editor::cycle_edit_point (bool with_marker)
3473 switch (_edit_point) {
3475 set_edit_point_preference (EditAtPlayhead);
3477 case EditAtPlayhead:
3479 set_edit_point_preference (EditAtSelectedMarker);
3481 set_edit_point_preference (EditAtMouse);
3484 case EditAtSelectedMarker:
3485 set_edit_point_preference (EditAtMouse);
3491 Editor::edit_point_selection_done ()
3493 string choice = edit_point_selector.get_active_text();
3494 EditPoint ep = EditAtSelectedMarker;
3496 if (choice == _("Marker")) {
3497 set_edit_point_preference (EditAtSelectedMarker);
3498 } else if (choice == _("Playhead")) {
3499 set_edit_point_preference (EditAtPlayhead);
3501 set_edit_point_preference (EditAtMouse);
3504 RefPtr<RadioAction> ract = edit_point_action (ep);
3507 ract->set_active (true);
3512 Editor::zoom_focus_selection_done ()
3514 string choice = zoom_focus_selector.get_active_text();
3515 ZoomFocus focus_type = ZoomFocusLeft;
3517 if (choice == _("Left")) {
3518 focus_type = ZoomFocusLeft;
3519 } else if (choice == _("Right")) {
3520 focus_type = ZoomFocusRight;
3521 } else if (choice == _("Center")) {
3522 focus_type = ZoomFocusCenter;
3523 } else if (choice == _("Playhead")) {
3524 focus_type = ZoomFocusPlayhead;
3525 } else if (choice == _("Mouse")) {
3526 focus_type = ZoomFocusMouse;
3527 } else if (choice == _("Edit point")) {
3528 focus_type = ZoomFocusEdit;
3531 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3534 ract->set_active ();
3539 Editor::edit_controls_button_release (GdkEventButton* ev)
3541 if (Keyboard::is_context_menu_event (ev)) {
3542 ARDOUR_UI::instance()->add_route (this);
3543 } else if (ev->button == 1) {
3544 selection->clear_tracks ();
3551 Editor::mouse_select_button_release (GdkEventButton* ev)
3553 /* this handles just right-clicks */
3555 if (ev->button != 3) {
3563 Editor::set_zoom_focus (ZoomFocus f)
3565 string str = zoom_focus_strings[(int)f];
3567 if (str != zoom_focus_selector.get_active_text()) {
3568 zoom_focus_selector.set_active_text (str);
3571 if (zoom_focus != f) {
3578 Editor::cycle_zoom_focus ()
3580 switch (zoom_focus) {
3582 set_zoom_focus (ZoomFocusRight);
3584 case ZoomFocusRight:
3585 set_zoom_focus (ZoomFocusCenter);
3587 case ZoomFocusCenter:
3588 set_zoom_focus (ZoomFocusPlayhead);
3590 case ZoomFocusPlayhead:
3591 set_zoom_focus (ZoomFocusMouse);
3593 case ZoomFocusMouse:
3594 set_zoom_focus (ZoomFocusEdit);
3597 set_zoom_focus (ZoomFocusLeft);
3603 Editor::ensure_float (Window& win)
3605 win.set_transient_for (*this);
3609 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3611 /* recover or initialize pane positions. do this here rather than earlier because
3612 we don't want the positions to change the child allocations, which they seem to do.
3618 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3627 XMLNode* geometry = find_named_node (*node, "geometry");
3629 if (which == static_cast<Paned*> (&edit_pane)) {
3631 if (done & Horizontal) {
3635 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3636 _notebook_shrunk = string_is_affirmative (prop->value ());
3639 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3640 /* initial allocation is 90% to canvas, 10% to notebook */
3641 pos = (int) floor (alloc.get_width() * 0.90f);
3642 snprintf (buf, sizeof(buf), "%d", pos);
3644 pos = atoi (prop->value());
3647 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3648 edit_pane.set_position (pos);
3651 done = (Pane) (done | Horizontal);
3653 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3655 if (done & Vertical) {
3659 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3660 /* initial allocation is 90% to canvas, 10% to summary */
3661 pos = (int) floor (alloc.get_height() * 0.90f);
3662 snprintf (buf, sizeof(buf), "%d", pos);
3665 pos = atoi (prop->value());
3668 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3669 editor_summary_pane.set_position (pos);
3672 done = (Pane) (done | Vertical);
3677 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3679 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3680 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3681 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3682 top_hbox.remove (toolbar_frame);
3687 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3689 if (toolbar_frame.get_parent() == 0) {
3690 top_hbox.pack_end (toolbar_frame);
3695 Editor::set_show_measures (bool yn)
3697 if (_show_measures != yn) {
3700 if ((_show_measures = yn) == true) {
3702 tempo_lines->show();
3704 (void) redraw_measures ();
3711 Editor::toggle_follow_playhead ()
3713 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3715 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3716 set_follow_playhead (tact->get_active());
3720 /** @param yn true to follow playhead, otherwise false.
3721 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3724 Editor::set_follow_playhead (bool yn, bool catch_up)
3726 if (_follow_playhead != yn) {
3727 if ((_follow_playhead = yn) == true && catch_up) {
3729 reset_x_origin_to_follow_playhead ();
3736 Editor::toggle_stationary_playhead ()
3738 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3740 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3741 set_stationary_playhead (tact->get_active());
3746 Editor::set_stationary_playhead (bool yn)
3748 if (_stationary_playhead != yn) {
3749 if ((_stationary_playhead = yn) == true) {
3751 // FIXME need a 3.0 equivalent of this 2.X call
3752 // update_current_screen ();
3759 Editor::playlist_selector () const
3761 return *_playlist_selector;
3765 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3769 switch (_snap_type) {
3774 case SnapToBeatDiv128:
3777 case SnapToBeatDiv64:
3780 case SnapToBeatDiv32:
3783 case SnapToBeatDiv28:
3786 case SnapToBeatDiv24:
3789 case SnapToBeatDiv20:
3792 case SnapToBeatDiv16:
3795 case SnapToBeatDiv14:
3798 case SnapToBeatDiv12:
3801 case SnapToBeatDiv10:
3804 case SnapToBeatDiv8:
3807 case SnapToBeatDiv7:
3810 case SnapToBeatDiv6:
3813 case SnapToBeatDiv5:
3816 case SnapToBeatDiv4:
3819 case SnapToBeatDiv3:
3822 case SnapToBeatDiv2:
3828 return _session->tempo_map().meter_at (position).divisions_per_bar();
3833 case SnapToTimecodeFrame:
3834 case SnapToTimecodeSeconds:
3835 case SnapToTimecodeMinutes:
3838 case SnapToRegionStart:
3839 case SnapToRegionEnd:
3840 case SnapToRegionSync:
3841 case SnapToRegionBoundary:
3851 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3855 ret = nudge_clock->current_duration (pos);
3856 next = ret + 1; /* XXXX fix me */
3862 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3864 ArdourDialog dialog (_("Playlist Deletion"));
3865 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3866 "If it is kept, its audio files will not be cleaned.\n"
3867 "If it is deleted, audio files used by it alone will be cleaned."),
3870 dialog.set_position (WIN_POS_CENTER);
3871 dialog.get_vbox()->pack_start (label);
3875 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3876 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3877 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3879 switch (dialog.run ()) {
3880 case RESPONSE_ACCEPT:
3881 /* delete the playlist */
3885 case RESPONSE_REJECT:
3886 /* keep the playlist */
3898 Editor::audio_region_selection_covers (framepos_t where)
3900 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3901 if ((*a)->region()->covers (where)) {
3910 Editor::prepare_for_cleanup ()
3912 cut_buffer->clear_regions ();
3913 cut_buffer->clear_playlists ();
3915 selection->clear_regions ();
3916 selection->clear_playlists ();
3918 _regions->suspend_redisplay ();
3922 Editor::finish_cleanup ()
3924 _regions->resume_redisplay ();
3928 Editor::transport_loop_location()
3931 return _session->locations()->auto_loop_location();
3938 Editor::transport_punch_location()
3941 return _session->locations()->auto_punch_location();
3948 Editor::control_layout_scroll (GdkEventScroll* ev)
3950 if (Keyboard::some_magic_widget_has_focus()) {
3954 switch (ev->direction) {
3956 scroll_tracks_up_line ();
3960 case GDK_SCROLL_DOWN:
3961 scroll_tracks_down_line ();
3965 /* no left/right handling yet */
3973 Editor::session_state_saved (string)
3976 _snapshots->redisplay ();
3980 Editor::update_tearoff_visibility()
3982 bool visible = Config->get_keep_tearoffs();
3983 _mouse_mode_tearoff->set_visible (visible);
3984 _tools_tearoff->set_visible (visible);
3985 _zoom_tearoff->set_visible (visible);
3989 Editor::maximise_editing_space ()
4001 Editor::restore_editing_space ()
4013 * Make new playlists for a given track and also any others that belong
4014 * to the same active route group with the `select' property.
4019 Editor::new_playlists (TimeAxisView* v)
4021 begin_reversible_command (_("new playlists"));
4022 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4023 _session->playlists->get (playlists);
4024 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4025 commit_reversible_command ();
4029 * Use a copy of the current playlist for a given track and also any others that belong
4030 * to the same active route group with the `select' property.
4035 Editor::copy_playlists (TimeAxisView* v)
4037 begin_reversible_command (_("copy playlists"));
4038 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4039 _session->playlists->get (playlists);
4040 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4041 commit_reversible_command ();
4044 /** Clear the current playlist for a given track and also any others that belong
4045 * to the same active route group with the `select' property.
4050 Editor::clear_playlists (TimeAxisView* v)
4052 begin_reversible_command (_("clear playlists"));
4053 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4054 _session->playlists->get (playlists);
4055 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4056 commit_reversible_command ();
4060 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4062 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4066 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4068 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4072 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4074 atv.clear_playlist ();
4078 Editor::on_key_press_event (GdkEventKey* ev)
4080 return key_press_focus_accelerator_handler (*this, ev);
4084 Editor::on_key_release_event (GdkEventKey* ev)
4086 return Gtk::Window::on_key_release_event (ev);
4087 // return key_press_focus_accelerator_handler (*this, ev);
4090 /** Queue up a change to the viewport x origin.
4091 * @param frame New x origin.
4094 Editor::reset_x_origin (framepos_t frame)
4096 pending_visual_change.add (VisualChange::TimeOrigin);
4097 pending_visual_change.time_origin = frame;
4098 ensure_visual_change_idle_handler ();
4102 Editor::reset_y_origin (double y)
4104 pending_visual_change.add (VisualChange::YOrigin);
4105 pending_visual_change.y_origin = y;
4106 ensure_visual_change_idle_handler ();
4110 Editor::reset_zoom (double fpu)
4112 clamp_frames_per_unit (fpu);
4114 if (fpu == frames_per_unit) {
4118 pending_visual_change.add (VisualChange::ZoomLevel);
4119 pending_visual_change.frames_per_unit = fpu;
4120 ensure_visual_change_idle_handler ();
4124 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4126 reset_x_origin (frame);
4129 if (!no_save_visual) {
4130 undo_visual_stack.push_back (current_visual_state(false));
4134 Editor::VisualState::VisualState (bool with_tracks)
4135 : gui_state (with_tracks ? new GUIObjectState : 0)
4139 Editor::VisualState::~VisualState ()
4144 Editor::VisualState*
4145 Editor::current_visual_state (bool with_tracks)
4147 VisualState* vs = new VisualState (with_tracks);
4148 vs->y_position = vertical_adjustment.get_value();
4149 vs->frames_per_unit = frames_per_unit;
4150 vs->leftmost_frame = leftmost_frame;
4151 vs->zoom_focus = zoom_focus;
4154 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4161 Editor::undo_visual_state ()
4163 if (undo_visual_stack.empty()) {
4167 VisualState* vs = undo_visual_stack.back();
4168 undo_visual_stack.pop_back();
4171 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4173 use_visual_state (*vs);
4177 Editor::redo_visual_state ()
4179 if (redo_visual_stack.empty()) {
4183 VisualState* vs = redo_visual_stack.back();
4184 redo_visual_stack.pop_back();
4186 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4188 use_visual_state (*vs);
4192 Editor::swap_visual_state ()
4194 if (undo_visual_stack.empty()) {
4195 redo_visual_state ();
4197 undo_visual_state ();
4202 Editor::use_visual_state (VisualState& vs)
4204 PBD::Unwinder<bool> nsv (no_save_visual, true);
4206 _routes->suspend_redisplay ();
4208 vertical_adjustment.set_value (vs.y_position);
4210 set_zoom_focus (vs.zoom_focus);
4211 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4214 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4216 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4217 (*i)->reset_visual_state ();
4221 _routes->update_visibility ();
4222 _routes->resume_redisplay ();
4225 /** This is the core function that controls the zoom level of the canvas. It is called
4226 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4227 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4230 Editor::set_frames_per_unit (double fpu)
4233 tempo_lines->tempo_map_changed();
4236 frames_per_unit = fpu;
4238 /* convert fpu to frame count */
4240 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4242 if (frames_per_unit != zoom_range_clock->current_duration()) {
4243 zoom_range_clock->set (frames);
4246 bool const showing_time_selection = selection->time.length() > 0;
4248 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4249 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4250 (*i)->reshow_selection (selection->time);
4254 ZoomChanged (); /* EMIT_SIGNAL */
4256 //reset_scrolling_region ();
4258 if (playhead_cursor) {
4259 playhead_cursor->set_position (playhead_cursor->current_frame);
4262 refresh_location_display();
4263 _summary->set_overlays_dirty ();
4265 update_marker_labels ();
4271 Editor::queue_visual_videotimeline_update ()
4274 * pending_visual_change.add (VisualChange::VideoTimeline);
4275 * or maybe even more specific: which videotimeline-image
4276 * currently it calls update_video_timeline() to update
4277 * _all outdated_ images on the video-timeline.
4278 * see 'exposeimg()' in video_image_frame.cc
4280 ensure_visual_change_idle_handler ();
4284 Editor::ensure_visual_change_idle_handler ()
4286 if (pending_visual_change.idle_handler_id < 0) {
4287 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4292 Editor::_idle_visual_changer (void* arg)
4294 return static_cast<Editor*>(arg)->idle_visual_changer ();
4298 Editor::idle_visual_changer ()
4300 /* set_horizontal_position() below (and maybe other calls) call
4301 gtk_main_iteration(), so it's possible that a signal will be handled
4302 half-way through this method. If this signal wants an
4303 idle_visual_changer we must schedule another one after this one, so
4304 mark the idle_handler_id as -1 here to allow that. Also make a note
4305 that we are doing the visual change, so that changes in response to
4306 super-rapid-screen-update can be dropped if we are still processing
4310 pending_visual_change.idle_handler_id = -1;
4311 pending_visual_change.being_handled = true;
4313 VisualChange::Type p = pending_visual_change.pending;
4314 pending_visual_change.pending = (VisualChange::Type) 0;
4316 double const last_time_origin = horizontal_position ();
4318 if (p & VisualChange::ZoomLevel) {
4319 set_frames_per_unit (pending_visual_change.frames_per_unit);
4321 compute_fixed_ruler_scale ();
4323 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4324 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4326 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4327 current_bbt_points_begin, current_bbt_points_end);
4328 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4329 current_bbt_points_begin, current_bbt_points_end);
4330 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4333 if (p & VisualChange::ZoomLevel) {
4334 update_video_timeline();
4337 if (p & VisualChange::TimeOrigin) {
4338 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4341 if (p & VisualChange::YOrigin) {
4342 vertical_adjustment.set_value (pending_visual_change.y_origin);
4345 if (last_time_origin == horizontal_position ()) {
4346 /* changed signal not emitted */
4347 update_fixed_rulers ();
4348 redisplay_tempo (true);
4351 if (!(p & VisualChange::ZoomLevel)) {
4352 update_video_timeline();
4355 _summary->set_overlays_dirty ();
4357 pending_visual_change.being_handled = false;
4358 return 0; /* this is always a one-shot call */
4361 struct EditorOrderTimeAxisSorter {
4362 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4363 return a->order () < b->order ();
4368 Editor::sort_track_selection (TrackViewList& sel)
4370 EditorOrderTimeAxisSorter cmp;
4375 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4378 framepos_t where = 0;
4379 EditPoint ep = _edit_point;
4381 if (from_context_menu && (ep == EditAtMouse)) {
4382 return event_frame (&context_click_event, 0, 0);
4385 if (entered_marker) {
4386 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4387 return entered_marker->position();
4390 if (ignore_playhead && ep == EditAtPlayhead) {
4391 ep = EditAtSelectedMarker;
4395 case EditAtPlayhead:
4396 where = _session->audible_frame();
4397 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4400 case EditAtSelectedMarker:
4401 if (!selection->markers.empty()) {
4403 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4406 where = loc->start();
4410 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4418 if (!mouse_frame (where, ignored)) {
4419 /* XXX not right but what can we do ? */
4423 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4431 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4433 if (!_session) return;
4435 begin_reversible_command (cmd);
4439 if ((tll = transport_loop_location()) == 0) {
4440 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4441 XMLNode &before = _session->locations()->get_state();
4442 _session->locations()->add (loc, true);
4443 _session->set_auto_loop_location (loc);
4444 XMLNode &after = _session->locations()->get_state();
4445 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4447 XMLNode &before = tll->get_state();
4448 tll->set_hidden (false, this);
4449 tll->set (start, end);
4450 XMLNode &after = tll->get_state();
4451 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4454 commit_reversible_command ();
4458 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4460 if (!_session) return;
4462 begin_reversible_command (cmd);
4466 if ((tpl = transport_punch_location()) == 0) {
4467 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4468 XMLNode &before = _session->locations()->get_state();
4469 _session->locations()->add (loc, true);
4470 _session->set_auto_loop_location (loc);
4471 XMLNode &after = _session->locations()->get_state();
4472 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4475 XMLNode &before = tpl->get_state();
4476 tpl->set_hidden (false, this);
4477 tpl->set (start, end);
4478 XMLNode &after = tpl->get_state();
4479 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4482 commit_reversible_command ();
4485 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4486 * @param rs List to which found regions are added.
4487 * @param where Time to look at.
4488 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4491 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4493 const TrackViewList* tracks;
4496 tracks = &track_views;
4501 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4503 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4506 boost::shared_ptr<Track> tr;
4507 boost::shared_ptr<Playlist> pl;
4509 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4511 boost::shared_ptr<RegionList> regions = pl->regions_at (
4512 (framepos_t) floor ( (double) where * tr->speed()));
4514 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4515 RegionView* rv = rtv->view()->find_view (*i);
4526 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4528 const TrackViewList* tracks;
4531 tracks = &track_views;
4536 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4537 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4539 boost::shared_ptr<Track> tr;
4540 boost::shared_ptr<Playlist> pl;
4542 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4544 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4545 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4547 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4549 RegionView* rv = rtv->view()->find_view (*i);
4560 /** Get regions using the following method:
4562 * Make a region list using the selected regions, unless
4563 * the edit point is `mouse' and the mouse is over an unselected
4564 * region. In this case, use just that region.
4566 * If the edit point is not 'mouse', and there are no regions selected,
4567 * search the list of selected tracks and return regions that are under
4568 * the edit point on these tracks. If there are no selected tracks and
4569 * 'No Selection = All Tracks' is active, search all tracks,
4571 * The rationale here is that the mouse edit point is special in that
4572 * its position describes both a time and a track; the other edit
4573 * modes only describe a time. Hence if the edit point is `mouse' we
4574 * ignore selected tracks, as we assume the user means something by
4575 * pointing at a particular track. Also in this case we take note of
4576 * the region directly under the edit point, as there is always just one
4577 * (rather than possibly several with non-mouse edit points).
4581 Editor::get_regions_from_selection_and_edit_point ()
4583 RegionSelection regions;
4585 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4586 regions.add (entered_regionview);
4588 regions = selection->regions;
4592 if (regions.empty() && _edit_point != EditAtMouse) {
4593 TrackViewList tracks = selection->tracks;
4595 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4596 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4597 * is enabled, so consider all tracks
4599 tracks = track_views;
4602 if (!tracks.empty()) {
4603 /* no region selected or entered, but some selected tracks:
4604 * act on all regions on the selected tracks at the edit point
4606 framepos_t const where = get_preferred_edit_position ();
4607 get_regions_at(regions, where, tracks);
4613 /** Start with regions that are selected, or the entered regionview if none are selected.
4614 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4615 * of the regions that we started with.
4619 Editor::get_regions_from_selection_and_entered ()
4621 RegionSelection regions = selection->regions;
4623 if (regions.empty() && entered_regionview) {
4624 regions.add (entered_regionview);
4631 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4633 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4635 RouteTimeAxisView* tatv;
4637 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4639 boost::shared_ptr<Playlist> pl;
4640 vector<boost::shared_ptr<Region> > results;
4642 boost::shared_ptr<Track> tr;
4644 if ((tr = tatv->track()) == 0) {
4649 if ((pl = (tr->playlist())) != 0) {
4650 if (src_comparison) {
4651 pl->get_source_equivalent_regions (region, results);
4653 pl->get_region_list_equivalent_regions (region, results);
4657 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4658 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4659 regions.push_back (marv);
4668 Editor::show_rhythm_ferret ()
4670 if (rhythm_ferret == 0) {
4671 rhythm_ferret = new RhythmFerret(*this);
4674 rhythm_ferret->set_session (_session);
4675 rhythm_ferret->show ();
4676 rhythm_ferret->present ();
4680 Editor::first_idle ()
4682 MessageDialog* dialog = 0;
4684 if (track_views.size() > 1) {
4685 dialog = new MessageDialog (
4687 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4691 ARDOUR_UI::instance()->flush_pending ();
4694 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4698 // first idle adds route children (automation tracks), so we need to redisplay here
4699 _routes->redisplay ();
4706 Editor::_idle_resize (gpointer arg)
4708 return ((Editor*)arg)->idle_resize ();
4712 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4714 if (resize_idle_id < 0) {
4715 resize_idle_id = g_idle_add (_idle_resize, this);
4716 _pending_resize_amount = 0;
4719 /* make a note of the smallest resulting height, so that we can clamp the
4720 lower limit at TimeAxisView::hSmall */
4722 int32_t min_resulting = INT32_MAX;
4724 _pending_resize_amount += h;
4725 _pending_resize_view = view;
4727 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4729 if (selection->tracks.contains (_pending_resize_view)) {
4730 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4731 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4735 if (min_resulting < 0) {
4740 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4741 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4745 /** Handle pending resizing of tracks */
4747 Editor::idle_resize ()
4749 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4751 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4752 selection->tracks.contains (_pending_resize_view)) {
4754 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4755 if (*i != _pending_resize_view) {
4756 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4761 _pending_resize_amount = 0;
4763 _group_tabs->set_dirty ();
4764 resize_idle_id = -1;
4772 ENSURE_GUI_THREAD (*this, &Editor::located);
4775 playhead_cursor->set_position (_session->audible_frame ());
4776 if (_follow_playhead && !_pending_initial_locate) {
4777 reset_x_origin_to_follow_playhead ();
4781 _pending_locate_request = false;
4782 _pending_initial_locate = false;
4786 Editor::region_view_added (RegionView *)
4788 _summary->set_dirty ();
4792 Editor::region_view_removed ()
4794 _summary->set_dirty ();
4798 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4800 TrackViewList::const_iterator j = track_views.begin ();
4801 while (j != track_views.end()) {
4802 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4803 if (rtv && rtv->route() == r) {
4814 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4818 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4819 TimeAxisView* tv = axis_view_from_route (*i);
4829 Editor::add_routes (RouteList& routes)
4831 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4833 RouteTimeAxisView *rtv;
4834 list<RouteTimeAxisView*> new_views;
4836 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4837 boost::shared_ptr<Route> route = (*x);
4839 if (route->is_auditioner() || route->is_monitor()) {
4843 DataType dt = route->input()->default_type();
4845 if (dt == ARDOUR::DataType::AUDIO) {
4846 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4847 rtv->set_route (route);
4848 } else if (dt == ARDOUR::DataType::MIDI) {
4849 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4850 rtv->set_route (route);
4852 throw unknown_type();
4855 new_views.push_back (rtv);
4856 track_views.push_back (rtv);
4858 rtv->effective_gain_display ();
4860 if (internal_editing()) {
4861 rtv->enter_internal_edit_mode ();
4863 rtv->leave_internal_edit_mode ();
4866 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4867 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4870 _routes->routes_added (new_views);
4871 _summary->routes_added (new_views);
4873 if (show_editor_mixer_when_tracks_arrive) {
4874 show_editor_mixer (true);
4877 editor_list_button.set_sensitive (true);
4881 Editor::timeaxisview_deleted (TimeAxisView *tv)
4883 if (_session && _session->deletion_in_progress()) {
4884 /* the situation is under control */
4888 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4890 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4892 _routes->route_removed (tv);
4894 if (tv == entered_track) {
4898 TimeAxisView::Children c = tv->get_child_list ();
4899 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4900 if (entered_track == i->get()) {
4905 /* remove it from the list of track views */
4907 TrackViewList::iterator i;
4909 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4910 i = track_views.erase (i);
4913 /* update whatever the current mixer strip is displaying, if revelant */
4915 boost::shared_ptr<Route> route;
4918 route = rtav->route ();
4921 if (current_mixer_strip && current_mixer_strip->route() == route) {
4923 TimeAxisView* next_tv;
4925 if (track_views.empty()) {
4927 } else if (i == track_views.end()) {
4928 next_tv = track_views.front();
4935 set_selected_mixer_strip (*next_tv);
4937 /* make the editor mixer strip go away setting the
4938 * button to inactive (which also unticks the menu option)
4941 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4947 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4949 if (apply_to_selection) {
4950 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4952 TrackSelection::iterator j = i;
4955 hide_track_in_display (*i, false);
4960 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4962 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4963 // this will hide the mixer strip
4964 set_selected_mixer_strip (*tv);
4967 _routes->hide_track_in_display (*tv);
4972 Editor::sync_track_view_list_and_routes ()
4974 track_views = TrackViewList (_routes->views ());
4976 _summary->set_dirty ();
4977 _group_tabs->set_dirty ();
4979 return false; // do not call again (until needed)
4983 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4985 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4990 /** Find a RouteTimeAxisView by the ID of its route */
4992 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4994 RouteTimeAxisView* v;
4996 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4997 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4998 if(v->route()->id() == id) {
5008 Editor::fit_route_group (RouteGroup *g)
5010 TrackViewList ts = axis_views_from_routes (g->route_list ());
5015 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5017 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5020 _session->cancel_audition ();
5024 if (_session->is_auditioning()) {
5025 _session->cancel_audition ();
5026 if (r == last_audition_region) {
5031 _session->audition_region (r);
5032 last_audition_region = r;
5037 Editor::hide_a_region (boost::shared_ptr<Region> r)
5039 r->set_hidden (true);
5043 Editor::show_a_region (boost::shared_ptr<Region> r)
5045 r->set_hidden (false);
5049 Editor::audition_region_from_region_list ()
5051 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5055 Editor::hide_region_from_region_list ()
5057 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5061 Editor::show_region_in_region_list ()
5063 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5067 Editor::step_edit_status_change (bool yn)
5070 start_step_editing ();
5072 stop_step_editing ();
5077 Editor::start_step_editing ()
5079 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5083 Editor::stop_step_editing ()
5085 step_edit_connection.disconnect ();
5089 Editor::check_step_edit ()
5091 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5092 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5094 mtv->check_step_edit ();
5098 return true; // do it again, till we stop
5102 Editor::scroll_press (Direction dir)
5104 ++_scroll_callbacks;
5106 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5107 /* delay the first auto-repeat */
5113 scroll_backward (1);
5121 scroll_tracks_up_line ();
5125 scroll_tracks_down_line ();
5129 /* do hacky auto-repeat */
5130 if (!_scroll_connection.connected ()) {
5132 _scroll_connection = Glib::signal_timeout().connect (
5133 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5136 _scroll_callbacks = 0;
5143 Editor::scroll_release ()
5145 _scroll_connection.disconnect ();
5148 /** Queue a change for the Editor viewport x origin to follow the playhead */
5150 Editor::reset_x_origin_to_follow_playhead ()
5152 framepos_t const frame = playhead_cursor->current_frame;
5154 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5156 if (_session->transport_speed() < 0) {
5158 if (frame > (current_page_frames() / 2)) {
5159 center_screen (frame-(current_page_frames()/2));
5161 center_screen (current_page_frames()/2);
5168 if (frame < leftmost_frame) {
5170 if (_session->transport_rolling()) {
5171 /* rolling; end up with the playhead at the right of the page */
5172 l = frame - current_page_frames ();
5174 /* not rolling: end up with the playhead 1/4 of the way along the page */
5175 l = frame - current_page_frames() / 4;
5179 if (_session->transport_rolling()) {
5180 /* rolling: end up with the playhead on the left of the page */
5183 /* not rolling: end up with the playhead 3/4 of the way along the page */
5184 l = frame - 3 * current_page_frames() / 4;
5192 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5198 Editor::super_rapid_screen_update ()
5200 if (!_session || !_session->engine().running()) {
5204 /* METERING / MIXER STRIPS */
5206 /* update track meters, if required */
5207 if (is_mapped() && meters_running) {
5208 RouteTimeAxisView* rtv;
5209 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5210 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5211 rtv->fast_update ();
5216 /* and any current mixer strip */
5217 if (current_mixer_strip) {
5218 current_mixer_strip->fast_update ();
5221 /* PLAYHEAD AND VIEWPORT */
5223 framepos_t const frame = _session->audible_frame();
5225 /* There are a few reasons why we might not update the playhead / viewport stuff:
5227 * 1. we don't update things when there's a pending locate request, otherwise
5228 * when the editor requests a locate there is a chance that this method
5229 * will move the playhead before the locate request is processed, causing
5231 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5232 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5235 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5237 last_update_frame = frame;
5239 if (!_dragging_playhead) {
5240 playhead_cursor->set_position (frame);
5243 if (!_stationary_playhead) {
5245 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5246 /* We only do this if we aren't already
5247 handling a visual change (ie if
5248 pending_visual_change.being_handled is
5249 false) so that these requests don't stack
5250 up there are too many of them to handle in
5253 reset_x_origin_to_follow_playhead ();
5258 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5262 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5263 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5264 if (target <= 0.0) {
5267 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5268 target = (target * 0.15) + (current * 0.85);
5274 set_horizontal_position (current);
5283 Editor::session_going_away ()
5285 _have_idled = false;
5287 _session_connections.drop_connections ();
5289 super_rapid_screen_update_connection.disconnect ();
5291 selection->clear ();
5292 cut_buffer->clear ();
5294 clicked_regionview = 0;
5295 clicked_axisview = 0;
5296 clicked_routeview = 0;
5297 entered_regionview = 0;
5299 last_update_frame = 0;
5302 playhead_cursor->canvas_item.hide ();
5304 /* rip everything out of the list displays */
5308 _route_groups->clear ();
5310 /* do this first so that deleting a track doesn't reset cms to null
5311 and thus cause a leak.
5314 if (current_mixer_strip) {
5315 if (current_mixer_strip->get_parent() != 0) {
5316 global_hpacker.remove (*current_mixer_strip);
5318 delete current_mixer_strip;
5319 current_mixer_strip = 0;
5322 /* delete all trackviews */
5324 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5327 track_views.clear ();
5329 zoom_range_clock->set_session (0);
5330 nudge_clock->set_session (0);
5332 editor_list_button.set_active(false);
5333 editor_list_button.set_sensitive(false);
5335 /* clear tempo/meter rulers */
5336 remove_metric_marks ();
5338 clear_marker_display ();
5340 stop_step_editing ();
5342 /* get rid of any existing editor mixer strip */
5344 WindowTitle title(Glib::get_application_name());
5345 title += _("Editor");
5347 set_title (title.get_string());
5349 SessionHandlePtr::session_going_away ();
5354 Editor::show_editor_list (bool yn)
5357 _the_notebook.show ();
5359 _the_notebook.hide ();
5364 Editor::change_region_layering_order (bool from_context_menu)
5366 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5368 if (!clicked_routeview) {
5369 if (layering_order_editor) {
5370 layering_order_editor->hide ();
5375 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5381 boost::shared_ptr<Playlist> pl = track->playlist();
5387 if (layering_order_editor == 0) {
5388 layering_order_editor = new RegionLayeringOrderEditor (*this);
5391 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5392 layering_order_editor->maybe_present ();
5396 Editor::update_region_layering_order_editor ()
5398 if (layering_order_editor && layering_order_editor->is_visible ()) {
5399 change_region_layering_order (true);
5404 Editor::setup_fade_images ()
5406 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5407 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5408 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5409 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5410 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5412 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5413 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5414 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5415 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5416 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5418 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5419 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5420 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5421 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5422 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5424 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5425 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5426 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5427 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5428 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5432 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5434 Editor::action_menu_item (std::string const & name)
5436 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5439 return *manage (a->create_menu_item ());
5443 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5445 EventBox* b = manage (new EventBox);
5446 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5447 Label* l = manage (new Label (name));
5451 _the_notebook.append_page (widget, *b);
5455 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5457 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5458 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5461 if (ev->type == GDK_2BUTTON_PRESS) {
5463 /* double-click on a notebook tab shrinks or expands the notebook */
5465 if (_notebook_shrunk) {
5466 if (pre_notebook_shrink_pane_width) {
5467 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5469 _notebook_shrunk = false;
5471 pre_notebook_shrink_pane_width = edit_pane.get_position();
5473 /* this expands the LHS of the edit pane to cover the notebook
5474 PAGE but leaves the tabs visible.
5476 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5477 _notebook_shrunk = true;
5485 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5487 using namespace Menu_Helpers;
5489 MenuList& items = _control_point_context_menu.items ();
5492 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5493 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5494 if (!can_remove_control_point (item)) {
5495 items.back().set_sensitive (false);
5498 _control_point_context_menu.popup (event->button.button, event->button.time);
5502 Editor::shift_key_released ()
5504 _stepping_axis_view = 0;