2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "canvas/debug.h"
74 #include "canvas/text.h"
76 #include "control_protocol/control_protocol.h"
80 #include "analysis_window.h"
81 #include "audio_clock.h"
82 #include "audio_region_view.h"
83 #include "audio_streamview.h"
84 #include "audio_time_axis.h"
85 #include "automation_time_axis.h"
86 #include "bundle_manager.h"
87 #include "crossfade_edit.h"
91 #include "editor_cursors.h"
92 #include "editor_drag.h"
93 #include "editor_group_tabs.h"
94 #include "editor_locations.h"
95 #include "editor_regions.h"
96 #include "editor_route_groups.h"
97 #include "editor_routes.h"
98 #include "editor_snapshots.h"
99 #include "editor_summary.h"
100 #include "global_port_matrix.h"
101 #include "gui_object.h"
102 #include "gui_thread.h"
103 #include "keyboard.h"
105 #include "midi_time_axis.h"
106 #include "mixer_strip.h"
107 #include "mixer_ui.h"
108 #include "mouse_cursors.h"
109 #include "playlist_selector.h"
110 #include "public_editor.h"
111 #include "region_layering_order_editor.h"
112 #include "rgb_macros.h"
113 #include "rhythm_ferret.h"
114 #include "selection.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 , videotl_label (_("Video Timeline"))
250 , edit_packer (4, 4, true)
252 /* the values here don't matter: layout widgets
253 reset them as needed.
256 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
257 , horizontal_adjustment (0.0, 0.0, 1e16)
258 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
260 , controls_layout (unused_adjustment, vertical_adjustment)
262 /* tool bar related */
264 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
266 , toolbar_selection_clock_table (2,3)
268 , automation_mode_button (_("mode"))
270 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
273 , image_socket_listener(0)
278 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
279 , meters_running(false)
280 , _pending_locate_request (false)
281 , _pending_initial_locate (false)
282 , _last_cut_copy_source_track (0)
284 , _region_selection_change_updates_region_list (true)
285 , _following_mixer_selection (false)
286 , _control_point_toggled_on_press (false)
287 , _stepping_axis_view (0)
291 /* we are a singleton */
293 PublicEditor::_instance = this;
297 selection = new Selection (this);
298 cut_buffer = new Selection (this);
300 clicked_regionview = 0;
301 clicked_axisview = 0;
302 clicked_routeview = 0;
303 clicked_control_point = 0;
304 last_update_frame = 0;
305 pre_press_cursor = 0;
306 _drags = new DragManager (this);
307 current_mixer_strip = 0;
310 snap_type_strings = I18N (_snap_type_strings);
311 snap_mode_strings = I18N (_snap_mode_strings);
312 zoom_focus_strings = I18N (_zoom_focus_strings);
313 edit_point_strings = I18N (_edit_point_strings);
314 #ifdef USE_RUBBERBAND
315 rb_opt_strings = I18N (_rb_opt_strings);
319 snap_threshold = 5.0;
320 bbt_beat_subdivision = 4;
321 _visible_canvas_width = 0;
322 _visible_canvas_height = 0;
323 last_autoscroll_x = 0;
324 last_autoscroll_y = 0;
325 autoscroll_active = false;
326 autoscroll_timeout_tag = -1;
331 current_interthread_info = 0;
332 _show_measures = true;
334 show_gain_after_trim = false;
336 have_pending_keyboard_selection = false;
337 _follow_playhead = true;
338 _stationary_playhead = false;
339 editor_ruler_menu = 0;
340 no_ruler_shown_update = false;
342 range_marker_menu = 0;
343 marker_menu_item = 0;
344 tempo_or_meter_marker_menu = 0;
345 transport_marker_menu = 0;
346 new_transport_marker_menu = 0;
347 editor_mixer_strip_width = Wide;
348 show_editor_mixer_when_tracks_arrive = false;
349 region_edit_menu_split_multichannel_item = 0;
350 region_edit_menu_split_item = 0;
353 current_stepping_trackview = 0;
355 entered_regionview = 0;
357 clear_entered_track = false;
360 button_release_can_deselect = true;
361 _dragging_playhead = false;
362 _dragging_edit_point = false;
363 select_new_marker = false;
365 layering_order_editor = 0;
366 no_save_visual = false;
368 within_track_canvas = false;
370 scrubbing_direction = 0;
374 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
375 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
376 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
377 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
378 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
380 _edit_point = EditAtMouse;
381 _internal_editing = false;
382 current_canvas_cursor = 0;
384 samples_per_pixel = 2048; /* too early to use reset_zoom () */
386 _scroll_callbacks = 0;
388 zoom_focus = ZoomFocusLeft;
389 set_zoom_focus (ZoomFocusLeft);
390 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
392 bbt_label.set_name ("EditorRulerLabel");
393 bbt_label.set_size_request (-1, (int)timebar_height);
394 bbt_label.set_alignment (1.0, 0.5);
395 bbt_label.set_padding (5,0);
397 bbt_label.set_no_show_all();
398 minsec_label.set_name ("EditorRulerLabel");
399 minsec_label.set_size_request (-1, (int)timebar_height);
400 minsec_label.set_alignment (1.0, 0.5);
401 minsec_label.set_padding (5,0);
402 minsec_label.hide ();
403 minsec_label.set_no_show_all();
404 timecode_label.set_name ("EditorRulerLabel");
405 timecode_label.set_size_request (-1, (int)timebar_height);
406 timecode_label.set_alignment (1.0, 0.5);
407 timecode_label.set_padding (5,0);
408 timecode_label.hide ();
409 timecode_label.set_no_show_all();
410 samples_label.set_name ("EditorRulerLabel");
411 samples_label.set_size_request (-1, (int)timebar_height);
412 samples_label.set_alignment (1.0, 0.5);
413 samples_label.set_padding (5,0);
414 samples_label.hide ();
415 samples_label.set_no_show_all();
417 tempo_label.set_name ("EditorRulerLabel");
418 tempo_label.set_size_request (-1, (int)timebar_height);
419 tempo_label.set_alignment (1.0, 0.5);
420 tempo_label.set_padding (5,0);
422 tempo_label.set_no_show_all();
424 meter_label.set_name ("EditorRulerLabel");
425 meter_label.set_size_request (-1, (int)timebar_height);
426 meter_label.set_alignment (1.0, 0.5);
427 meter_label.set_padding (5,0);
429 meter_label.set_no_show_all();
431 mark_label.set_name ("EditorRulerLabel");
432 mark_label.set_size_request (-1, (int)timebar_height);
433 mark_label.set_alignment (1.0, 0.5);
434 mark_label.set_padding (5,0);
436 mark_label.set_no_show_all();
438 cd_mark_label.set_name ("EditorRulerLabel");
439 cd_mark_label.set_size_request (-1, (int)timebar_height);
440 cd_mark_label.set_alignment (1.0, 0.5);
441 cd_mark_label.set_padding (5,0);
442 cd_mark_label.hide();
443 cd_mark_label.set_no_show_all();
445 videotl_bar_height = 4;
446 videotl_label.set_name ("EditorRulerLabel");
447 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
448 videotl_label.set_alignment (1.0, 0.5);
449 videotl_label.set_padding (5,0);
450 videotl_label.hide();
451 videotl_label.set_no_show_all();
453 range_mark_label.set_name ("EditorRulerLabel");
454 range_mark_label.set_size_request (-1, (int)timebar_height);
455 range_mark_label.set_alignment (1.0, 0.5);
456 range_mark_label.set_padding (5,0);
457 range_mark_label.hide();
458 range_mark_label.set_no_show_all();
460 transport_mark_label.set_name ("EditorRulerLabel");
461 transport_mark_label.set_size_request (-1, (int)timebar_height);
462 transport_mark_label.set_alignment (1.0, 0.5);
463 transport_mark_label.set_padding (5,0);
464 transport_mark_label.hide();
465 transport_mark_label.set_no_show_all();
467 initialize_rulers ();
468 initialize_canvas ();
470 _summary = new EditorSummary (this);
472 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
473 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
475 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
477 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
478 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
480 edit_controls_vbox.set_spacing (0);
481 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
482 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
484 HBox* h = manage (new HBox);
485 _group_tabs = new EditorGroupTabs (this);
486 h->pack_start (*_group_tabs, PACK_SHRINK);
487 h->pack_start (edit_controls_vbox);
488 controls_layout.add (*h);
490 controls_layout.set_name ("EditControlsBase");
491 controls_layout.add_events (Gdk::SCROLL_MASK);
492 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
494 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
495 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
497 _cursors = new MouseCursors;
499 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
501 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
502 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
503 pad_line_1->set_outline_color (0xFF0000FF);
509 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
510 time_canvas_vbox.set_size_request (-1, -1);
512 ruler_label_event_box.add (ruler_label_vbox);
513 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
514 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
516 time_bars_event_box.add (time_bars_vbox);
517 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
518 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
520 time_canvas_event_box.add (time_canvas_vbox);
521 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
523 edit_packer.set_col_spacings (0);
524 edit_packer.set_row_spacings (0);
525 edit_packer.set_homogeneous (false);
526 edit_packer.set_border_width (0);
527 edit_packer.set_name ("EditorWindow");
529 /* labels for the rulers */
530 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
531 /* labels for the marker "tracks" (time bars) */
532 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
534 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
536 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
537 /* time bars canvas */
538 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
540 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
542 bottom_hbox.set_border_width (2);
543 bottom_hbox.set_spacing (3);
545 _route_groups = new EditorRouteGroups (this);
546 _routes = new EditorRoutes (this);
547 _regions = new EditorRegions (this);
548 _snapshots = new EditorSnapshots (this);
549 _locations = new EditorLocations (this);
551 add_notebook_page (_("Regions"), _regions->widget ());
552 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
553 add_notebook_page (_("Snapshots"), _snapshots->widget ());
554 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
555 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
557 _the_notebook.set_show_tabs (true);
558 _the_notebook.set_scrollable (true);
559 _the_notebook.popup_disable ();
560 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
561 _the_notebook.show_all ();
563 _notebook_shrunk = false;
565 editor_summary_pane.pack1(edit_packer);
567 Button* summary_arrows_left_left = manage (new Button);
568 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
569 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
570 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
572 Button* summary_arrows_left_right = manage (new Button);
573 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
574 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
575 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 VBox* summary_arrows_left = manage (new VBox);
578 summary_arrows_left->pack_start (*summary_arrows_left_left);
579 summary_arrows_left->pack_start (*summary_arrows_left_right);
581 Button* summary_arrows_right_up = manage (new Button);
582 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
583 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
584 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
586 Button* summary_arrows_right_down = manage (new Button);
587 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
588 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
589 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591 VBox* summary_arrows_right = manage (new VBox);
592 summary_arrows_right->pack_start (*summary_arrows_right_up);
593 summary_arrows_right->pack_start (*summary_arrows_right_down);
595 Frame* summary_frame = manage (new Frame);
596 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
598 summary_frame->add (*_summary);
599 summary_frame->show ();
601 _summary_hbox.pack_start (*summary_arrows_left, false, false);
602 _summary_hbox.pack_start (*summary_frame, true, true);
603 _summary_hbox.pack_start (*summary_arrows_right, false, false);
605 editor_summary_pane.pack2 (_summary_hbox);
607 edit_pane.pack1 (editor_summary_pane, true, true);
608 edit_pane.pack2 (_the_notebook, false, true);
610 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
612 /* XXX: editor_summary_pane might need similar to the edit_pane */
614 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
616 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
617 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
619 top_hbox.pack_start (toolbar_frame);
621 HBox *hbox = manage (new HBox);
622 hbox->pack_start (edit_pane, true, true);
624 global_vpacker.pack_start (top_hbox, false, false);
625 global_vpacker.pack_start (*hbox, true, true);
627 global_hpacker.pack_start (global_vpacker, true, true);
629 set_name ("EditorWindow");
630 add_accel_group (ActionManager::ui_manager->get_accel_group());
632 status_bar_hpacker.show ();
634 vpacker.pack_end (status_bar_hpacker, false, false);
635 vpacker.pack_end (global_hpacker, true, true);
637 /* register actions now so that set_state() can find them and set toggles/checks etc */
640 /* when we start using our own keybinding system for the editor, this
641 * will be uncommented
647 _snap_type = SnapToBeat;
648 set_snap_to (_snap_type);
649 _snap_mode = SnapOff;
650 set_snap_mode (_snap_mode);
651 set_mouse_mode (MouseObject, true);
652 pre_internal_mouse_mode = MouseObject;
653 pre_internal_snap_type = _snap_type;
654 pre_internal_snap_mode = _snap_mode;
655 internal_snap_type = _snap_type;
656 internal_snap_mode = _snap_mode;
657 set_edit_point_preference (EditAtMouse, true);
659 _playlist_selector = new PlaylistSelector();
660 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
662 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
666 nudge_forward_button.set_name ("zoom button");
667 nudge_forward_button.add_elements (ArdourButton::FlatFace);
668 nudge_forward_button.set_image(::get_icon("nudge_right"));
670 nudge_backward_button.set_name ("zoom button");
671 nudge_backward_button.add_elements (ArdourButton::FlatFace);
672 nudge_backward_button.set_image(::get_icon("nudge_left"));
674 fade_context_menu.set_name ("ArdourContextMenu");
676 /* icons, titles, WM stuff */
678 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
679 Glib::RefPtr<Gdk::Pixbuf> icon;
681 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
682 window_icons.push_back (icon);
684 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
685 window_icons.push_back (icon);
687 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
688 window_icons.push_back (icon);
690 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
691 window_icons.push_back (icon);
693 if (!window_icons.empty()) {
694 // set_icon_list (window_icons);
695 set_default_icon_list (window_icons);
698 WindowTitle title(Glib::get_application_name());
699 title += _("Editor");
700 set_title (title.get_string());
701 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
704 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
706 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
707 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
709 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
711 /* allow external control surfaces/protocols to do various things */
713 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
714 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
715 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
716 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
717 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
718 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
719 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
720 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
721 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
722 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
723 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
724 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
725 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
726 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
728 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
729 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
730 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
731 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
732 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
734 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
736 /* problematic: has to return a value and thus cannot be x-thread */
738 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
740 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
742 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
744 _ignore_region_action = false;
745 _last_region_menu_was_main = false;
746 _popup_region_menu_item = 0;
748 _show_marker_lines = false;
749 _over_region_trim_target = false;
751 /* Button bindings */
753 button_bindings = new Bindings;
755 XMLNode* node = button_settings();
757 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
758 button_bindings->load (**i);
765 setup_fade_images ();
771 if(image_socket_listener) {
772 if(image_socket_listener->is_connected())
774 image_socket_listener->close_connection() ;
777 delete image_socket_listener ;
778 image_socket_listener = 0 ;
782 delete button_bindings;
784 delete _route_groups;
785 delete _time_bars_canvas_viewport;
786 delete _track_canvas_viewport;
791 Editor::button_settings () const
793 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
794 XMLNode* node = find_named_node (*settings, X_("Buttons"));
797 node = new XMLNode (X_("Buttons"));
804 Editor::add_toplevel_controls (Container& cont)
806 vpacker.pack_start (cont, false, false);
811 Editor::get_smart_mode () const
813 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
817 Editor::catch_vanishing_regionview (RegionView *rv)
819 /* note: the selection will take care of the vanishing
820 audioregionview by itself.
823 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
827 if (clicked_regionview == rv) {
828 clicked_regionview = 0;
831 if (entered_regionview == rv) {
832 set_entered_regionview (0);
835 if (!_all_region_actions_sensitized) {
836 sensitize_all_region_actions (true);
839 _over_region_trim_target = false;
843 Editor::set_entered_regionview (RegionView* rv)
845 if (rv == entered_regionview) {
849 if (entered_regionview) {
850 entered_regionview->exited ();
853 if ((entered_regionview = rv) != 0) {
854 entered_regionview->entered (internal_editing ());
857 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
858 /* This RegionView entry might have changed what region actions
859 are allowed, so sensitize them all in case a key is pressed.
861 sensitize_all_region_actions (true);
866 Editor::set_entered_track (TimeAxisView* tav)
869 entered_track->exited ();
872 if ((entered_track = tav) != 0) {
873 entered_track->entered ();
878 Editor::show_window ()
880 if (!is_visible ()) {
883 /* XXX: this is a bit unfortunate; it would probably
884 be nicer if we could just call show () above rather
885 than needing the show_all ()
888 /* re-hide stuff if necessary */
889 editor_list_button_toggled ();
890 parameter_changed ("show-summary");
891 parameter_changed ("show-group-tabs");
892 parameter_changed ("show-zoom-tools");
894 /* now reset all audio_time_axis heights, because widgets might need
900 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
901 tv = (static_cast<TimeAxisView*>(*i));
905 if (current_mixer_strip) {
906 current_mixer_strip->hide_things ();
907 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
915 Editor::instant_save ()
917 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
922 _session->add_instant_xml(get_state());
924 Config->add_instant_xml(get_state());
929 Editor::zoom_adjustment_changed ()
935 double fpu = zoom_range_clock->current_duration() / _visible_canvas_width;
936 bool clamped = clamp_samples_per_pixel (fpu);
939 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
946 Editor::control_vertical_zoom_in_all ()
948 tav_zoom_smooth (false, true);
952 Editor::control_vertical_zoom_out_all ()
954 tav_zoom_smooth (true, true);
958 Editor::control_vertical_zoom_in_selected ()
960 tav_zoom_smooth (false, false);
964 Editor::control_vertical_zoom_out_selected ()
966 tav_zoom_smooth (true, false);
970 Editor::control_view (uint32_t view)
972 goto_visual_state (view);
976 Editor::control_unselect ()
978 selection->clear_tracks ();
982 Editor::control_select (uint32_t rid, Selection::Operation op)
984 /* handles the (static) signal from the ControlProtocol class that
985 * requests setting the selected track to a given RID
992 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
998 TimeAxisView* tav = axis_view_from_route (r);
1002 case Selection::Add:
1003 selection->add (tav);
1005 case Selection::Toggle:
1006 selection->toggle (tav);
1008 case Selection::Extend:
1010 case Selection::Set:
1011 selection->set (tav);
1015 selection->clear_tracks ();
1020 Editor::control_step_tracks_up ()
1022 scroll_tracks_up_line ();
1026 Editor::control_step_tracks_down ()
1028 scroll_tracks_down_line ();
1032 Editor::control_scroll (float fraction)
1034 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1040 double step = fraction * current_page_samples();
1043 _control_scroll_target is an optional<T>
1045 it acts like a pointer to an framepos_t, with
1046 a operator conversion to boolean to check
1047 that it has a value could possibly use
1048 playhead_cursor->current_frame to store the
1049 value and a boolean in the class to know
1050 when it's out of date
1053 if (!_control_scroll_target) {
1054 _control_scroll_target = _session->transport_frame();
1055 _dragging_playhead = true;
1058 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1059 *_control_scroll_target = 0;
1060 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1061 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1063 *_control_scroll_target += (framepos_t) floor (step);
1066 /* move visuals, we'll catch up with it later */
1068 playhead_cursor->set_position (*_control_scroll_target);
1069 UpdateAllTransportClocks (*_control_scroll_target);
1071 if (*_control_scroll_target > (current_page_samples() / 2)) {
1072 /* try to center PH in window */
1073 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1079 Now we do a timeout to actually bring the session to the right place
1080 according to the playhead. This is to avoid reading disk buffers on every
1081 call to control_scroll, which is driven by ScrollTimeline and therefore
1082 probably by a control surface wheel which can generate lots of events.
1084 /* cancel the existing timeout */
1086 control_scroll_connection.disconnect ();
1088 /* add the next timeout */
1090 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1094 Editor::deferred_control_scroll (framepos_t /*target*/)
1096 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1097 // reset for next stream
1098 _control_scroll_target = boost::none;
1099 _dragging_playhead = false;
1104 Editor::access_action (std::string action_group, std::string action_item)
1110 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1113 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1121 Editor::on_realize ()
1123 Window::on_realize ();
1128 Editor::map_position_change (framepos_t frame)
1130 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1132 if (_session == 0) {
1136 if (_follow_playhead) {
1137 center_screen (frame);
1140 playhead_cursor->set_position (frame);
1144 Editor::center_screen (framepos_t frame)
1146 double const page = _visible_canvas_width * samples_per_pixel;
1148 /* if we're off the page, then scroll.
1151 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1152 center_screen_internal (frame, page);
1157 Editor::center_screen_internal (framepos_t frame, float page)
1162 frame -= (framepos_t) page;
1167 reset_x_origin (frame);
1172 Editor::update_title ()
1174 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1177 bool dirty = _session->dirty();
1179 string session_name;
1181 if (_session->snap_name() != _session->name()) {
1182 session_name = _session->snap_name();
1184 session_name = _session->name();
1188 session_name = "*" + session_name;
1191 WindowTitle title(session_name);
1192 title += Glib::get_application_name();
1193 set_title (title.get_string());
1195 /* ::session_going_away() will have taken care of it */
1200 Editor::set_session (Session *t)
1202 SessionHandlePtr::set_session (t);
1208 zoom_range_clock->set_session (_session);
1209 _playlist_selector->set_session (_session);
1210 nudge_clock->set_session (_session);
1211 _summary->set_session (_session);
1212 _group_tabs->set_session (_session);
1213 _route_groups->set_session (_session);
1214 _regions->set_session (_session);
1215 _snapshots->set_session (_session);
1216 _routes->set_session (_session);
1217 _locations->set_session (_session);
1219 if (rhythm_ferret) {
1220 rhythm_ferret->set_session (_session);
1223 if (analysis_window) {
1224 analysis_window->set_session (_session);
1228 sfbrowser->set_session (_session);
1231 compute_fixed_ruler_scale ();
1233 /* Make sure we have auto loop and auto punch ranges */
1235 Location* loc = _session->locations()->auto_loop_location();
1237 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1239 if (loc->start() == loc->end()) {
1240 loc->set_end (loc->start() + 1);
1243 _session->locations()->add (loc, false);
1244 _session->set_auto_loop_location (loc);
1247 loc->set_name (_("Loop"));
1250 loc = _session->locations()->auto_punch_location();
1253 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1255 if (loc->start() == loc->end()) {
1256 loc->set_end (loc->start() + 1);
1259 _session->locations()->add (loc, false);
1260 _session->set_auto_punch_location (loc);
1263 loc->set_name (_("Punch"));
1266 refresh_location_display ();
1268 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1269 the selected Marker; this needs the LocationMarker list to be available.
1271 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1272 set_state (*node, Stateful::loading_state_version);
1274 /* catch up with the playhead */
1276 _session->request_locate (playhead_cursor->current_frame ());
1277 _pending_initial_locate = true;
1281 /* These signals can all be emitted by a non-GUI thread. Therefore the
1282 handlers for them must not attempt to directly interact with the GUI,
1283 but use Gtkmm2ext::UI::instance()->call_slot();
1286 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1287 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1288 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1289 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1290 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1291 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1292 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1293 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1294 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1295 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1296 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1297 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1298 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1299 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1301 playhead_cursor->show ();
1303 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1304 Config->map_parameters (pc);
1305 _session->config.map_parameters (pc);
1307 restore_ruler_visibility ();
1308 //tempo_map_changed (PropertyChange (0));
1309 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1311 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1312 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1315 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1316 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1319 switch (_snap_type) {
1320 case SnapToRegionStart:
1321 case SnapToRegionEnd:
1322 case SnapToRegionSync:
1323 case SnapToRegionBoundary:
1324 build_region_boundary_cache ();
1331 /* register for undo history */
1332 _session->register_with_memento_command_factory(id(), this);
1334 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1336 start_updating_meters ();
1340 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1342 if (a->get_name() == "RegionMenu") {
1343 /* When the main menu's region menu is opened, we setup the actions so that they look right
1344 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1345 so we resensitize all region actions when the entered regionview or the region selection
1346 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1347 happens after the region context menu is opened. So we set a flag here, too.
1351 sensitize_the_right_region_actions ();
1352 _last_region_menu_was_main = true;
1357 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1359 using namespace Menu_Helpers;
1361 void (Editor::*emf)(FadeShape);
1362 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1365 images = &_xfade_in_images;
1366 emf = &Editor::set_fade_in_shape;
1368 images = &_xfade_out_images;
1369 emf = &Editor::set_fade_out_shape;
1374 _("Linear (for highly correlated material)"),
1375 *(*images)[FadeLinear],
1376 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1380 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1384 _("Constant power"),
1385 *(*images)[FadeConstantPower],
1386 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1389 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1394 *(*images)[FadeSymmetric],
1395 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1399 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1404 *(*images)[FadeSlow],
1405 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1408 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1413 *(*images)[FadeFast],
1414 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1417 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1420 /** Pop up a context menu for when the user clicks on a start crossfade */
1422 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1424 using namespace Menu_Helpers;
1426 MenuList& items (xfade_in_context_menu.items());
1428 if (items.empty()) {
1429 fill_xfade_menu (items, true);
1432 xfade_in_context_menu.popup (button, time);
1435 /** Pop up a context menu for when the user clicks on an end crossfade */
1437 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1439 using namespace Menu_Helpers;
1441 MenuList& items (xfade_out_context_menu.items());
1443 if (items.empty()) {
1444 fill_xfade_menu (items, false);
1447 xfade_out_context_menu.popup (button, time);
1451 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1453 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1455 using namespace Menu_Helpers;
1456 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1459 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1463 MenuList& items (fade_context_menu.items());
1466 switch (item_type) {
1468 case FadeInHandleItem:
1469 if (arv->audio_region()->fade_in_active()) {
1470 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1472 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1475 items.push_back (SeparatorElem());
1477 if (Profile->get_sae()) {
1479 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1480 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1487 *_fade_in_images[FadeLinear],
1488 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *_fade_in_images[FadeSlow],
1498 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1501 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1506 *_fade_in_images[FadeFast],
1507 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1510 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1515 *_fade_in_images[FadeSymmetric],
1516 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1521 _("Constant power"),
1522 *_fade_in_images[FadeConstantPower],
1523 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1526 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1532 case FadeOutHandleItem:
1533 if (arv->audio_region()->fade_out_active()) {
1534 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1536 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1539 items.push_back (SeparatorElem());
1541 if (Profile->get_sae()) {
1542 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1543 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1549 *_fade_out_images[FadeLinear],
1550 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1554 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1559 *_fade_out_images[FadeSlow],
1560 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1563 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1568 *_fade_out_images[FadeFast],
1569 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1572 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1577 *_fade_out_images[FadeSymmetric],
1578 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1583 _("Constant power"),
1584 *_fade_out_images[FadeConstantPower],
1585 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1588 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1594 fatal << _("programming error: ")
1595 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1600 fade_context_menu.popup (button, time);
1604 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1606 using namespace Menu_Helpers;
1607 Menu* (Editor::*build_menu_function)();
1610 switch (item_type) {
1612 case RegionViewName:
1613 case RegionViewNameHighlight:
1614 case LeftFrameHandle:
1615 case RightFrameHandle:
1616 if (with_selection) {
1617 build_menu_function = &Editor::build_track_selection_context_menu;
1619 build_menu_function = &Editor::build_track_region_context_menu;
1624 if (with_selection) {
1625 build_menu_function = &Editor::build_track_selection_context_menu;
1627 build_menu_function = &Editor::build_track_context_menu;
1632 if (clicked_routeview->track()) {
1633 build_menu_function = &Editor::build_track_context_menu;
1635 build_menu_function = &Editor::build_track_bus_context_menu;
1640 /* probably shouldn't happen but if it does, we don't care */
1644 menu = (this->*build_menu_function)();
1645 menu->set_name ("ArdourContextMenu");
1647 /* now handle specific situations */
1649 switch (item_type) {
1651 case RegionViewName:
1652 case RegionViewNameHighlight:
1653 case LeftFrameHandle:
1654 case RightFrameHandle:
1655 if (!with_selection) {
1656 if (region_edit_menu_split_item) {
1657 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1658 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1660 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1663 if (region_edit_menu_split_multichannel_item) {
1664 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1665 region_edit_menu_split_multichannel_item->set_sensitive (true);
1667 region_edit_menu_split_multichannel_item->set_sensitive (false);
1680 /* probably shouldn't happen but if it does, we don't care */
1684 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1686 /* Bounce to disk */
1688 using namespace Menu_Helpers;
1689 MenuList& edit_items = menu->items();
1691 edit_items.push_back (SeparatorElem());
1693 switch (clicked_routeview->audio_track()->freeze_state()) {
1694 case AudioTrack::NoFreeze:
1695 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1698 case AudioTrack::Frozen:
1699 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1702 case AudioTrack::UnFrozen:
1703 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1709 if (item_type == StreamItem && clicked_routeview) {
1710 clicked_routeview->build_underlay_menu(menu);
1713 /* When the region menu is opened, we setup the actions so that they look right
1716 sensitize_the_right_region_actions ();
1717 _last_region_menu_was_main = false;
1719 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1720 menu->popup (button, time);
1724 Editor::build_track_context_menu ()
1726 using namespace Menu_Helpers;
1728 MenuList& edit_items = track_context_menu.items();
1731 add_dstream_context_items (edit_items);
1732 return &track_context_menu;
1736 Editor::build_track_bus_context_menu ()
1738 using namespace Menu_Helpers;
1740 MenuList& edit_items = track_context_menu.items();
1743 add_bus_context_items (edit_items);
1744 return &track_context_menu;
1748 Editor::build_track_region_context_menu ()
1750 using namespace Menu_Helpers;
1751 MenuList& edit_items = track_region_context_menu.items();
1754 /* we've just cleared the track region context menu, so the menu that these
1755 two items were on will have disappeared; stop them dangling.
1757 region_edit_menu_split_item = 0;
1758 region_edit_menu_split_multichannel_item = 0;
1760 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1763 boost::shared_ptr<Track> tr;
1764 boost::shared_ptr<Playlist> pl;
1766 if ((tr = rtv->track())) {
1767 add_region_context_items (edit_items, tr);
1771 add_dstream_context_items (edit_items);
1773 return &track_region_context_menu;
1777 Editor::analyze_region_selection ()
1779 if (analysis_window == 0) {
1780 analysis_window = new AnalysisWindow();
1783 analysis_window->set_session(_session);
1785 analysis_window->show_all();
1788 analysis_window->set_regionmode();
1789 analysis_window->analyze();
1791 analysis_window->present();
1795 Editor::analyze_range_selection()
1797 if (analysis_window == 0) {
1798 analysis_window = new AnalysisWindow();
1801 analysis_window->set_session(_session);
1803 analysis_window->show_all();
1806 analysis_window->set_rangemode();
1807 analysis_window->analyze();
1809 analysis_window->present();
1813 Editor::build_track_selection_context_menu ()
1815 using namespace Menu_Helpers;
1816 MenuList& edit_items = track_selection_context_menu.items();
1817 edit_items.clear ();
1819 add_selection_context_items (edit_items);
1820 // edit_items.push_back (SeparatorElem());
1821 // add_dstream_context_items (edit_items);
1823 return &track_selection_context_menu;
1827 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1829 using namespace Menu_Helpers;
1831 /* OK, stick the region submenu at the top of the list, and then add
1835 RegionSelection rs = get_regions_from_selection_and_entered ();
1837 string::size_type pos = 0;
1838 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1840 /* we have to hack up the region name because "_" has a special
1841 meaning for menu titles.
1844 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1845 menu_item_name.replace (pos, 1, "__");
1849 if (_popup_region_menu_item == 0) {
1850 _popup_region_menu_item = new MenuItem (menu_item_name);
1851 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1852 _popup_region_menu_item->show ();
1854 _popup_region_menu_item->set_label (menu_item_name);
1857 const framepos_t position = get_preferred_edit_position (false, true);
1859 edit_items.push_back (*_popup_region_menu_item);
1860 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1861 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1863 edit_items.push_back (SeparatorElem());
1866 /** Add context menu items relevant to selection ranges.
1867 * @param edit_items List to add the items to.
1870 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1872 using namespace Menu_Helpers;
1874 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1875 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1877 edit_items.push_back (SeparatorElem());
1878 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1880 edit_items.push_back (SeparatorElem());
1882 edit_items.push_back (
1884 _("Move Range Start to Previous Region Boundary"),
1885 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1889 edit_items.push_back (
1891 _("Move Range Start to Next Region Boundary"),
1892 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1896 edit_items.push_back (
1898 _("Move Range End to Previous Region Boundary"),
1899 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1903 edit_items.push_back (
1905 _("Move Range End to Next Region Boundary"),
1906 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1910 edit_items.push_back (SeparatorElem());
1911 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1912 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1914 edit_items.push_back (SeparatorElem());
1915 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1917 edit_items.push_back (SeparatorElem());
1918 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1919 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1921 edit_items.push_back (SeparatorElem());
1922 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1924 edit_items.push_back (SeparatorElem());
1925 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1926 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1927 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1929 edit_items.push_back (SeparatorElem());
1930 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1931 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1932 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1933 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1934 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1939 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1941 using namespace Menu_Helpers;
1945 Menu *play_menu = manage (new Menu);
1946 MenuList& play_items = play_menu->items();
1947 play_menu->set_name ("ArdourContextMenu");
1949 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1950 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1951 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1952 play_items.push_back (SeparatorElem());
1953 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1955 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1959 Menu *select_menu = manage (new Menu);
1960 MenuList& select_items = select_menu->items();
1961 select_menu->set_name ("ArdourContextMenu");
1963 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1964 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1965 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1966 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1967 select_items.push_back (SeparatorElem());
1968 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1969 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1970 select_items.push_back (SeparatorElem());
1971 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1972 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1973 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1974 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1975 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1976 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1977 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1979 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1983 Menu *cutnpaste_menu = manage (new Menu);
1984 MenuList& cutnpaste_items = cutnpaste_menu->items();
1985 cutnpaste_menu->set_name ("ArdourContextMenu");
1987 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1988 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1989 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1991 cutnpaste_items.push_back (SeparatorElem());
1993 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1994 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1996 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1998 /* Adding new material */
2000 edit_items.push_back (SeparatorElem());
2001 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2002 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2006 Menu *nudge_menu = manage (new Menu());
2007 MenuList& nudge_items = nudge_menu->items();
2008 nudge_menu->set_name ("ArdourContextMenu");
2010 edit_items.push_back (SeparatorElem());
2011 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2012 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2013 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2014 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2016 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2020 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2022 using namespace Menu_Helpers;
2026 Menu *play_menu = manage (new Menu);
2027 MenuList& play_items = play_menu->items();
2028 play_menu->set_name ("ArdourContextMenu");
2030 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2031 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2032 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2036 Menu *select_menu = manage (new Menu);
2037 MenuList& select_items = select_menu->items();
2038 select_menu->set_name ("ArdourContextMenu");
2040 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2041 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2042 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2043 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2044 select_items.push_back (SeparatorElem());
2045 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2046 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2047 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2048 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2050 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2054 Menu *cutnpaste_menu = manage (new Menu);
2055 MenuList& cutnpaste_items = cutnpaste_menu->items();
2056 cutnpaste_menu->set_name ("ArdourContextMenu");
2058 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2059 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2060 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2062 Menu *nudge_menu = manage (new Menu());
2063 MenuList& nudge_items = nudge_menu->items();
2064 nudge_menu->set_name ("ArdourContextMenu");
2066 edit_items.push_back (SeparatorElem());
2067 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2068 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2069 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2070 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2072 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2076 Editor::snap_type() const
2082 Editor::snap_mode() const
2088 Editor::set_snap_to (SnapType st)
2090 unsigned int snap_ind = (unsigned int)st;
2094 if (snap_ind > snap_type_strings.size() - 1) {
2096 _snap_type = (SnapType)snap_ind;
2099 string str = snap_type_strings[snap_ind];
2101 if (str != snap_type_selector.get_active_text()) {
2102 snap_type_selector.set_active_text (str);
2107 switch (_snap_type) {
2108 case SnapToBeatDiv128:
2109 case SnapToBeatDiv64:
2110 case SnapToBeatDiv32:
2111 case SnapToBeatDiv28:
2112 case SnapToBeatDiv24:
2113 case SnapToBeatDiv20:
2114 case SnapToBeatDiv16:
2115 case SnapToBeatDiv14:
2116 case SnapToBeatDiv12:
2117 case SnapToBeatDiv10:
2118 case SnapToBeatDiv8:
2119 case SnapToBeatDiv7:
2120 case SnapToBeatDiv6:
2121 case SnapToBeatDiv5:
2122 case SnapToBeatDiv4:
2123 case SnapToBeatDiv3:
2124 case SnapToBeatDiv2: {
2125 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2126 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2128 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2129 current_bbt_points_begin, current_bbt_points_end);
2130 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2131 current_bbt_points_begin, current_bbt_points_end);
2132 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2136 case SnapToRegionStart:
2137 case SnapToRegionEnd:
2138 case SnapToRegionSync:
2139 case SnapToRegionBoundary:
2140 build_region_boundary_cache ();
2148 SnapChanged (); /* EMIT SIGNAL */
2152 Editor::set_snap_mode (SnapMode mode)
2154 string str = snap_mode_strings[(int)mode];
2156 if (_internal_editing) {
2157 internal_snap_mode = mode;
2159 pre_internal_snap_mode = mode;
2164 if (str != snap_mode_selector.get_active_text ()) {
2165 snap_mode_selector.set_active_text (str);
2171 Editor::set_edit_point_preference (EditPoint ep, bool force)
2173 bool changed = (_edit_point != ep);
2176 string str = edit_point_strings[(int)ep];
2178 if (str != edit_point_selector.get_active_text ()) {
2179 edit_point_selector.set_active_text (str);
2182 set_canvas_cursor ();
2184 if (!force && !changed) {
2188 const char* action=NULL;
2190 switch (_edit_point) {
2191 case EditAtPlayhead:
2192 action = "edit-at-playhead";
2194 case EditAtSelectedMarker:
2195 action = "edit-at-marker";
2198 action = "edit-at-mouse";
2202 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2204 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2208 bool in_track_canvas;
2210 if (!mouse_frame (foo, in_track_canvas)) {
2211 in_track_canvas = false;
2214 reset_canvas_action_sensitivity (in_track_canvas);
2220 Editor::set_state (const XMLNode& node, int /*version*/)
2222 const XMLProperty* prop;
2229 g.base_width = default_width;
2230 g.base_height = default_height;
2234 if ((geometry = find_named_node (node, "geometry")) != 0) {
2238 if ((prop = geometry->property("x_size")) == 0) {
2239 prop = geometry->property ("x-size");
2242 g.base_width = atoi(prop->value());
2244 if ((prop = geometry->property("y_size")) == 0) {
2245 prop = geometry->property ("y-size");
2248 g.base_height = atoi(prop->value());
2251 if ((prop = geometry->property ("x_pos")) == 0) {
2252 prop = geometry->property ("x-pos");
2255 x = atoi (prop->value());
2258 if ((prop = geometry->property ("y_pos")) == 0) {
2259 prop = geometry->property ("y-pos");
2262 y = atoi (prop->value());
2266 set_default_size (g.base_width, g.base_height);
2269 if (_session && (prop = node.property ("playhead"))) {
2271 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2272 playhead_cursor->set_position (pos);
2274 playhead_cursor->set_position (0);
2277 if ((prop = node.property ("mixer-width"))) {
2278 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2281 if ((prop = node.property ("zoom-focus"))) {
2282 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2285 if ((prop = node.property ("zoom"))) {
2286 reset_zoom (PBD::atof (prop->value()));
2288 reset_zoom (samples_per_pixel);
2291 if ((prop = node.property ("snap-to"))) {
2292 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2295 if ((prop = node.property ("snap-mode"))) {
2296 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2299 if ((prop = node.property ("internal-snap-to"))) {
2300 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2303 if ((prop = node.property ("internal-snap-mode"))) {
2304 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2307 if ((prop = node.property ("pre-internal-snap-to"))) {
2308 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2312 if ((prop = node.property ("pre-internal-snap-mode"))) {
2313 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2316 if ((prop = node.property ("mouse-mode"))) {
2317 MouseMode m = str2mousemode(prop->value());
2318 set_mouse_mode (m, true);
2320 set_mouse_mode (MouseObject, true);
2323 if ((prop = node.property ("left-frame")) != 0) {
2325 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2329 reset_x_origin (pos);
2333 if ((prop = node.property ("y-origin")) != 0) {
2334 reset_y_origin (atof (prop->value ()));
2337 if ((prop = node.property ("internal-edit"))) {
2338 bool yn = string_is_affirmative (prop->value());
2339 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2341 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2342 tact->set_active (!yn);
2343 tact->set_active (yn);
2347 if ((prop = node.property ("join-object-range"))) {
2348 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2349 bool yn = string_is_affirmative (prop->value());
2351 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2352 tact->set_active (!yn);
2353 tact->set_active (yn);
2355 set_mouse_mode(mouse_mode, true);
2358 if ((prop = node.property ("edit-point"))) {
2359 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2362 if ((prop = node.property ("show-measures"))) {
2363 bool yn = string_is_affirmative (prop->value());
2364 _show_measures = yn;
2365 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2367 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2368 /* do it twice to force the change */
2369 tact->set_active (!yn);
2370 tact->set_active (yn);
2374 if ((prop = node.property ("follow-playhead"))) {
2375 bool yn = string_is_affirmative (prop->value());
2376 set_follow_playhead (yn);
2377 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2379 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2380 if (tact->get_active() != yn) {
2381 tact->set_active (yn);
2386 if ((prop = node.property ("stationary-playhead"))) {
2387 bool yn = string_is_affirmative (prop->value());
2388 set_stationary_playhead (yn);
2389 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2391 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2392 if (tact->get_active() != yn) {
2393 tact->set_active (yn);
2398 if ((prop = node.property ("region-list-sort-type"))) {
2399 RegionListSortType st;
2400 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2403 if ((prop = node.property ("show-editor-mixer"))) {
2405 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2408 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2409 bool yn = string_is_affirmative (prop->value());
2411 /* do it twice to force the change */
2413 tact->set_active (!yn);
2414 tact->set_active (yn);
2417 if ((prop = node.property ("show-editor-list"))) {
2419 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2422 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2423 bool yn = string_is_affirmative (prop->value());
2425 /* do it twice to force the change */
2427 tact->set_active (!yn);
2428 tact->set_active (yn);
2431 if ((prop = node.property (X_("editor-list-page")))) {
2432 _the_notebook.set_current_page (atoi (prop->value ()));
2435 if ((prop = node.property (X_("show-marker-lines")))) {
2436 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2438 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2439 bool yn = string_is_affirmative (prop->value ());
2441 tact->set_active (!yn);
2442 tact->set_active (yn);
2445 XMLNodeList children = node.children ();
2446 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2447 selection->set_state (**i, Stateful::current_state_version);
2448 _regions->set_state (**i);
2451 if ((prop = node.property ("maximised"))) {
2452 bool yn = string_is_affirmative (prop->value());
2454 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2458 if ((prop = node.property ("nudge-clock-value"))) {
2460 sscanf (prop->value().c_str(), "%" PRId64, &f);
2461 nudge_clock->set (f);
2463 nudge_clock->set_mode (AudioClock::Timecode);
2464 nudge_clock->set (_session->frame_rate() * 5, true);
2471 Editor::get_state ()
2473 XMLNode* node = new XMLNode ("Editor");
2476 id().print (buf, sizeof (buf));
2477 node->add_property ("id", buf);
2479 if (is_realized()) {
2480 Glib::RefPtr<Gdk::Window> win = get_window();
2482 int x, y, width, height;
2483 win->get_root_origin(x, y);
2484 win->get_size(width, height);
2486 XMLNode* geometry = new XMLNode ("geometry");
2488 snprintf(buf, sizeof(buf), "%d", width);
2489 geometry->add_property("x-size", string(buf));
2490 snprintf(buf, sizeof(buf), "%d", height);
2491 geometry->add_property("y-size", string(buf));
2492 snprintf(buf, sizeof(buf), "%d", x);
2493 geometry->add_property("x-pos", string(buf));
2494 snprintf(buf, sizeof(buf), "%d", y);
2495 geometry->add_property("y-pos", string(buf));
2496 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2497 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2498 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2499 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2500 geometry->add_property("edit-vertical-pane-pos", string(buf));
2502 node->add_child_nocopy (*geometry);
2505 maybe_add_mixer_strip_width (*node);
2507 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2508 snprintf (buf, sizeof(buf), "%f", samples_per_pixel);
2509 node->add_property ("zoom", buf);
2510 node->add_property ("snap-to", enum_2_string (_snap_type));
2511 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2512 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2513 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2514 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2515 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2516 node->add_property ("edit-point", enum_2_string (_edit_point));
2518 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2519 node->add_property ("playhead", buf);
2520 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2521 node->add_property ("left-frame", buf);
2522 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2523 node->add_property ("y-origin", buf);
2525 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2526 node->add_property ("maximised", _maximised ? "yes" : "no");
2527 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2528 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2529 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2530 node->add_property ("mouse-mode", enum2str(mouse_mode));
2531 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2532 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2534 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2536 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2537 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2540 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2542 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2543 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2546 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2547 node->add_property (X_("editor-list-page"), buf);
2549 if (button_bindings) {
2550 XMLNode* bb = new XMLNode (X_("Buttons"));
2551 button_bindings->save (*bb);
2552 node->add_child_nocopy (*bb);
2555 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2557 node->add_child_nocopy (selection->get_state ());
2558 node->add_child_nocopy (_regions->get_state ());
2560 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2561 node->add_property ("nudge-clock-value", buf);
2568 /** @param y y offset from the top of all trackviews.
2569 * @return pair: TimeAxisView that y is over, layer index.
2570 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2571 * in stacked or expanded region display mode, otherwise 0.
2573 std::pair<TimeAxisView *, double>
2574 Editor::trackview_by_y_position (double y)
2576 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2578 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2584 return std::make_pair ( (TimeAxisView *) 0, 0);
2587 /** Snap a position to the grid, if appropriate, taking into account current
2588 * grid settings and also the state of any snap modifier keys that may be pressed.
2589 * @param start Position to snap.
2590 * @param event Event to get current key modifier information from, or 0.
2593 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2595 if (!_session || !event) {
2599 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2600 if (_snap_mode == SnapOff) {
2601 snap_to_internal (start, direction, for_mark);
2604 if (_snap_mode != SnapOff) {
2605 snap_to_internal (start, direction, for_mark);
2611 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2613 if (!_session || _snap_mode == SnapOff) {
2617 snap_to_internal (start, direction, for_mark);
2621 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2623 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2624 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2626 switch (_snap_type) {
2627 case SnapToTimecodeFrame:
2628 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2629 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2631 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2635 case SnapToTimecodeSeconds:
2636 if (_session->config.get_timecode_offset_negative()) {
2637 start += _session->config.get_timecode_offset ();
2639 start -= _session->config.get_timecode_offset ();
2641 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2642 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2644 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2647 if (_session->config.get_timecode_offset_negative()) {
2648 start -= _session->config.get_timecode_offset ();
2650 start += _session->config.get_timecode_offset ();
2654 case SnapToTimecodeMinutes:
2655 if (_session->config.get_timecode_offset_negative()) {
2656 start += _session->config.get_timecode_offset ();
2658 start -= _session->config.get_timecode_offset ();
2660 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2661 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2663 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2665 if (_session->config.get_timecode_offset_negative()) {
2666 start -= _session->config.get_timecode_offset ();
2668 start += _session->config.get_timecode_offset ();
2672 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2678 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2680 const framepos_t one_second = _session->frame_rate();
2681 const framepos_t one_minute = _session->frame_rate() * 60;
2682 framepos_t presnap = start;
2686 switch (_snap_type) {
2687 case SnapToTimecodeFrame:
2688 case SnapToTimecodeSeconds:
2689 case SnapToTimecodeMinutes:
2690 return timecode_snap_to_internal (start, direction, for_mark);
2693 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2694 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2696 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2701 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2702 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2704 start = (framepos_t) floor ((double) start / one_second) * one_second;
2709 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2710 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2712 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2717 start = _session->tempo_map().round_to_bar (start, direction);
2721 start = _session->tempo_map().round_to_beat (start, direction);
2724 case SnapToBeatDiv128:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2727 case SnapToBeatDiv64:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2730 case SnapToBeatDiv32:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2733 case SnapToBeatDiv28:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2736 case SnapToBeatDiv24:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2739 case SnapToBeatDiv20:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2742 case SnapToBeatDiv16:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2745 case SnapToBeatDiv14:
2746 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2748 case SnapToBeatDiv12:
2749 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2751 case SnapToBeatDiv10:
2752 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2754 case SnapToBeatDiv8:
2755 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2757 case SnapToBeatDiv7:
2758 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2760 case SnapToBeatDiv6:
2761 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2763 case SnapToBeatDiv5:
2764 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2766 case SnapToBeatDiv4:
2767 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2769 case SnapToBeatDiv3:
2770 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2772 case SnapToBeatDiv2:
2773 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2781 _session->locations()->marks_either_side (start, before, after);
2783 if (before == max_framepos && after == max_framepos) {
2784 /* No marks to snap to, so just don't snap */
2786 } else if (before == max_framepos) {
2788 } else if (after == max_framepos) {
2790 } else if (before != max_framepos && after != max_framepos) {
2791 /* have before and after */
2792 if ((start - before) < (after - start)) {
2801 case SnapToRegionStart:
2802 case SnapToRegionEnd:
2803 case SnapToRegionSync:
2804 case SnapToRegionBoundary:
2805 if (!region_boundary_cache.empty()) {
2807 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2808 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2810 if (direction > 0) {
2811 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2813 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2816 if (next != region_boundary_cache.begin ()) {
2821 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2822 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2824 if (start > (p + n) / 2) {
2833 switch (_snap_mode) {
2839 if (presnap > start) {
2840 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2844 } else if (presnap < start) {
2845 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2851 /* handled at entry */
2859 Editor::setup_toolbar ()
2861 HBox* mode_box = manage(new HBox);
2862 mode_box->set_border_width (2);
2863 mode_box->set_spacing(4);
2865 HBox* mouse_mode_box = manage (new HBox);
2866 HBox* mouse_mode_hbox = manage (new HBox);
2867 VBox* mouse_mode_vbox = manage (new VBox);
2868 Alignment* mouse_mode_align = manage (new Alignment);
2870 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2871 // mouse_mode_size_group->add_widget (smart_mode_button);
2872 mouse_mode_size_group->add_widget (mouse_move_button);
2873 mouse_mode_size_group->add_widget (mouse_select_button);
2874 mouse_mode_size_group->add_widget (mouse_zoom_button);
2875 mouse_mode_size_group->add_widget (mouse_gain_button);
2876 mouse_mode_size_group->add_widget (mouse_timefx_button);
2877 mouse_mode_size_group->add_widget (mouse_audition_button);
2878 mouse_mode_size_group->add_widget (mouse_draw_button);
2879 mouse_mode_size_group->add_widget (internal_edit_button);
2881 /* make them just a bit bigger */
2882 mouse_move_button.set_size_request (-1, 30);
2884 mouse_mode_hbox->set_spacing (2);
2886 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2887 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2890 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2891 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2893 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2894 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2896 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2898 mouse_mode_align->add (*mouse_mode_vbox);
2899 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2901 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2903 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2904 if (!Profile->get_sae()) {
2905 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2907 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2909 edit_mode_selector.set_name ("EditModeSelector");
2910 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2911 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2913 mode_box->pack_start (edit_mode_selector, false, false);
2914 mode_box->pack_start (*mouse_mode_box, false, false);
2916 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2917 _mouse_mode_tearoff->set_name ("MouseModeBase");
2918 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2920 if (Profile->get_sae()) {
2921 _mouse_mode_tearoff->set_can_be_torn_off (false);
2924 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_mouse_mode_tearoff->tearoff_window()));
2926 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_mouse_mode_tearoff->tearoff_window(), 1));
2928 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_mouse_mode_tearoff->tearoff_window()));
2930 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_mouse_mode_tearoff->tearoff_window(), 1));
2935 _zoom_box.set_spacing (2);
2936 _zoom_box.set_border_width (2);
2940 zoom_in_button.set_name ("zoom button");
2941 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2942 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2943 zoom_in_button.set_image(::get_icon ("zoom_in"));
2944 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2945 zoom_in_button.set_related_action (act);
2947 zoom_out_button.set_name ("zoom button");
2948 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2949 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2950 zoom_out_button.set_image(::get_icon ("zoom_out"));
2951 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2952 zoom_out_button.set_related_action (act);
2954 zoom_out_full_button.set_name ("zoom button");
2955 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2956 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2957 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2958 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2959 zoom_out_full_button.set_related_action (act);
2961 zoom_focus_selector.set_name ("ZoomFocusSelector");
2962 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2963 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2965 _zoom_box.pack_start (zoom_out_button, false, false);
2966 _zoom_box.pack_start (zoom_in_button, false, false);
2967 _zoom_box.pack_start (zoom_out_full_button, false, false);
2969 _zoom_box.pack_start (zoom_focus_selector, false, false);
2971 /* Track zoom buttons */
2972 tav_expand_button.set_name ("zoom button");
2973 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2974 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2975 tav_expand_button.set_size_request (-1, 20);
2976 tav_expand_button.set_image(::get_icon ("tav_exp"));
2977 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2978 tav_expand_button.set_related_action (act);
2980 tav_shrink_button.set_name ("zoom button");
2981 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2982 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2983 tav_shrink_button.set_size_request (-1, 20);
2984 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2985 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2986 tav_shrink_button.set_related_action (act);
2988 _zoom_box.pack_start (tav_shrink_button);
2989 _zoom_box.pack_start (tav_expand_button);
2991 _zoom_tearoff = manage (new TearOff (_zoom_box));
2993 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2994 &_zoom_tearoff->tearoff_window()));
2995 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2996 &_zoom_tearoff->tearoff_window(), 0));
2997 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2998 &_zoom_tearoff->tearoff_window()));
2999 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3000 &_zoom_tearoff->tearoff_window(), 0));
3002 snap_box.set_spacing (2);
3003 snap_box.set_border_width (2);
3005 snap_type_selector.set_name ("SnapTypeSelector");
3006 set_popdown_strings (snap_type_selector, snap_type_strings);
3007 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3009 snap_mode_selector.set_name ("SnapModeSelector");
3010 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3011 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3013 edit_point_selector.set_name ("EditPointSelector");
3014 set_popdown_strings (edit_point_selector, edit_point_strings);
3015 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3017 snap_box.pack_start (snap_mode_selector, false, false);
3018 snap_box.pack_start (snap_type_selector, false, false);
3019 snap_box.pack_start (edit_point_selector, false, false);
3023 HBox *nudge_box = manage (new HBox);
3024 nudge_box->set_spacing (2);
3025 nudge_box->set_border_width (2);
3027 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3028 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3030 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3031 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3033 nudge_box->pack_start (nudge_backward_button, false, false);
3034 nudge_box->pack_start (nudge_forward_button, false, false);
3035 nudge_box->pack_start (*nudge_clock, false, false);
3038 /* Pack everything in... */
3040 HBox* hbox = manage (new HBox);
3041 hbox->set_spacing(10);
3043 _tools_tearoff = manage (new TearOff (*hbox));
3044 _tools_tearoff->set_name ("MouseModeBase");
3045 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3047 if (Profile->get_sae()) {
3048 _tools_tearoff->set_can_be_torn_off (false);
3051 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3052 &_tools_tearoff->tearoff_window()));
3053 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3054 &_tools_tearoff->tearoff_window(), 0));
3055 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3056 &_tools_tearoff->tearoff_window()));
3057 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3058 &_tools_tearoff->tearoff_window(), 0));
3060 toolbar_hbox.set_spacing (10);
3061 toolbar_hbox.set_border_width (1);
3063 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3064 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3065 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3067 hbox->pack_start (snap_box, false, false);
3068 if (!Profile->get_small_screen()) {
3069 hbox->pack_start (*nudge_box, false, false);
3071 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3073 hbox->pack_start (panic_box, false, false);
3077 toolbar_base.set_name ("ToolBarBase");
3078 toolbar_base.add (toolbar_hbox);
3080 _toolbar_viewport.add (toolbar_base);
3081 /* stick to the required height but allow width to vary if there's not enough room */
3082 _toolbar_viewport.set_size_request (1, -1);
3084 toolbar_frame.set_shadow_type (SHADOW_OUT);
3085 toolbar_frame.set_name ("BaseFrame");
3086 toolbar_frame.add (_toolbar_viewport);
3090 Editor::setup_tooltips ()
3092 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3093 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3094 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3095 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3096 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3097 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3098 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3099 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3100 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3101 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3102 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3103 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3104 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3105 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3106 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3107 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3108 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3109 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3110 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3111 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3112 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3113 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3114 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3118 Editor::convert_drop_to_paths (
3119 vector<string>& paths,
3120 const RefPtr<Gdk::DragContext>& /*context*/,
3123 const SelectionData& data,
3127 if (_session == 0) {
3131 vector<string> uris = data.get_uris();
3135 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3136 are actually URI lists. So do it by hand.
3139 if (data.get_target() != "text/plain") {
3143 /* Parse the "uri-list" format that Nautilus provides,
3144 where each pathname is delimited by \r\n.
3146 THERE MAY BE NO NULL TERMINATING CHAR!!!
3149 string txt = data.get_text();
3153 p = (const char *) malloc (txt.length() + 1);
3154 txt.copy (const_cast<char *> (p), txt.length(), 0);
3155 const_cast<char*>(p)[txt.length()] = '\0';
3161 while (g_ascii_isspace (*p))
3165 while (*q && (*q != '\n') && (*q != '\r')) {
3172 while (q > p && g_ascii_isspace (*q))
3177 uris.push_back (string (p, q - p + 1));
3181 p = strchr (p, '\n');
3193 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3195 if ((*i).substr (0,7) == "file://") {
3197 string const p = PBD::url_decode (*i);
3199 // scan forward past three slashes
3201 string::size_type slashcnt = 0;
3202 string::size_type n = 0;
3203 string::const_iterator x = p.begin();
3205 while (slashcnt < 3 && x != p.end()) {
3208 } else if (slashcnt == 3) {
3215 if (slashcnt != 3 || x == p.end()) {
3216 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3220 paths.push_back (p.substr (n - 1));
3228 Editor::new_tempo_section ()
3234 Editor::map_transport_state ()
3236 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3238 if (_session && _session->transport_stopped()) {
3239 have_pending_keyboard_selection = false;
3242 update_loop_range_view (true);
3248 Editor::begin_reversible_command (string name)
3251 _session->begin_reversible_command (name);
3256 Editor::begin_reversible_command (GQuark q)
3259 _session->begin_reversible_command (q);
3264 Editor::commit_reversible_command ()
3267 _session->commit_reversible_command ();
3272 Editor::history_changed ()
3276 if (undo_action && _session) {
3277 if (_session->undo_depth() == 0) {
3278 label = S_("Command|Undo");
3280 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3282 undo_action->property_label() = label;
3285 if (redo_action && _session) {
3286 if (_session->redo_depth() == 0) {
3289 label = string_compose(_("Redo (%1)"), _session->next_redo());
3291 redo_action->property_label() = label;
3296 Editor::duplicate_range (bool with_dialog)
3300 RegionSelection rs = get_regions_from_selection_and_entered ();
3302 if ( selection->time.length() == 0 && rs.empty()) {
3308 ArdourDialog win (_("Duplicate"));
3309 Label label (_("Number of duplications:"));
3310 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3311 SpinButton spinner (adjustment, 0.0, 1);
3314 win.get_vbox()->set_spacing (12);
3315 win.get_vbox()->pack_start (hbox);
3316 hbox.set_border_width (6);
3317 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3319 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3320 place, visually. so do this by hand.
3323 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3324 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3325 spinner.grab_focus();
3331 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3332 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3333 win.set_default_response (RESPONSE_ACCEPT);
3335 win.set_position (WIN_POS_MOUSE);
3337 spinner.grab_focus ();
3339 switch (win.run ()) {
3340 case RESPONSE_ACCEPT:
3346 times = adjustment.get_value();
3349 if ((current_mouse_mode() == Editing::MouseRange)) {
3350 if (selection->time.length()) {
3351 duplicate_selection (times);
3353 } else if (get_smart_mode()) {
3354 if (selection->time.length()) {
3355 duplicate_selection (times);
3357 duplicate_some_regions (rs, times);
3359 duplicate_some_regions (rs, times);
3364 Editor::set_edit_mode (EditMode m)
3366 Config->set_edit_mode (m);
3370 Editor::cycle_edit_mode ()
3372 switch (Config->get_edit_mode()) {
3374 if (Profile->get_sae()) {
3375 Config->set_edit_mode (Lock);
3377 Config->set_edit_mode (Splice);
3381 Config->set_edit_mode (Lock);
3384 Config->set_edit_mode (Slide);
3390 Editor::edit_mode_selection_done ()
3392 string s = edit_mode_selector.get_active_text ();
3395 Config->set_edit_mode (string_to_edit_mode (s));
3400 Editor::snap_type_selection_done ()
3402 string choice = snap_type_selector.get_active_text();
3403 SnapType snaptype = SnapToBeat;
3405 if (choice == _("Beats/2")) {
3406 snaptype = SnapToBeatDiv2;
3407 } else if (choice == _("Beats/3")) {
3408 snaptype = SnapToBeatDiv3;
3409 } else if (choice == _("Beats/4")) {
3410 snaptype = SnapToBeatDiv4;
3411 } else if (choice == _("Beats/5")) {
3412 snaptype = SnapToBeatDiv5;
3413 } else if (choice == _("Beats/6")) {
3414 snaptype = SnapToBeatDiv6;
3415 } else if (choice == _("Beats/7")) {
3416 snaptype = SnapToBeatDiv7;
3417 } else if (choice == _("Beats/8")) {
3418 snaptype = SnapToBeatDiv8;
3419 } else if (choice == _("Beats/10")) {
3420 snaptype = SnapToBeatDiv10;
3421 } else if (choice == _("Beats/12")) {
3422 snaptype = SnapToBeatDiv12;
3423 } else if (choice == _("Beats/14")) {
3424 snaptype = SnapToBeatDiv14;
3425 } else if (choice == _("Beats/16")) {
3426 snaptype = SnapToBeatDiv16;
3427 } else if (choice == _("Beats/20")) {
3428 snaptype = SnapToBeatDiv20;
3429 } else if (choice == _("Beats/24")) {
3430 snaptype = SnapToBeatDiv24;
3431 } else if (choice == _("Beats/28")) {
3432 snaptype = SnapToBeatDiv28;
3433 } else if (choice == _("Beats/32")) {
3434 snaptype = SnapToBeatDiv32;
3435 } else if (choice == _("Beats/64")) {
3436 snaptype = SnapToBeatDiv64;
3437 } else if (choice == _("Beats/128")) {
3438 snaptype = SnapToBeatDiv128;
3439 } else if (choice == _("Beats")) {
3440 snaptype = SnapToBeat;
3441 } else if (choice == _("Bars")) {
3442 snaptype = SnapToBar;
3443 } else if (choice == _("Marks")) {
3444 snaptype = SnapToMark;
3445 } else if (choice == _("Region starts")) {
3446 snaptype = SnapToRegionStart;
3447 } else if (choice == _("Region ends")) {
3448 snaptype = SnapToRegionEnd;
3449 } else if (choice == _("Region bounds")) {
3450 snaptype = SnapToRegionBoundary;
3451 } else if (choice == _("Region syncs")) {
3452 snaptype = SnapToRegionSync;
3453 } else if (choice == _("CD Frames")) {
3454 snaptype = SnapToCDFrame;
3455 } else if (choice == _("Timecode Frames")) {
3456 snaptype = SnapToTimecodeFrame;
3457 } else if (choice == _("Timecode Seconds")) {
3458 snaptype = SnapToTimecodeSeconds;
3459 } else if (choice == _("Timecode Minutes")) {
3460 snaptype = SnapToTimecodeMinutes;
3461 } else if (choice == _("Seconds")) {
3462 snaptype = SnapToSeconds;
3463 } else if (choice == _("Minutes")) {
3464 snaptype = SnapToMinutes;
3467 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3469 ract->set_active ();
3474 Editor::snap_mode_selection_done ()
3476 string choice = snap_mode_selector.get_active_text();
3477 SnapMode mode = SnapNormal;
3479 if (choice == _("No Grid")) {
3481 } else if (choice == _("Grid")) {
3483 } else if (choice == _("Magnetic")) {
3484 mode = SnapMagnetic;
3487 RefPtr<RadioAction> ract = snap_mode_action (mode);
3490 ract->set_active (true);
3495 Editor::cycle_edit_point (bool with_marker)
3497 switch (_edit_point) {
3499 set_edit_point_preference (EditAtPlayhead);
3501 case EditAtPlayhead:
3503 set_edit_point_preference (EditAtSelectedMarker);
3505 set_edit_point_preference (EditAtMouse);
3508 case EditAtSelectedMarker:
3509 set_edit_point_preference (EditAtMouse);
3515 Editor::edit_point_selection_done ()
3517 string choice = edit_point_selector.get_active_text();
3518 EditPoint ep = EditAtSelectedMarker;
3520 if (choice == _("Marker")) {
3521 set_edit_point_preference (EditAtSelectedMarker);
3522 } else if (choice == _("Playhead")) {
3523 set_edit_point_preference (EditAtPlayhead);
3525 set_edit_point_preference (EditAtMouse);
3528 RefPtr<RadioAction> ract = edit_point_action (ep);
3531 ract->set_active (true);
3536 Editor::zoom_focus_selection_done ()
3538 string choice = zoom_focus_selector.get_active_text();
3539 ZoomFocus focus_type = ZoomFocusLeft;
3541 if (choice == _("Left")) {
3542 focus_type = ZoomFocusLeft;
3543 } else if (choice == _("Right")) {
3544 focus_type = ZoomFocusRight;
3545 } else if (choice == _("Center")) {
3546 focus_type = ZoomFocusCenter;
3547 } else if (choice == _("Playhead")) {
3548 focus_type = ZoomFocusPlayhead;
3549 } else if (choice == _("Mouse")) {
3550 focus_type = ZoomFocusMouse;
3551 } else if (choice == _("Edit point")) {
3552 focus_type = ZoomFocusEdit;
3555 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3558 ract->set_active ();
3563 Editor::edit_controls_button_release (GdkEventButton* ev)
3565 if (Keyboard::is_context_menu_event (ev)) {
3566 ARDOUR_UI::instance()->add_route (this);
3567 } else if (ev->button == 1) {
3568 selection->clear_tracks ();
3575 Editor::mouse_select_button_release (GdkEventButton* ev)
3577 /* this handles just right-clicks */
3579 if (ev->button != 3) {
3587 Editor::set_zoom_focus (ZoomFocus f)
3589 string str = zoom_focus_strings[(int)f];
3591 if (str != zoom_focus_selector.get_active_text()) {
3592 zoom_focus_selector.set_active_text (str);
3595 if (zoom_focus != f) {
3602 Editor::cycle_zoom_focus ()
3604 switch (zoom_focus) {
3606 set_zoom_focus (ZoomFocusRight);
3608 case ZoomFocusRight:
3609 set_zoom_focus (ZoomFocusCenter);
3611 case ZoomFocusCenter:
3612 set_zoom_focus (ZoomFocusPlayhead);
3614 case ZoomFocusPlayhead:
3615 set_zoom_focus (ZoomFocusMouse);
3617 case ZoomFocusMouse:
3618 set_zoom_focus (ZoomFocusEdit);
3621 set_zoom_focus (ZoomFocusLeft);
3627 Editor::ensure_float (Window& win)
3629 win.set_transient_for (*this);
3633 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3635 /* recover or initialize pane positions. do this here rather than earlier because
3636 we don't want the positions to change the child allocations, which they seem to do.
3642 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3651 XMLNode* geometry = find_named_node (*node, "geometry");
3653 if (which == static_cast<Paned*> (&edit_pane)) {
3655 if (done & Horizontal) {
3659 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3660 _notebook_shrunk = string_is_affirmative (prop->value ());
3663 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3664 /* initial allocation is 90% to canvas, 10% to notebook */
3665 pos = (int) floor (alloc.get_width() * 0.90f);
3666 snprintf (buf, sizeof(buf), "%d", pos);
3668 pos = atoi (prop->value());
3671 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3672 edit_pane.set_position (pos);
3675 done = (Pane) (done | Horizontal);
3677 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3679 if (done & Vertical) {
3683 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3684 /* initial allocation is 90% to canvas, 10% to summary */
3685 pos = (int) floor (alloc.get_height() * 0.90f);
3686 snprintf (buf, sizeof(buf), "%d", pos);
3689 pos = atoi (prop->value());
3692 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3693 editor_summary_pane.set_position (pos);
3696 done = (Pane) (done | Vertical);
3701 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3703 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3704 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3705 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3706 top_hbox.remove (toolbar_frame);
3711 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3713 if (toolbar_frame.get_parent() == 0) {
3714 top_hbox.pack_end (toolbar_frame);
3719 Editor::set_show_measures (bool yn)
3721 if (_show_measures != yn) {
3724 if ((_show_measures = yn) == true) {
3726 tempo_lines->show();
3728 (void) redraw_measures ();
3735 Editor::toggle_follow_playhead ()
3737 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3739 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3740 set_follow_playhead (tact->get_active());
3744 /** @param yn true to follow playhead, otherwise false.
3745 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3748 Editor::set_follow_playhead (bool yn, bool catch_up)
3750 if (_follow_playhead != yn) {
3751 if ((_follow_playhead = yn) == true && catch_up) {
3753 reset_x_origin_to_follow_playhead ();
3760 Editor::toggle_stationary_playhead ()
3762 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3764 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3765 set_stationary_playhead (tact->get_active());
3770 Editor::set_stationary_playhead (bool yn)
3772 if (_stationary_playhead != yn) {
3773 if ((_stationary_playhead = yn) == true) {
3775 // FIXME need a 3.0 equivalent of this 2.X call
3776 // update_current_screen ();
3783 Editor::playlist_selector () const
3785 return *_playlist_selector;
3789 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3793 switch (_snap_type) {
3798 case SnapToBeatDiv128:
3801 case SnapToBeatDiv64:
3804 case SnapToBeatDiv32:
3807 case SnapToBeatDiv28:
3810 case SnapToBeatDiv24:
3813 case SnapToBeatDiv20:
3816 case SnapToBeatDiv16:
3819 case SnapToBeatDiv14:
3822 case SnapToBeatDiv12:
3825 case SnapToBeatDiv10:
3828 case SnapToBeatDiv8:
3831 case SnapToBeatDiv7:
3834 case SnapToBeatDiv6:
3837 case SnapToBeatDiv5:
3840 case SnapToBeatDiv4:
3843 case SnapToBeatDiv3:
3846 case SnapToBeatDiv2:
3852 return _session->tempo_map().meter_at (position).divisions_per_bar();
3857 case SnapToTimecodeFrame:
3858 case SnapToTimecodeSeconds:
3859 case SnapToTimecodeMinutes:
3862 case SnapToRegionStart:
3863 case SnapToRegionEnd:
3864 case SnapToRegionSync:
3865 case SnapToRegionBoundary:
3875 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3879 ret = nudge_clock->current_duration (pos);
3880 next = ret + 1; /* XXXX fix me */
3886 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3888 ArdourDialog dialog (_("Playlist Deletion"));
3889 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3890 "If it is kept, its audio files will not be cleaned.\n"
3891 "If it is deleted, audio files used by it alone will be cleaned."),
3894 dialog.set_position (WIN_POS_CENTER);
3895 dialog.get_vbox()->pack_start (label);
3899 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3900 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3901 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3903 switch (dialog.run ()) {
3904 case RESPONSE_ACCEPT:
3905 /* delete the playlist */
3909 case RESPONSE_REJECT:
3910 /* keep the playlist */
3922 Editor::audio_region_selection_covers (framepos_t where)
3924 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3925 if ((*a)->region()->covers (where)) {
3934 Editor::prepare_for_cleanup ()
3936 cut_buffer->clear_regions ();
3937 cut_buffer->clear_playlists ();
3939 selection->clear_regions ();
3940 selection->clear_playlists ();
3942 _regions->suspend_redisplay ();
3946 Editor::finish_cleanup ()
3948 _regions->resume_redisplay ();
3952 Editor::transport_loop_location()
3955 return _session->locations()->auto_loop_location();
3962 Editor::transport_punch_location()
3965 return _session->locations()->auto_punch_location();
3972 Editor::control_layout_scroll (GdkEventScroll* ev)
3974 if (Keyboard::some_magic_widget_has_focus()) {
3978 switch (ev->direction) {
3980 scroll_tracks_up_line ();
3984 case GDK_SCROLL_DOWN:
3985 scroll_tracks_down_line ();
3989 /* no left/right handling yet */
3997 Editor::session_state_saved (string)
4000 _snapshots->redisplay ();
4004 Editor::update_tearoff_visibility()
4006 bool visible = Config->get_keep_tearoffs();
4007 _mouse_mode_tearoff->set_visible (visible);
4008 _tools_tearoff->set_visible (visible);
4009 _zoom_tearoff->set_visible (visible);
4013 Editor::maximise_editing_space ()
4025 Editor::restore_editing_space ()
4037 * Make new playlists for a given track and also any others that belong
4038 * to the same active route group with the `select' property.
4043 Editor::new_playlists (TimeAxisView* v)
4045 begin_reversible_command (_("new playlists"));
4046 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4047 _session->playlists->get (playlists);
4048 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4049 commit_reversible_command ();
4053 * Use a copy of the current playlist for a given track and also any others that belong
4054 * to the same active route group with the `select' property.
4059 Editor::copy_playlists (TimeAxisView* v)
4061 begin_reversible_command (_("copy playlists"));
4062 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4063 _session->playlists->get (playlists);
4064 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4065 commit_reversible_command ();
4068 /** Clear the current playlist for a given track and also any others that belong
4069 * to the same active route group with the `select' property.
4074 Editor::clear_playlists (TimeAxisView* v)
4076 begin_reversible_command (_("clear playlists"));
4077 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4078 _session->playlists->get (playlists);
4079 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4080 commit_reversible_command ();
4084 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4086 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4090 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4092 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4096 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4098 atv.clear_playlist ();
4102 Editor::on_key_press_event (GdkEventKey* ev)
4104 return key_press_focus_accelerator_handler (*this, ev);
4108 Editor::on_key_release_event (GdkEventKey* ev)
4110 return Gtk::Window::on_key_release_event (ev);
4111 // return key_press_focus_accelerator_handler (*this, ev);
4114 /** Queue up a change to the viewport x origin.
4115 * @param frame New x origin.
4118 Editor::reset_x_origin (framepos_t frame)
4120 pending_visual_change.add (VisualChange::TimeOrigin);
4121 pending_visual_change.time_origin = frame;
4122 ensure_visual_change_idle_handler ();
4126 Editor::reset_y_origin (double y)
4128 pending_visual_change.add (VisualChange::YOrigin);
4129 pending_visual_change.y_origin = y;
4130 ensure_visual_change_idle_handler ();
4134 Editor::reset_zoom (double fpp)
4136 clamp_samples_per_pixel (fpp);
4138 if (fpp == samples_per_pixel) {
4142 pending_visual_change.add (VisualChange::ZoomLevel);
4143 pending_visual_change.samples_per_pixel = fpp;
4144 ensure_visual_change_idle_handler ();
4148 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4150 reset_x_origin (frame);
4153 if (!no_save_visual) {
4154 undo_visual_stack.push_back (current_visual_state(false));
4158 Editor::VisualState::VisualState (bool with_tracks)
4159 : gui_state (with_tracks ? new GUIObjectState : 0)
4163 Editor::VisualState::~VisualState ()
4168 Editor::VisualState*
4169 Editor::current_visual_state (bool with_tracks)
4171 VisualState* vs = new VisualState (with_tracks);
4172 vs->y_position = vertical_adjustment.get_value();
4173 vs->samples_per_pixel = samples_per_pixel;
4174 vs->leftmost_frame = leftmost_frame;
4175 vs->zoom_focus = zoom_focus;
4178 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4185 Editor::undo_visual_state ()
4187 if (undo_visual_stack.empty()) {
4191 VisualState* vs = undo_visual_stack.back();
4192 undo_visual_stack.pop_back();
4195 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4197 use_visual_state (*vs);
4201 Editor::redo_visual_state ()
4203 if (redo_visual_stack.empty()) {
4207 VisualState* vs = redo_visual_stack.back();
4208 redo_visual_stack.pop_back();
4210 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4212 use_visual_state (*vs);
4216 Editor::swap_visual_state ()
4218 if (undo_visual_stack.empty()) {
4219 redo_visual_state ();
4221 undo_visual_state ();
4226 Editor::use_visual_state (VisualState& vs)
4228 PBD::Unwinder<bool> nsv (no_save_visual, true);
4230 _routes->suspend_redisplay ();
4232 vertical_adjustment.set_value (vs.y_position);
4234 set_zoom_focus (vs.zoom_focus);
4235 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4238 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4240 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4241 (*i)->reset_visual_state ();
4245 _routes->update_visibility ();
4246 _routes->resume_redisplay ();
4249 /** This is the core function that controls the zoom level of the canvas. It is called
4250 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4251 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4254 Editor::set_samples_per_pixel (double fpp)
4257 tempo_lines->tempo_map_changed();
4260 samples_per_pixel = fpp;
4262 /* convert fpu to frame count */
4264 framepos_t frames = (framepos_t) floor (samples_per_pixel * _visible_canvas_width);
4266 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4267 zoom_range_clock->set (frames);
4270 bool const showing_time_selection = selection->time.length() > 0;
4272 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4273 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4274 (*i)->reshow_selection (selection->time);
4278 ZoomChanged (); /* EMIT_SIGNAL */
4280 //reset_scrolling_region ();
4282 if (playhead_cursor) {
4283 playhead_cursor->set_position (playhead_cursor->current_frame ());
4286 refresh_location_display();
4287 _summary->set_overlays_dirty ();
4289 update_marker_labels ();
4295 Editor::queue_visual_videotimeline_update ()
4298 * pending_visual_change.add (VisualChange::VideoTimeline);
4299 * or maybe even more specific: which videotimeline-image
4300 * currently it calls update_video_timeline() to update
4301 * _all outdated_ images on the video-timeline.
4302 * see 'exposeimg()' in video_image_frame.cc
4304 ensure_visual_change_idle_handler ();
4308 Editor::ensure_visual_change_idle_handler ()
4310 if (pending_visual_change.idle_handler_id < 0) {
4311 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4312 pending_visual_change.being_handled = false;
4317 Editor::_idle_visual_changer (void* arg)
4319 return static_cast<Editor*>(arg)->idle_visual_changer ();
4323 Editor::idle_visual_changer ()
4325 /* set_horizontal_position() below (and maybe other calls) call
4326 gtk_main_iteration(), so it's possible that a signal will be handled
4327 half-way through this method. If this signal wants an
4328 idle_visual_changer we must schedule another one after this one, so
4329 mark the idle_handler_id as -1 here to allow that. Also make a note
4330 that we are doing the visual change, so that changes in response to
4331 super-rapid-screen-update can be dropped if we are still processing
4335 pending_visual_change.idle_handler_id = -1;
4336 pending_visual_change.being_handled = true;
4338 VisualChange::Type p = pending_visual_change.pending;
4339 pending_visual_change.pending = (VisualChange::Type) 0;
4341 double const last_time_origin = horizontal_position ();
4343 if (p & VisualChange::ZoomLevel) {
4344 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4346 compute_fixed_ruler_scale ();
4348 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4349 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4351 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4352 current_bbt_points_begin, current_bbt_points_end);
4353 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4354 current_bbt_points_begin, current_bbt_points_end);
4355 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4358 if (p & VisualChange::ZoomLevel) {
4359 update_video_timeline();
4362 if (p & VisualChange::TimeOrigin) {
4363 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4366 if (p & VisualChange::YOrigin) {
4367 vertical_adjustment.set_value (pending_visual_change.y_origin);
4370 if (last_time_origin == horizontal_position ()) {
4371 /* changed signal not emitted */
4372 update_fixed_rulers ();
4373 redisplay_tempo (true);
4376 if (!(p & VisualChange::ZoomLevel)) {
4377 update_video_timeline();
4380 _summary->set_overlays_dirty ();
4382 pending_visual_change.being_handled = false;
4383 return 0; /* this is always a one-shot call */
4386 struct EditorOrderTimeAxisSorter {
4387 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4388 return a->order () < b->order ();
4393 Editor::sort_track_selection (TrackViewList& sel)
4395 EditorOrderTimeAxisSorter cmp;
4400 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4403 framepos_t where = 0;
4404 EditPoint ep = _edit_point;
4406 if (from_context_menu && (ep == EditAtMouse)) {
4407 return window_event_frame (&context_click_event, 0, 0);
4410 if (entered_marker) {
4411 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4412 return entered_marker->position();
4415 if (ignore_playhead && ep == EditAtPlayhead) {
4416 ep = EditAtSelectedMarker;
4420 case EditAtPlayhead:
4421 where = _session->audible_frame();
4422 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4425 case EditAtSelectedMarker:
4426 if (!selection->markers.empty()) {
4428 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4431 where = loc->start();
4435 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4443 if (!mouse_frame (where, ignored)) {
4444 /* XXX not right but what can we do ? */
4448 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4456 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4458 if (!_session) return;
4460 begin_reversible_command (cmd);
4464 if ((tll = transport_loop_location()) == 0) {
4465 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4466 XMLNode &before = _session->locations()->get_state();
4467 _session->locations()->add (loc, true);
4468 _session->set_auto_loop_location (loc);
4469 XMLNode &after = _session->locations()->get_state();
4470 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4472 XMLNode &before = tll->get_state();
4473 tll->set_hidden (false, this);
4474 tll->set (start, end);
4475 XMLNode &after = tll->get_state();
4476 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4479 commit_reversible_command ();
4483 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4485 if (!_session) return;
4487 begin_reversible_command (cmd);
4491 if ((tpl = transport_punch_location()) == 0) {
4492 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4493 XMLNode &before = _session->locations()->get_state();
4494 _session->locations()->add (loc, true);
4495 _session->set_auto_loop_location (loc);
4496 XMLNode &after = _session->locations()->get_state();
4497 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4500 XMLNode &before = tpl->get_state();
4501 tpl->set_hidden (false, this);
4502 tpl->set (start, end);
4503 XMLNode &after = tpl->get_state();
4504 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4507 commit_reversible_command ();
4510 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4511 * @param rs List to which found regions are added.
4512 * @param where Time to look at.
4513 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4516 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4518 const TrackViewList* tracks;
4521 tracks = &track_views;
4526 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4528 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4531 boost::shared_ptr<Track> tr;
4532 boost::shared_ptr<Playlist> pl;
4534 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4536 boost::shared_ptr<RegionList> regions = pl->regions_at (
4537 (framepos_t) floor ( (double) where * tr->speed()));
4539 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4540 RegionView* rv = rtv->view()->find_view (*i);
4551 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4553 const TrackViewList* tracks;
4556 tracks = &track_views;
4561 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4562 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4564 boost::shared_ptr<Track> tr;
4565 boost::shared_ptr<Playlist> pl;
4567 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4569 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4570 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4572 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4574 RegionView* rv = rtv->view()->find_view (*i);
4585 /** Get regions using the following method:
4587 * Make a region list using the selected regions, unless
4588 * the edit point is `mouse' and the mouse is over an unselected
4589 * region. In this case, use just that region.
4591 * If the edit point is not 'mouse', and there are no regions selected,
4592 * search the list of selected tracks and return regions that are under
4593 * the edit point on these tracks. If there are no selected tracks and
4594 * 'No Selection = All Tracks' is active, search all tracks,
4596 * The rationale here is that the mouse edit point is special in that
4597 * its position describes both a time and a track; the other edit
4598 * modes only describe a time. Hence if the edit point is `mouse' we
4599 * ignore selected tracks, as we assume the user means something by
4600 * pointing at a particular track. Also in this case we take note of
4601 * the region directly under the edit point, as there is always just one
4602 * (rather than possibly several with non-mouse edit points).
4606 Editor::get_regions_from_selection_and_edit_point ()
4608 RegionSelection regions;
4610 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4611 regions.add (entered_regionview);
4613 regions = selection->regions;
4617 if (regions.empty() && _edit_point != EditAtMouse) {
4618 TrackViewList tracks = selection->tracks;
4620 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4621 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4622 * is enabled, so consider all tracks
4624 tracks = track_views;
4627 if (!tracks.empty()) {
4628 /* no region selected or entered, but some selected tracks:
4629 * act on all regions on the selected tracks at the edit point
4631 framepos_t const where = get_preferred_edit_position ();
4632 get_regions_at(regions, where, tracks);
4638 /** Start with regions that are selected, or the entered regionview if none are selected.
4639 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4640 * of the regions that we started with.
4644 Editor::get_regions_from_selection_and_entered ()
4646 RegionSelection regions = selection->regions;
4648 if (regions.empty() && entered_regionview) {
4649 regions.add (entered_regionview);
4656 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4658 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4660 RouteTimeAxisView* tatv;
4662 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4664 boost::shared_ptr<Playlist> pl;
4665 vector<boost::shared_ptr<Region> > results;
4667 boost::shared_ptr<Track> tr;
4669 if ((tr = tatv->track()) == 0) {
4674 if ((pl = (tr->playlist())) != 0) {
4675 if (src_comparison) {
4676 pl->get_source_equivalent_regions (region, results);
4678 pl->get_region_list_equivalent_regions (region, results);
4682 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4683 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4684 regions.push_back (marv);
4693 Editor::show_rhythm_ferret ()
4695 if (rhythm_ferret == 0) {
4696 rhythm_ferret = new RhythmFerret(*this);
4699 rhythm_ferret->set_session (_session);
4700 rhythm_ferret->show ();
4701 rhythm_ferret->present ();
4705 Editor::first_idle ()
4707 MessageDialog* dialog = 0;
4709 if (track_views.size() > 1) {
4710 dialog = new MessageDialog (
4712 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4716 ARDOUR_UI::instance()->flush_pending ();
4719 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4723 // first idle adds route children (automation tracks), so we need to redisplay here
4724 _routes->redisplay ();
4731 Editor::_idle_resize (gpointer arg)
4733 return ((Editor*)arg)->idle_resize ();
4737 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4739 if (resize_idle_id < 0) {
4740 resize_idle_id = g_idle_add (_idle_resize, this);
4741 _pending_resize_amount = 0;
4744 /* make a note of the smallest resulting height, so that we can clamp the
4745 lower limit at TimeAxisView::hSmall */
4747 int32_t min_resulting = INT32_MAX;
4749 _pending_resize_amount += h;
4750 _pending_resize_view = view;
4752 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4754 if (selection->tracks.contains (_pending_resize_view)) {
4755 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4756 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4760 if (min_resulting < 0) {
4765 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4766 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4770 /** Handle pending resizing of tracks */
4772 Editor::idle_resize ()
4774 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4776 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4777 selection->tracks.contains (_pending_resize_view)) {
4779 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4780 if (*i != _pending_resize_view) {
4781 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4786 _pending_resize_amount = 0;
4787 _group_tabs->set_dirty ();
4788 resize_idle_id = -1;
4796 ENSURE_GUI_THREAD (*this, &Editor::located);
4799 playhead_cursor->set_position (_session->audible_frame ());
4800 if (_follow_playhead && !_pending_initial_locate) {
4801 reset_x_origin_to_follow_playhead ();
4805 _pending_locate_request = false;
4806 _pending_initial_locate = false;
4810 Editor::region_view_added (RegionView *)
4812 _summary->set_dirty ();
4816 Editor::region_view_removed ()
4818 _summary->set_dirty ();
4822 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4824 TrackViewList::const_iterator j = track_views.begin ();
4825 while (j != track_views.end()) {
4826 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4827 if (rtv && rtv->route() == r) {
4838 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4842 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4843 TimeAxisView* tv = axis_view_from_route (*i);
4853 Editor::add_routes (RouteList& routes)
4855 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4857 RouteTimeAxisView *rtv;
4858 list<RouteTimeAxisView*> new_views;
4860 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4861 boost::shared_ptr<Route> route = (*x);
4863 if (route->is_auditioner() || route->is_monitor()) {
4867 DataType dt = route->input()->default_type();
4869 if (dt == ARDOUR::DataType::AUDIO) {
4870 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4871 rtv->set_route (route);
4872 } else if (dt == ARDOUR::DataType::MIDI) {
4873 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4874 rtv->set_route (route);
4876 throw unknown_type();
4879 new_views.push_back (rtv);
4880 track_views.push_back (rtv);
4882 rtv->effective_gain_display ();
4884 if (internal_editing()) {
4885 rtv->enter_internal_edit_mode ();
4887 rtv->leave_internal_edit_mode ();
4890 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4891 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4894 _routes->routes_added (new_views);
4895 _summary->routes_added (new_views);
4897 if (show_editor_mixer_when_tracks_arrive) {
4898 show_editor_mixer (true);
4901 editor_list_button.set_sensitive (true);
4905 Editor::timeaxisview_deleted (TimeAxisView *tv)
4907 if (_session && _session->deletion_in_progress()) {
4908 /* the situation is under control */
4912 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4914 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4916 _routes->route_removed (tv);
4918 if (tv == entered_track) {
4922 TimeAxisView::Children c = tv->get_child_list ();
4923 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4924 if (entered_track == i->get()) {
4929 /* remove it from the list of track views */
4931 TrackViewList::iterator i;
4933 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4934 i = track_views.erase (i);
4937 /* update whatever the current mixer strip is displaying, if revelant */
4939 boost::shared_ptr<Route> route;
4942 route = rtav->route ();
4945 if (current_mixer_strip && current_mixer_strip->route() == route) {
4947 TimeAxisView* next_tv;
4949 if (track_views.empty()) {
4951 } else if (i == track_views.end()) {
4952 next_tv = track_views.front();
4959 set_selected_mixer_strip (*next_tv);
4961 /* make the editor mixer strip go away setting the
4962 * button to inactive (which also unticks the menu option)
4965 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4971 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4973 if (apply_to_selection) {
4974 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4976 TrackSelection::iterator j = i;
4979 hide_track_in_display (*i, false);
4984 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4986 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4987 // this will hide the mixer strip
4988 set_selected_mixer_strip (*tv);
4991 _routes->hide_track_in_display (*tv);
4996 Editor::sync_track_view_list_and_routes ()
4998 track_views = TrackViewList (_routes->views ());
5000 _summary->set_dirty ();
5001 _group_tabs->set_dirty ();
5003 return false; // do not call again (until needed)
5007 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5009 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5014 /** Find a RouteTimeAxisView by the ID of its route */
5016 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5018 RouteTimeAxisView* v;
5020 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5021 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5022 if(v->route()->id() == id) {
5032 Editor::fit_route_group (RouteGroup *g)
5034 TrackViewList ts = axis_views_from_routes (g->route_list ());
5039 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5041 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5044 _session->cancel_audition ();
5048 if (_session->is_auditioning()) {
5049 _session->cancel_audition ();
5050 if (r == last_audition_region) {
5055 _session->audition_region (r);
5056 last_audition_region = r;
5061 Editor::hide_a_region (boost::shared_ptr<Region> r)
5063 r->set_hidden (true);
5067 Editor::show_a_region (boost::shared_ptr<Region> r)
5069 r->set_hidden (false);
5073 Editor::audition_region_from_region_list ()
5075 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5079 Editor::hide_region_from_region_list ()
5081 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5085 Editor::show_region_in_region_list ()
5087 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5091 Editor::step_edit_status_change (bool yn)
5094 start_step_editing ();
5096 stop_step_editing ();
5101 Editor::start_step_editing ()
5103 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5107 Editor::stop_step_editing ()
5109 step_edit_connection.disconnect ();
5113 Editor::check_step_edit ()
5115 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5116 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5118 mtv->check_step_edit ();
5122 return true; // do it again, till we stop
5126 Editor::scroll_press (Direction dir)
5128 ++_scroll_callbacks;
5130 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5131 /* delay the first auto-repeat */
5137 scroll_backward (1);
5145 scroll_tracks_up_line ();
5149 scroll_tracks_down_line ();
5153 /* do hacky auto-repeat */
5154 if (!_scroll_connection.connected ()) {
5156 _scroll_connection = Glib::signal_timeout().connect (
5157 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5160 _scroll_callbacks = 0;
5167 Editor::scroll_release ()
5169 _scroll_connection.disconnect ();
5172 /** Queue a change for the Editor viewport x origin to follow the playhead */
5174 Editor::reset_x_origin_to_follow_playhead ()
5176 framepos_t const frame = playhead_cursor->current_frame ();
5178 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5180 if (_session->transport_speed() < 0) {
5182 if (frame > (current_page_samples() / 2)) {
5183 center_screen (frame-(current_page_samples()/2));
5185 center_screen (current_page_samples()/2);
5192 if (frame < leftmost_frame) {
5194 if (_session->transport_rolling()) {
5195 /* rolling; end up with the playhead at the right of the page */
5196 l = frame - current_page_samples ();
5198 /* not rolling: end up with the playhead 1/4 of the way along the page */
5199 l = frame - current_page_samples() / 4;
5203 if (_session->transport_rolling()) {
5204 /* rolling: end up with the playhead on the left of the page */
5207 /* not rolling: end up with the playhead 3/4 of the way along the page */
5208 l = frame - 3 * current_page_samples() / 4;
5216 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5222 Editor::super_rapid_screen_update ()
5224 if (!_session || !_session->engine().running()) {
5228 /* METERING / MIXER STRIPS */
5230 /* update track meters, if required */
5231 if (is_mapped() && meters_running) {
5232 RouteTimeAxisView* rtv;
5233 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5234 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5235 rtv->fast_update ();
5240 /* and any current mixer strip */
5241 if (current_mixer_strip) {
5242 current_mixer_strip->fast_update ();
5245 /* PLAYHEAD AND VIEWPORT */
5247 framepos_t const frame = _session->audible_frame();
5249 /* There are a few reasons why we might not update the playhead / viewport stuff:
5251 * 1. we don't update things when there's a pending locate request, otherwise
5252 * when the editor requests a locate there is a chance that this method
5253 * will move the playhead before the locate request is processed, causing
5255 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5256 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5259 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5261 last_update_frame = frame;
5263 if (!_dragging_playhead) {
5264 playhead_cursor->set_position (frame);
5267 if (!_stationary_playhead) {
5269 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5270 /* We only do this if we aren't already
5271 handling a visual change (ie if
5272 pending_visual_change.being_handled is
5273 false) so that these requests don't stack
5274 up there are too many of them to handle in
5277 reset_x_origin_to_follow_playhead ();
5282 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5286 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5287 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5288 if (target <= 0.0) {
5291 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5292 target = (target * 0.15) + (current * 0.85);
5298 set_horizontal_position (current);
5307 Editor::session_going_away ()
5309 _have_idled = false;
5311 _session_connections.drop_connections ();
5313 super_rapid_screen_update_connection.disconnect ();
5315 selection->clear ();
5316 cut_buffer->clear ();
5318 clicked_regionview = 0;
5319 clicked_axisview = 0;
5320 clicked_routeview = 0;
5321 entered_regionview = 0;
5323 last_update_frame = 0;
5326 playhead_cursor->hide ();
5328 /* rip everything out of the list displays */
5332 _route_groups->clear ();
5334 /* do this first so that deleting a track doesn't reset cms to null
5335 and thus cause a leak.
5338 if (current_mixer_strip) {
5339 if (current_mixer_strip->get_parent() != 0) {
5340 global_hpacker.remove (*current_mixer_strip);
5342 delete current_mixer_strip;
5343 current_mixer_strip = 0;
5346 /* delete all trackviews */
5348 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5351 track_views.clear ();
5353 zoom_range_clock->set_session (0);
5354 nudge_clock->set_session (0);
5356 editor_list_button.set_active(false);
5357 editor_list_button.set_sensitive(false);
5359 /* clear tempo/meter rulers */
5360 remove_metric_marks ();
5362 clear_marker_display ();
5364 stop_step_editing ();
5366 /* get rid of any existing editor mixer strip */
5368 WindowTitle title(Glib::get_application_name());
5369 title += _("Editor");
5371 set_title (title.get_string());
5373 SessionHandlePtr::session_going_away ();
5378 Editor::show_editor_list (bool yn)
5381 _the_notebook.show ();
5383 _the_notebook.hide ();
5388 Editor::change_region_layering_order (bool from_context_menu)
5390 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5392 if (!clicked_routeview) {
5393 if (layering_order_editor) {
5394 layering_order_editor->hide ();
5399 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5405 boost::shared_ptr<Playlist> pl = track->playlist();
5411 if (layering_order_editor == 0) {
5412 layering_order_editor = new RegionLayeringOrderEditor (*this);
5413 layering_order_editor->set_position (WIN_POS_MOUSE);
5416 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5417 layering_order_editor->maybe_present ();
5421 Editor::update_region_layering_order_editor ()
5423 if (layering_order_editor && layering_order_editor->is_visible ()) {
5424 change_region_layering_order (true);
5429 Editor::setup_fade_images ()
5431 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5432 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5433 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5434 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5435 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5437 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5438 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5439 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5440 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5441 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5443 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5444 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5445 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5446 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5447 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5449 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5450 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5451 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5452 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5453 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5457 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5459 Editor::action_menu_item (std::string const & name)
5461 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5464 return *manage (a->create_menu_item ());
5468 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5470 EventBox* b = manage (new EventBox);
5471 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5472 Label* l = manage (new Label (name));
5476 _the_notebook.append_page (widget, *b);
5480 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5482 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5483 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5486 if (ev->type == GDK_2BUTTON_PRESS) {
5488 /* double-click on a notebook tab shrinks or expands the notebook */
5490 if (_notebook_shrunk) {
5491 if (pre_notebook_shrink_pane_width) {
5492 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5494 _notebook_shrunk = false;
5496 pre_notebook_shrink_pane_width = edit_pane.get_position();
5498 /* this expands the LHS of the edit pane to cover the notebook
5499 PAGE but leaves the tabs visible.
5501 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5502 _notebook_shrunk = true;
5510 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5512 using namespace Menu_Helpers;
5514 MenuList& items = _control_point_context_menu.items ();
5517 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5518 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5519 if (!can_remove_control_point (item)) {
5520 items.back().set_sensitive (false);
5523 _control_point_context_menu.popup (event->button.button, event->button.time);
5527 Editor::shift_key_released ()
5529 _stepping_axis_view = 0;
5534 Editor::save_canvas_state ()
5536 XMLTree* tree = static_cast<ArdourCanvas::Canvas*>(_track_canvas)->get_state ();
5537 string path = string_compose ("%1/canvas-state.xml", _session->path());