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()->get_canvasvar_LocationMarker();
375 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
376 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
377 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
378 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
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();
3729 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3730 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3732 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3733 draw_measures (begin, end);
3741 Editor::toggle_follow_playhead ()
3743 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3745 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3746 set_follow_playhead (tact->get_active());
3750 /** @param yn true to follow playhead, otherwise false.
3751 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3754 Editor::set_follow_playhead (bool yn, bool catch_up)
3756 if (_follow_playhead != yn) {
3757 if ((_follow_playhead = yn) == true && catch_up) {
3759 reset_x_origin_to_follow_playhead ();
3766 Editor::toggle_stationary_playhead ()
3768 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3770 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3771 set_stationary_playhead (tact->get_active());
3776 Editor::set_stationary_playhead (bool yn)
3778 if (_stationary_playhead != yn) {
3779 if ((_stationary_playhead = yn) == true) {
3781 // FIXME need a 3.0 equivalent of this 2.X call
3782 // update_current_screen ();
3789 Editor::playlist_selector () const
3791 return *_playlist_selector;
3795 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3799 switch (_snap_type) {
3804 case SnapToBeatDiv128:
3807 case SnapToBeatDiv64:
3810 case SnapToBeatDiv32:
3813 case SnapToBeatDiv28:
3816 case SnapToBeatDiv24:
3819 case SnapToBeatDiv20:
3822 case SnapToBeatDiv16:
3825 case SnapToBeatDiv14:
3828 case SnapToBeatDiv12:
3831 case SnapToBeatDiv10:
3834 case SnapToBeatDiv8:
3837 case SnapToBeatDiv7:
3840 case SnapToBeatDiv6:
3843 case SnapToBeatDiv5:
3846 case SnapToBeatDiv4:
3849 case SnapToBeatDiv3:
3852 case SnapToBeatDiv2:
3858 return _session->tempo_map().meter_at (position).divisions_per_bar();
3863 case SnapToTimecodeFrame:
3864 case SnapToTimecodeSeconds:
3865 case SnapToTimecodeMinutes:
3868 case SnapToRegionStart:
3869 case SnapToRegionEnd:
3870 case SnapToRegionSync:
3871 case SnapToRegionBoundary:
3881 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3885 ret = nudge_clock->current_duration (pos);
3886 next = ret + 1; /* XXXX fix me */
3892 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3894 ArdourDialog dialog (_("Playlist Deletion"));
3895 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3896 "If it is kept, its audio files will not be cleaned.\n"
3897 "If it is deleted, audio files used by it alone will be cleaned."),
3900 dialog.set_position (WIN_POS_CENTER);
3901 dialog.get_vbox()->pack_start (label);
3905 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3906 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3907 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3909 switch (dialog.run ()) {
3910 case RESPONSE_ACCEPT:
3911 /* delete the playlist */
3915 case RESPONSE_REJECT:
3916 /* keep the playlist */
3928 Editor::audio_region_selection_covers (framepos_t where)
3930 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3931 if ((*a)->region()->covers (where)) {
3940 Editor::prepare_for_cleanup ()
3942 cut_buffer->clear_regions ();
3943 cut_buffer->clear_playlists ();
3945 selection->clear_regions ();
3946 selection->clear_playlists ();
3948 _regions->suspend_redisplay ();
3952 Editor::finish_cleanup ()
3954 _regions->resume_redisplay ();
3958 Editor::transport_loop_location()
3961 return _session->locations()->auto_loop_location();
3968 Editor::transport_punch_location()
3971 return _session->locations()->auto_punch_location();
3978 Editor::control_layout_scroll (GdkEventScroll* ev)
3980 if (Keyboard::some_magic_widget_has_focus()) {
3984 switch (ev->direction) {
3986 scroll_tracks_up_line ();
3990 case GDK_SCROLL_DOWN:
3991 scroll_tracks_down_line ();
3995 /* no left/right handling yet */
4003 Editor::session_state_saved (string)
4006 _snapshots->redisplay ();
4010 Editor::update_tearoff_visibility()
4012 bool visible = Config->get_keep_tearoffs();
4013 _mouse_mode_tearoff->set_visible (visible);
4014 _tools_tearoff->set_visible (visible);
4015 _zoom_tearoff->set_visible (visible);
4019 Editor::maximise_editing_space ()
4031 Editor::restore_editing_space ()
4043 * Make new playlists for a given track and also any others that belong
4044 * to the same active route group with the `select' property.
4049 Editor::new_playlists (TimeAxisView* v)
4051 begin_reversible_command (_("new playlists"));
4052 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4053 _session->playlists->get (playlists);
4054 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4055 commit_reversible_command ();
4059 * Use a copy of the current playlist for a given track and also any others that belong
4060 * to the same active route group with the `select' property.
4065 Editor::copy_playlists (TimeAxisView* v)
4067 begin_reversible_command (_("copy playlists"));
4068 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4069 _session->playlists->get (playlists);
4070 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4071 commit_reversible_command ();
4074 /** Clear the current playlist for a given track and also any others that belong
4075 * to the same active route group with the `select' property.
4080 Editor::clear_playlists (TimeAxisView* v)
4082 begin_reversible_command (_("clear playlists"));
4083 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4084 _session->playlists->get (playlists);
4085 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4086 commit_reversible_command ();
4090 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4092 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4096 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4098 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4102 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4104 atv.clear_playlist ();
4108 Editor::on_key_press_event (GdkEventKey* ev)
4110 return key_press_focus_accelerator_handler (*this, ev);
4114 Editor::on_key_release_event (GdkEventKey* ev)
4116 return Gtk::Window::on_key_release_event (ev);
4117 // return key_press_focus_accelerator_handler (*this, ev);
4120 /** Queue up a change to the viewport x origin.
4121 * @param frame New x origin.
4124 Editor::reset_x_origin (framepos_t frame)
4126 pending_visual_change.add (VisualChange::TimeOrigin);
4127 pending_visual_change.time_origin = frame;
4128 ensure_visual_change_idle_handler ();
4132 Editor::reset_y_origin (double y)
4134 pending_visual_change.add (VisualChange::YOrigin);
4135 pending_visual_change.y_origin = y;
4136 ensure_visual_change_idle_handler ();
4140 Editor::reset_zoom (double fpp)
4142 clamp_samples_per_pixel (fpp);
4144 if (fpp == samples_per_pixel) {
4148 pending_visual_change.add (VisualChange::ZoomLevel);
4149 pending_visual_change.samples_per_pixel = fpp;
4150 ensure_visual_change_idle_handler ();
4154 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4156 reset_x_origin (frame);
4159 if (!no_save_visual) {
4160 undo_visual_stack.push_back (current_visual_state(false));
4164 Editor::VisualState::VisualState (bool with_tracks)
4165 : gui_state (with_tracks ? new GUIObjectState : 0)
4169 Editor::VisualState::~VisualState ()
4174 Editor::VisualState*
4175 Editor::current_visual_state (bool with_tracks)
4177 VisualState* vs = new VisualState (with_tracks);
4178 vs->y_position = vertical_adjustment.get_value();
4179 vs->samples_per_pixel = samples_per_pixel;
4180 vs->leftmost_frame = leftmost_frame;
4181 vs->zoom_focus = zoom_focus;
4184 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4191 Editor::undo_visual_state ()
4193 if (undo_visual_stack.empty()) {
4197 VisualState* vs = undo_visual_stack.back();
4198 undo_visual_stack.pop_back();
4201 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4203 use_visual_state (*vs);
4207 Editor::redo_visual_state ()
4209 if (redo_visual_stack.empty()) {
4213 VisualState* vs = redo_visual_stack.back();
4214 redo_visual_stack.pop_back();
4216 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4218 use_visual_state (*vs);
4222 Editor::swap_visual_state ()
4224 if (undo_visual_stack.empty()) {
4225 redo_visual_state ();
4227 undo_visual_state ();
4232 Editor::use_visual_state (VisualState& vs)
4234 PBD::Unwinder<bool> nsv (no_save_visual, true);
4236 _routes->suspend_redisplay ();
4238 vertical_adjustment.set_value (vs.y_position);
4240 set_zoom_focus (vs.zoom_focus);
4241 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4244 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4246 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4247 (*i)->reset_visual_state ();
4251 _routes->update_visibility ();
4252 _routes->resume_redisplay ();
4255 /** This is the core function that controls the zoom level of the canvas. It is called
4256 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4257 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4260 Editor::set_samples_per_pixel (double fpp)
4263 tempo_lines->tempo_map_changed();
4266 samples_per_pixel = fpp;
4268 /* convert fpu to frame count */
4270 framepos_t frames = (framepos_t) floor (samples_per_pixel * _visible_canvas_width);
4272 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4273 zoom_range_clock->set (frames);
4276 bool const showing_time_selection = selection->time.length() > 0;
4278 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4279 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4280 (*i)->reshow_selection (selection->time);
4284 ZoomChanged (); /* EMIT_SIGNAL */
4286 //reset_scrolling_region ();
4288 if (playhead_cursor) {
4289 playhead_cursor->set_position (playhead_cursor->current_frame ());
4292 refresh_location_display();
4293 _summary->set_overlays_dirty ();
4295 update_marker_labels ();
4301 Editor::queue_visual_videotimeline_update ()
4304 * pending_visual_change.add (VisualChange::VideoTimeline);
4305 * or maybe even more specific: which videotimeline-image
4306 * currently it calls update_video_timeline() to update
4307 * _all outdated_ images on the video-timeline.
4308 * see 'exposeimg()' in video_image_frame.cc
4310 ensure_visual_change_idle_handler ();
4314 Editor::ensure_visual_change_idle_handler ()
4316 if (pending_visual_change.idle_handler_id < 0) {
4317 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4318 pending_visual_change.being_handled = false;
4323 Editor::_idle_visual_changer (void* arg)
4325 return static_cast<Editor*>(arg)->idle_visual_changer ();
4329 Editor::idle_visual_changer ()
4331 /* set_horizontal_position() below (and maybe other calls) call
4332 gtk_main_iteration(), so it's possible that a signal will be handled
4333 half-way through this method. If this signal wants an
4334 idle_visual_changer we must schedule another one after this one, so
4335 mark the idle_handler_id as -1 here to allow that. Also make a note
4336 that we are doing the visual change, so that changes in response to
4337 super-rapid-screen-update can be dropped if we are still processing
4341 pending_visual_change.idle_handler_id = -1;
4342 pending_visual_change.being_handled = true;
4344 VisualChange::Type p = pending_visual_change.pending;
4345 pending_visual_change.pending = (VisualChange::Type) 0;
4347 double const last_time_origin = horizontal_position ();
4349 if (p & VisualChange::ZoomLevel) {
4350 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4352 compute_fixed_ruler_scale ();
4354 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4355 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4357 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4358 current_bbt_points_begin, current_bbt_points_end);
4359 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4360 current_bbt_points_begin, current_bbt_points_end);
4361 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4364 if (p & VisualChange::ZoomLevel) {
4365 update_video_timeline();
4368 if (p & VisualChange::TimeOrigin) {
4369 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4372 if (p & VisualChange::YOrigin) {
4373 vertical_adjustment.set_value (pending_visual_change.y_origin);
4376 if (last_time_origin == horizontal_position ()) {
4377 /* changed signal not emitted */
4378 update_fixed_rulers ();
4379 redisplay_tempo (true);
4382 if (!(p & VisualChange::ZoomLevel)) {
4383 update_video_timeline();
4386 _summary->set_overlays_dirty ();
4388 pending_visual_change.being_handled = false;
4389 return 0; /* this is always a one-shot call */
4392 struct EditorOrderTimeAxisSorter {
4393 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4394 return a->order () < b->order ();
4399 Editor::sort_track_selection (TrackViewList& sel)
4401 EditorOrderTimeAxisSorter cmp;
4406 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4409 framepos_t where = 0;
4410 EditPoint ep = _edit_point;
4412 if (from_context_menu && (ep == EditAtMouse)) {
4413 return window_event_frame (&context_click_event, 0, 0);
4416 if (entered_marker) {
4417 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4418 return entered_marker->position();
4421 if (ignore_playhead && ep == EditAtPlayhead) {
4422 ep = EditAtSelectedMarker;
4426 case EditAtPlayhead:
4427 where = _session->audible_frame();
4428 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4431 case EditAtSelectedMarker:
4432 if (!selection->markers.empty()) {
4434 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4437 where = loc->start();
4441 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4449 if (!mouse_frame (where, ignored)) {
4450 /* XXX not right but what can we do ? */
4454 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4462 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4464 if (!_session) return;
4466 begin_reversible_command (cmd);
4470 if ((tll = transport_loop_location()) == 0) {
4471 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4472 XMLNode &before = _session->locations()->get_state();
4473 _session->locations()->add (loc, true);
4474 _session->set_auto_loop_location (loc);
4475 XMLNode &after = _session->locations()->get_state();
4476 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4478 XMLNode &before = tll->get_state();
4479 tll->set_hidden (false, this);
4480 tll->set (start, end);
4481 XMLNode &after = tll->get_state();
4482 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4485 commit_reversible_command ();
4489 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4491 if (!_session) return;
4493 begin_reversible_command (cmd);
4497 if ((tpl = transport_punch_location()) == 0) {
4498 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4499 XMLNode &before = _session->locations()->get_state();
4500 _session->locations()->add (loc, true);
4501 _session->set_auto_loop_location (loc);
4502 XMLNode &after = _session->locations()->get_state();
4503 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4506 XMLNode &before = tpl->get_state();
4507 tpl->set_hidden (false, this);
4508 tpl->set (start, end);
4509 XMLNode &after = tpl->get_state();
4510 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4513 commit_reversible_command ();
4516 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4517 * @param rs List to which found regions are added.
4518 * @param where Time to look at.
4519 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4522 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4524 const TrackViewList* tracks;
4527 tracks = &track_views;
4532 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4534 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4537 boost::shared_ptr<Track> tr;
4538 boost::shared_ptr<Playlist> pl;
4540 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4542 boost::shared_ptr<RegionList> regions = pl->regions_at (
4543 (framepos_t) floor ( (double) where * tr->speed()));
4545 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4546 RegionView* rv = rtv->view()->find_view (*i);
4557 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4559 const TrackViewList* tracks;
4562 tracks = &track_views;
4567 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4568 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4570 boost::shared_ptr<Track> tr;
4571 boost::shared_ptr<Playlist> pl;
4573 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4575 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4576 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4578 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4580 RegionView* rv = rtv->view()->find_view (*i);
4591 /** Get regions using the following method:
4593 * Make a region list using the selected regions, unless
4594 * the edit point is `mouse' and the mouse is over an unselected
4595 * region. In this case, use just that region.
4597 * If the edit point is not 'mouse', and there are no regions selected,
4598 * search the list of selected tracks and return regions that are under
4599 * the edit point on these tracks. If there are no selected tracks and
4600 * 'No Selection = All Tracks' is active, search all tracks,
4602 * The rationale here is that the mouse edit point is special in that
4603 * its position describes both a time and a track; the other edit
4604 * modes only describe a time. Hence if the edit point is `mouse' we
4605 * ignore selected tracks, as we assume the user means something by
4606 * pointing at a particular track. Also in this case we take note of
4607 * the region directly under the edit point, as there is always just one
4608 * (rather than possibly several with non-mouse edit points).
4612 Editor::get_regions_from_selection_and_edit_point ()
4614 RegionSelection regions;
4616 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4617 regions.add (entered_regionview);
4619 regions = selection->regions;
4623 if (regions.empty() && _edit_point != EditAtMouse) {
4624 TrackViewList tracks = selection->tracks;
4626 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4627 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4628 * is enabled, so consider all tracks
4630 tracks = track_views;
4633 if (!tracks.empty()) {
4634 /* no region selected or entered, but some selected tracks:
4635 * act on all regions on the selected tracks at the edit point
4637 framepos_t const where = get_preferred_edit_position ();
4638 get_regions_at(regions, where, tracks);
4644 /** Start with regions that are selected, or the entered regionview if none are selected.
4645 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4646 * of the regions that we started with.
4650 Editor::get_regions_from_selection_and_entered ()
4652 RegionSelection regions = selection->regions;
4654 if (regions.empty() && entered_regionview) {
4655 regions.add (entered_regionview);
4662 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4664 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4666 RouteTimeAxisView* tatv;
4668 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4670 boost::shared_ptr<Playlist> pl;
4671 vector<boost::shared_ptr<Region> > results;
4673 boost::shared_ptr<Track> tr;
4675 if ((tr = tatv->track()) == 0) {
4680 if ((pl = (tr->playlist())) != 0) {
4681 if (src_comparison) {
4682 pl->get_source_equivalent_regions (region, results);
4684 pl->get_region_list_equivalent_regions (region, results);
4688 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4689 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4690 regions.push_back (marv);
4699 Editor::show_rhythm_ferret ()
4701 if (rhythm_ferret == 0) {
4702 rhythm_ferret = new RhythmFerret(*this);
4705 rhythm_ferret->set_session (_session);
4706 rhythm_ferret->show ();
4707 rhythm_ferret->present ();
4711 Editor::first_idle ()
4713 MessageDialog* dialog = 0;
4715 if (track_views.size() > 1) {
4716 dialog = new MessageDialog (
4718 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4722 ARDOUR_UI::instance()->flush_pending ();
4725 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4729 // first idle adds route children (automation tracks), so we need to redisplay here
4730 _routes->redisplay ();
4737 Editor::_idle_resize (gpointer arg)
4739 return ((Editor*)arg)->idle_resize ();
4743 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4745 if (resize_idle_id < 0) {
4746 resize_idle_id = g_idle_add (_idle_resize, this);
4747 _pending_resize_amount = 0;
4750 /* make a note of the smallest resulting height, so that we can clamp the
4751 lower limit at TimeAxisView::hSmall */
4753 int32_t min_resulting = INT32_MAX;
4755 _pending_resize_amount += h;
4756 _pending_resize_view = view;
4758 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4760 if (selection->tracks.contains (_pending_resize_view)) {
4761 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4762 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4766 if (min_resulting < 0) {
4771 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4772 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4776 /** Handle pending resizing of tracks */
4778 Editor::idle_resize ()
4780 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4782 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4783 selection->tracks.contains (_pending_resize_view)) {
4785 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4786 if (*i != _pending_resize_view) {
4787 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4792 _pending_resize_amount = 0;
4793 _group_tabs->set_dirty ();
4794 resize_idle_id = -1;
4802 ENSURE_GUI_THREAD (*this, &Editor::located);
4805 playhead_cursor->set_position (_session->audible_frame ());
4806 if (_follow_playhead && !_pending_initial_locate) {
4807 reset_x_origin_to_follow_playhead ();
4811 _pending_locate_request = false;
4812 _pending_initial_locate = false;
4816 Editor::region_view_added (RegionView *)
4818 _summary->set_dirty ();
4822 Editor::region_view_removed ()
4824 _summary->set_dirty ();
4828 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4830 TrackViewList::const_iterator j = track_views.begin ();
4831 while (j != track_views.end()) {
4832 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4833 if (rtv && rtv->route() == r) {
4844 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4848 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4849 TimeAxisView* tv = axis_view_from_route (*i);
4859 Editor::add_routes (RouteList& routes)
4861 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4863 RouteTimeAxisView *rtv;
4864 list<RouteTimeAxisView*> new_views;
4866 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4867 boost::shared_ptr<Route> route = (*x);
4869 if (route->is_auditioner() || route->is_monitor()) {
4873 DataType dt = route->input()->default_type();
4875 if (dt == ARDOUR::DataType::AUDIO) {
4876 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4877 rtv->set_route (route);
4878 } else if (dt == ARDOUR::DataType::MIDI) {
4879 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4880 rtv->set_route (route);
4882 throw unknown_type();
4885 new_views.push_back (rtv);
4886 track_views.push_back (rtv);
4888 rtv->effective_gain_display ();
4890 if (internal_editing()) {
4891 rtv->enter_internal_edit_mode ();
4893 rtv->leave_internal_edit_mode ();
4896 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4897 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4900 _routes->routes_added (new_views);
4901 _summary->routes_added (new_views);
4903 if (show_editor_mixer_when_tracks_arrive) {
4904 show_editor_mixer (true);
4907 editor_list_button.set_sensitive (true);
4911 Editor::timeaxisview_deleted (TimeAxisView *tv)
4913 if (_session && _session->deletion_in_progress()) {
4914 /* the situation is under control */
4918 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4920 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4922 _routes->route_removed (tv);
4924 if (tv == entered_track) {
4928 TimeAxisView::Children c = tv->get_child_list ();
4929 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4930 if (entered_track == i->get()) {
4935 /* remove it from the list of track views */
4937 TrackViewList::iterator i;
4939 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4940 i = track_views.erase (i);
4943 /* update whatever the current mixer strip is displaying, if revelant */
4945 boost::shared_ptr<Route> route;
4948 route = rtav->route ();
4951 if (current_mixer_strip && current_mixer_strip->route() == route) {
4953 TimeAxisView* next_tv;
4955 if (track_views.empty()) {
4957 } else if (i == track_views.end()) {
4958 next_tv = track_views.front();
4965 set_selected_mixer_strip (*next_tv);
4967 /* make the editor mixer strip go away setting the
4968 * button to inactive (which also unticks the menu option)
4971 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4977 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4979 if (apply_to_selection) {
4980 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4982 TrackSelection::iterator j = i;
4985 hide_track_in_display (*i, false);
4990 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4992 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4993 // this will hide the mixer strip
4994 set_selected_mixer_strip (*tv);
4997 _routes->hide_track_in_display (*tv);
5002 Editor::sync_track_view_list_and_routes ()
5004 track_views = TrackViewList (_routes->views ());
5006 _summary->set_dirty ();
5007 _group_tabs->set_dirty ();
5009 return false; // do not call again (until needed)
5013 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5015 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5020 /** Find a RouteTimeAxisView by the ID of its route */
5022 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5024 RouteTimeAxisView* v;
5026 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5027 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5028 if(v->route()->id() == id) {
5038 Editor::fit_route_group (RouteGroup *g)
5040 TrackViewList ts = axis_views_from_routes (g->route_list ());
5045 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5047 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5050 _session->cancel_audition ();
5054 if (_session->is_auditioning()) {
5055 _session->cancel_audition ();
5056 if (r == last_audition_region) {
5061 _session->audition_region (r);
5062 last_audition_region = r;
5067 Editor::hide_a_region (boost::shared_ptr<Region> r)
5069 r->set_hidden (true);
5073 Editor::show_a_region (boost::shared_ptr<Region> r)
5075 r->set_hidden (false);
5079 Editor::audition_region_from_region_list ()
5081 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5085 Editor::hide_region_from_region_list ()
5087 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5091 Editor::show_region_in_region_list ()
5093 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5097 Editor::step_edit_status_change (bool yn)
5100 start_step_editing ();
5102 stop_step_editing ();
5107 Editor::start_step_editing ()
5109 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5113 Editor::stop_step_editing ()
5115 step_edit_connection.disconnect ();
5119 Editor::check_step_edit ()
5121 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5122 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5124 mtv->check_step_edit ();
5128 return true; // do it again, till we stop
5132 Editor::scroll_press (Direction dir)
5134 ++_scroll_callbacks;
5136 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5137 /* delay the first auto-repeat */
5143 scroll_backward (1);
5151 scroll_tracks_up_line ();
5155 scroll_tracks_down_line ();
5159 /* do hacky auto-repeat */
5160 if (!_scroll_connection.connected ()) {
5162 _scroll_connection = Glib::signal_timeout().connect (
5163 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5166 _scroll_callbacks = 0;
5173 Editor::scroll_release ()
5175 _scroll_connection.disconnect ();
5178 /** Queue a change for the Editor viewport x origin to follow the playhead */
5180 Editor::reset_x_origin_to_follow_playhead ()
5182 framepos_t const frame = playhead_cursor->current_frame ();
5184 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5186 if (_session->transport_speed() < 0) {
5188 if (frame > (current_page_samples() / 2)) {
5189 center_screen (frame-(current_page_samples()/2));
5191 center_screen (current_page_samples()/2);
5198 if (frame < leftmost_frame) {
5200 if (_session->transport_rolling()) {
5201 /* rolling; end up with the playhead at the right of the page */
5202 l = frame - current_page_samples ();
5204 /* not rolling: end up with the playhead 1/4 of the way along the page */
5205 l = frame - current_page_samples() / 4;
5209 if (_session->transport_rolling()) {
5210 /* rolling: end up with the playhead on the left of the page */
5213 /* not rolling: end up with the playhead 3/4 of the way along the page */
5214 l = frame - 3 * current_page_samples() / 4;
5222 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5228 Editor::super_rapid_screen_update ()
5230 if (!_session || !_session->engine().running()) {
5234 /* METERING / MIXER STRIPS */
5236 /* update track meters, if required */
5237 if (is_mapped() && meters_running) {
5238 RouteTimeAxisView* rtv;
5239 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5240 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5241 rtv->fast_update ();
5246 /* and any current mixer strip */
5247 if (current_mixer_strip) {
5248 current_mixer_strip->fast_update ();
5251 /* PLAYHEAD AND VIEWPORT */
5253 framepos_t const frame = _session->audible_frame();
5255 /* There are a few reasons why we might not update the playhead / viewport stuff:
5257 * 1. we don't update things when there's a pending locate request, otherwise
5258 * when the editor requests a locate there is a chance that this method
5259 * will move the playhead before the locate request is processed, causing
5261 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5262 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5265 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5267 last_update_frame = frame;
5269 if (!_dragging_playhead) {
5270 playhead_cursor->set_position (frame);
5273 if (!_stationary_playhead) {
5275 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5276 /* We only do this if we aren't already
5277 handling a visual change (ie if
5278 pending_visual_change.being_handled is
5279 false) so that these requests don't stack
5280 up there are too many of them to handle in
5283 reset_x_origin_to_follow_playhead ();
5288 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5292 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5293 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5294 if (target <= 0.0) {
5297 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5298 target = (target * 0.15) + (current * 0.85);
5304 set_horizontal_position (current);
5313 Editor::session_going_away ()
5315 _have_idled = false;
5317 _session_connections.drop_connections ();
5319 super_rapid_screen_update_connection.disconnect ();
5321 selection->clear ();
5322 cut_buffer->clear ();
5324 clicked_regionview = 0;
5325 clicked_axisview = 0;
5326 clicked_routeview = 0;
5327 entered_regionview = 0;
5329 last_update_frame = 0;
5332 playhead_cursor->hide ();
5334 /* rip everything out of the list displays */
5338 _route_groups->clear ();
5340 /* do this first so that deleting a track doesn't reset cms to null
5341 and thus cause a leak.
5344 if (current_mixer_strip) {
5345 if (current_mixer_strip->get_parent() != 0) {
5346 global_hpacker.remove (*current_mixer_strip);
5348 delete current_mixer_strip;
5349 current_mixer_strip = 0;
5352 /* delete all trackviews */
5354 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5357 track_views.clear ();
5359 zoom_range_clock->set_session (0);
5360 nudge_clock->set_session (0);
5362 editor_list_button.set_active(false);
5363 editor_list_button.set_sensitive(false);
5365 /* clear tempo/meter rulers */
5366 remove_metric_marks ();
5368 clear_marker_display ();
5370 stop_step_editing ();
5372 /* get rid of any existing editor mixer strip */
5374 WindowTitle title(Glib::get_application_name());
5375 title += _("Editor");
5377 set_title (title.get_string());
5379 SessionHandlePtr::session_going_away ();
5384 Editor::show_editor_list (bool yn)
5387 _the_notebook.show ();
5389 _the_notebook.hide ();
5394 Editor::change_region_layering_order (bool from_context_menu)
5396 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5398 if (!clicked_routeview) {
5399 if (layering_order_editor) {
5400 layering_order_editor->hide ();
5405 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5411 boost::shared_ptr<Playlist> pl = track->playlist();
5417 if (layering_order_editor == 0) {
5418 layering_order_editor = new RegionLayeringOrderEditor (*this);
5419 layering_order_editor->set_position (WIN_POS_MOUSE);
5422 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5423 layering_order_editor->maybe_present ();
5427 Editor::update_region_layering_order_editor ()
5429 if (layering_order_editor && layering_order_editor->is_visible ()) {
5430 change_region_layering_order (true);
5435 Editor::setup_fade_images ()
5437 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5438 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5439 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5440 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5441 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5443 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5444 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5445 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5446 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5447 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5449 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5450 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5451 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5452 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5453 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5455 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5456 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5457 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5458 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5459 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5463 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5465 Editor::action_menu_item (std::string const & name)
5467 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5470 return *manage (a->create_menu_item ());
5474 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5476 EventBox* b = manage (new EventBox);
5477 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5478 Label* l = manage (new Label (name));
5482 _the_notebook.append_page (widget, *b);
5486 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5488 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5489 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5492 if (ev->type == GDK_2BUTTON_PRESS) {
5494 /* double-click on a notebook tab shrinks or expands the notebook */
5496 if (_notebook_shrunk) {
5497 if (pre_notebook_shrink_pane_width) {
5498 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5500 _notebook_shrunk = false;
5502 pre_notebook_shrink_pane_width = edit_pane.get_position();
5504 /* this expands the LHS of the edit pane to cover the notebook
5505 PAGE but leaves the tabs visible.
5507 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5508 _notebook_shrunk = true;
5516 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5518 using namespace Menu_Helpers;
5520 MenuList& items = _control_point_context_menu.items ();
5523 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5524 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5525 if (!can_remove_control_point (item)) {
5526 items.back().set_sensitive (false);
5529 _control_point_context_menu.popup (event->button.button, event->button.time);
5533 Editor::shift_key_released ()
5535 _stepping_axis_view = 0;