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"
48 #include "pbd/timersub.h"
50 #include <glibmm/miscutils.h>
51 #include <glibmm/uriutils.h>
52 #include <gtkmm/image.h>
53 #include <gdkmm/color.h>
54 #include <gdkmm/bitmap.h>
56 #include <gtkmm/menu.h>
57 #include <gtkmm/menuitem.h>
59 #include "gtkmm2ext/bindings.h"
60 #include "gtkmm2ext/grouped_buttons.h"
61 #include "gtkmm2ext/gtk_ui.h"
62 #include "gtkmm2ext/tearoff.h"
63 #include "gtkmm2ext/utils.h"
64 #include "gtkmm2ext/window_title.h"
65 #include "gtkmm2ext/choice.h"
66 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
68 #include "ardour/audio_track.h"
69 #include "ardour/audioengine.h"
70 #include "ardour/audioregion.h"
71 #include "ardour/location.h"
72 #include "ardour/profile.h"
73 #include "ardour/route_group.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/tempo.h"
76 #include "ardour/utils.h"
78 #include "canvas/debug.h"
79 #include "canvas/text.h"
81 #include "control_protocol/control_protocol.h"
85 #include "analysis_window.h"
86 #include "audio_clock.h"
87 #include "audio_region_view.h"
88 #include "audio_streamview.h"
89 #include "audio_time_axis.h"
90 #include "automation_time_axis.h"
91 #include "bundle_manager.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
128 using namespace ARDOUR;
129 using namespace ARDOUR_UI_UTILS;
132 using namespace Glib;
133 using namespace Gtkmm2ext;
134 using namespace Editing;
136 using PBD::internationalize;
138 using Gtkmm2ext::Keyboard;
140 const double Editor::timebar_height = 15.0;
142 static const gchar *_snap_type_strings[] = {
144 N_("Timecode Frames"),
145 N_("Timecode Seconds"),
146 N_("Timecode Minutes"),
176 static const gchar *_snap_mode_strings[] = {
183 static const gchar *_edit_point_strings[] = {
190 static const gchar *_zoom_focus_strings[] = {
200 #ifdef USE_RUBBERBAND
201 static const gchar *_rb_opt_strings[] = {
204 N_("Balanced multitimbral mixture"),
205 N_("Unpitched percussion with stable notes"),
206 N_("Crisp monophonic instrumental"),
207 N_("Unpitched solo percussion"),
208 N_("Resample without preserving pitch"),
214 pane_size_watcher (Paned* pane)
216 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
220 Quartz: impossible to access
222 so stop that by preventing it from ever getting too narrow. 35
223 pixels is basically a rough guess at the tab width.
228 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
230 gint pos = pane->get_position ();
232 if (pos > max_width_of_lhs) {
233 pane->set_position (max_width_of_lhs);
238 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
240 /* time display buttons */
241 , minsec_label (_("Mins:Secs"))
242 , bbt_label (_("Bars:Beats"))
243 , timecode_label (_("Timecode"))
244 , samples_label (_("Samples"))
245 , tempo_label (_("Tempo"))
246 , meter_label (_("Meter"))
247 , mark_label (_("Location Markers"))
248 , range_mark_label (_("Range Markers"))
249 , transport_mark_label (_("Loop/Punch Ranges"))
250 , cd_mark_label (_("CD Markers"))
251 , videotl_label (_("Video Timeline"))
252 , edit_packer (4, 4, true)
254 /* the values here don't matter: layout widgets
255 reset them as needed.
258 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
259 , horizontal_adjustment (0.0, 0.0, 1e16)
260 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
262 , controls_layout (unused_adjustment, vertical_adjustment)
264 /* tool bar related */
266 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
267 , toolbar_selection_clock_table (2,3)
268 , _mouse_mode_tearoff (0)
269 , automation_mode_button (_("mode"))
273 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
277 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
278 , meters_running(false)
279 , _pending_locate_request (false)
280 , _pending_initial_locate (false)
281 , _last_cut_copy_source_track (0)
283 , _region_selection_change_updates_region_list (true)
284 , _following_mixer_selection (false)
285 , _control_point_toggled_on_press (false)
286 , _stepping_axis_view (0)
290 /* we are a singleton */
292 PublicEditor::_instance = this;
296 selection = new Selection (this);
297 cut_buffer = new Selection (this);
299 clicked_regionview = 0;
300 clicked_axisview = 0;
301 clicked_routeview = 0;
302 clicked_control_point = 0;
303 last_update_frame = 0;
304 pre_press_cursor = 0;
305 _drags = new DragManager (this);
308 current_mixer_strip = 0;
311 snap_type_strings = I18N (_snap_type_strings);
312 snap_mode_strings = I18N (_snap_mode_strings);
313 zoom_focus_strings = I18N (_zoom_focus_strings);
314 edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316 rb_opt_strings = I18N (_rb_opt_strings);
320 build_edit_mode_menu();
321 build_zoom_focus_menu();
322 build_track_count_menu();
323 build_snap_mode_menu();
324 build_snap_type_menu();
325 build_edit_point_menu();
327 snap_threshold = 5.0;
328 bbt_beat_subdivision = 4;
329 _visible_canvas_width = 0;
330 _visible_canvas_height = 0;
331 autoscroll_horizontal_allowed = false;
332 autoscroll_vertical_allowed = false;
337 current_interthread_info = 0;
338 _show_measures = true;
340 show_gain_after_trim = false;
342 have_pending_keyboard_selection = false;
343 _follow_playhead = true;
344 _stationary_playhead = false;
345 editor_ruler_menu = 0;
346 no_ruler_shown_update = false;
348 range_marker_menu = 0;
349 marker_menu_item = 0;
350 tempo_or_meter_marker_menu = 0;
351 transport_marker_menu = 0;
352 new_transport_marker_menu = 0;
353 editor_mixer_strip_width = Wide;
354 show_editor_mixer_when_tracks_arrive = false;
355 region_edit_menu_split_multichannel_item = 0;
356 region_edit_menu_split_item = 0;
359 current_stepping_trackview = 0;
361 entered_regionview = 0;
363 clear_entered_track = false;
366 button_release_can_deselect = true;
367 _dragging_playhead = false;
368 _dragging_edit_point = false;
369 select_new_marker = false;
371 layering_order_editor = 0;
372 no_save_visual = false;
374 within_track_canvas = false;
376 scrubbing_direction = 0;
380 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
381 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
382 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
383 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
384 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
386 zoom_focus = ZoomFocusLeft;
387 _edit_point = EditAtMouse;
388 _internal_editing = false;
389 current_canvas_cursor = 0;
390 _visible_track_count = 16;
392 samples_per_pixel = 2048; /* too early to use reset_zoom () */
394 _scroll_callbacks = 0;
396 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
398 bbt_label.set_name ("EditorRulerLabel");
399 bbt_label.set_size_request (-1, (int)timebar_height);
400 bbt_label.set_alignment (1.0, 0.5);
401 bbt_label.set_padding (5,0);
403 bbt_label.set_no_show_all();
404 minsec_label.set_name ("EditorRulerLabel");
405 minsec_label.set_size_request (-1, (int)timebar_height);
406 minsec_label.set_alignment (1.0, 0.5);
407 minsec_label.set_padding (5,0);
408 minsec_label.hide ();
409 minsec_label.set_no_show_all();
410 timecode_label.set_name ("EditorRulerLabel");
411 timecode_label.set_size_request (-1, (int)timebar_height);
412 timecode_label.set_alignment (1.0, 0.5);
413 timecode_label.set_padding (5,0);
414 timecode_label.hide ();
415 timecode_label.set_no_show_all();
416 samples_label.set_name ("EditorRulerLabel");
417 samples_label.set_size_request (-1, (int)timebar_height);
418 samples_label.set_alignment (1.0, 0.5);
419 samples_label.set_padding (5,0);
420 samples_label.hide ();
421 samples_label.set_no_show_all();
423 tempo_label.set_name ("EditorRulerLabel");
424 tempo_label.set_size_request (-1, (int)timebar_height);
425 tempo_label.set_alignment (1.0, 0.5);
426 tempo_label.set_padding (5,0);
428 tempo_label.set_no_show_all();
430 meter_label.set_name ("EditorRulerLabel");
431 meter_label.set_size_request (-1, (int)timebar_height);
432 meter_label.set_alignment (1.0, 0.5);
433 meter_label.set_padding (5,0);
435 meter_label.set_no_show_all();
437 if (Profile->get_trx()) {
438 mark_label.set_text (_("Markers"));
440 mark_label.set_name ("EditorRulerLabel");
441 mark_label.set_size_request (-1, (int)timebar_height);
442 mark_label.set_alignment (1.0, 0.5);
443 mark_label.set_padding (5,0);
445 mark_label.set_no_show_all();
447 cd_mark_label.set_name ("EditorRulerLabel");
448 cd_mark_label.set_size_request (-1, (int)timebar_height);
449 cd_mark_label.set_alignment (1.0, 0.5);
450 cd_mark_label.set_padding (5,0);
451 cd_mark_label.hide();
452 cd_mark_label.set_no_show_all();
454 videotl_bar_height = 4;
455 videotl_label.set_name ("EditorRulerLabel");
456 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
457 videotl_label.set_alignment (1.0, 0.5);
458 videotl_label.set_padding (5,0);
459 videotl_label.hide();
460 videotl_label.set_no_show_all();
462 range_mark_label.set_name ("EditorRulerLabel");
463 range_mark_label.set_size_request (-1, (int)timebar_height);
464 range_mark_label.set_alignment (1.0, 0.5);
465 range_mark_label.set_padding (5,0);
466 range_mark_label.hide();
467 range_mark_label.set_no_show_all();
469 transport_mark_label.set_name ("EditorRulerLabel");
470 transport_mark_label.set_size_request (-1, (int)timebar_height);
471 transport_mark_label.set_alignment (1.0, 0.5);
472 transport_mark_label.set_padding (5,0);
473 transport_mark_label.hide();
474 transport_mark_label.set_no_show_all();
476 initialize_canvas ();
478 _summary = new EditorSummary (this);
480 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
481 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
483 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
485 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
486 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
488 edit_controls_vbox.set_spacing (0);
489 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
490 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
492 HBox* h = manage (new HBox);
493 _group_tabs = new EditorGroupTabs (this);
494 if (!ARDOUR::Profile->get_trx()) {
495 h->pack_start (*_group_tabs, PACK_SHRINK);
497 h->pack_start (edit_controls_vbox);
498 controls_layout.add (*h);
500 controls_layout.set_name ("EditControlsBase");
501 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
502 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
503 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
505 _cursors = new MouseCursors;
506 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
507 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
509 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
511 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
512 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
513 pad_line_1->set_outline_color (0xFF0000FF);
519 edit_packer.set_col_spacings (0);
520 edit_packer.set_row_spacings (0);
521 edit_packer.set_homogeneous (false);
522 edit_packer.set_border_width (0);
523 edit_packer.set_name ("EditorWindow");
525 time_bars_event_box.add (time_bars_vbox);
526 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
527 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
529 /* labels for the time bars */
530 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
532 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
534 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
536 bottom_hbox.set_border_width (2);
537 bottom_hbox.set_spacing (3);
539 _route_groups = new EditorRouteGroups (this);
540 _routes = new EditorRoutes (this);
541 _regions = new EditorRegions (this);
542 _snapshots = new EditorSnapshots (this);
543 _locations = new EditorLocations (this);
545 add_notebook_page (_("Regions"), _regions->widget ());
546 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
547 add_notebook_page (_("Snapshots"), _snapshots->widget ());
548 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
549 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
551 _the_notebook.set_show_tabs (true);
552 _the_notebook.set_scrollable (true);
553 _the_notebook.popup_disable ();
554 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
555 _the_notebook.show_all ();
557 _notebook_shrunk = false;
559 editor_summary_pane.pack1(edit_packer);
561 Button* summary_arrows_left_left = manage (new Button);
562 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
563 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
564 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
566 Button* summary_arrows_left_right = manage (new Button);
567 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
568 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
569 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
571 VBox* summary_arrows_left = manage (new VBox);
572 summary_arrows_left->pack_start (*summary_arrows_left_left);
573 summary_arrows_left->pack_start (*summary_arrows_left_right);
575 Button* summary_arrows_right_up = manage (new Button);
576 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
577 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
578 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
580 Button* summary_arrows_right_down = manage (new Button);
581 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
582 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
583 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
585 VBox* summary_arrows_right = manage (new VBox);
586 summary_arrows_right->pack_start (*summary_arrows_right_up);
587 summary_arrows_right->pack_start (*summary_arrows_right_down);
589 Frame* summary_frame = manage (new Frame);
590 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
592 summary_frame->add (*_summary);
593 summary_frame->show ();
595 _summary_hbox.pack_start (*summary_arrows_left, false, false);
596 _summary_hbox.pack_start (*summary_frame, true, true);
597 _summary_hbox.pack_start (*summary_arrows_right, false, false);
599 if (!ARDOUR::Profile->get_trx()) {
600 editor_summary_pane.pack2 (_summary_hbox);
603 edit_pane.pack1 (editor_summary_pane, true, true);
604 if (!ARDOUR::Profile->get_trx()) {
605 edit_pane.pack2 (_the_notebook, false, true);
608 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
610 /* XXX: editor_summary_pane might need similar to the edit_pane */
612 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
614 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
615 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
617 top_hbox.pack_start (toolbar_frame);
619 HBox *hbox = manage (new HBox);
620 hbox->pack_start (edit_pane, true, true);
622 global_vpacker.pack_start (top_hbox, false, false);
623 global_vpacker.pack_start (*hbox, true, true);
625 global_hpacker.pack_start (global_vpacker, true, true);
627 set_name ("EditorWindow");
628 add_accel_group (ActionManager::ui_manager->get_accel_group());
630 status_bar_hpacker.show ();
632 vpacker.pack_end (status_bar_hpacker, false, false);
633 vpacker.pack_end (global_hpacker, true, true);
635 /* register actions now so that set_state() can find them and set toggles/checks etc */
638 /* when we start using our own keybinding system for the editor, this
639 * will be uncommented
645 set_zoom_focus (zoom_focus);
646 set_visible_track_count (_visible_track_count);
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 ("nudge button");
667 // nudge_forward_button.add_elements (ArdourButton::Inset);
668 nudge_forward_button.set_image(::get_icon("nudge_right"));
670 nudge_backward_button.set_name ("nudge button");
671 // nudge_backward_button.add_elements (ArdourButton::Inset);
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().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_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());
741 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
743 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
745 _ignore_region_action = false;
746 _last_region_menu_was_main = false;
747 _popup_region_menu_item = 0;
749 _show_marker_lines = 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 ();
770 delete button_bindings;
772 delete _route_groups;
773 delete _track_canvas_viewport;
778 Editor::button_settings () const
780 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
781 XMLNode* node = find_named_node (*settings, X_("Buttons"));
784 node = new XMLNode (X_("Buttons"));
791 Editor::add_toplevel_controls (Container& cont)
793 vpacker.pack_start (cont, false, false);
798 Editor::get_smart_mode () const
800 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
804 Editor::catch_vanishing_regionview (RegionView *rv)
806 /* note: the selection will take care of the vanishing
807 audioregionview by itself.
810 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
814 if (clicked_regionview == rv) {
815 clicked_regionview = 0;
818 if (entered_regionview == rv) {
819 set_entered_regionview (0);
822 if (!_all_region_actions_sensitized) {
823 sensitize_all_region_actions (true);
828 Editor::set_entered_regionview (RegionView* rv)
830 if (rv == entered_regionview) {
834 if (entered_regionview) {
835 entered_regionview->exited ();
838 entered_regionview = rv;
840 if (entered_regionview != 0) {
841 entered_regionview->entered (internal_editing ());
844 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
845 /* This RegionView entry might have changed what region actions
846 are allowed, so sensitize them all in case a key is pressed.
848 sensitize_all_region_actions (true);
853 Editor::set_entered_track (TimeAxisView* tav)
856 entered_track->exited ();
862 entered_track->entered ();
867 Editor::show_window ()
869 if (!is_visible ()) {
872 /* XXX: this is a bit unfortunate; it would probably
873 be nicer if we could just call show () above rather
874 than needing the show_all ()
877 /* re-hide stuff if necessary */
878 editor_list_button_toggled ();
879 parameter_changed ("show-summary");
880 parameter_changed ("show-group-tabs");
881 parameter_changed ("show-zoom-tools");
883 /* now reset all audio_time_axis heights, because widgets might need
889 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
890 tv = (static_cast<TimeAxisView*>(*i));
894 if (current_mixer_strip) {
895 current_mixer_strip->hide_things ();
896 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
904 Editor::instant_save ()
906 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
911 _session->add_instant_xml(get_state());
913 Config->add_instant_xml(get_state());
918 Editor::zoom_adjustment_changed ()
924 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
925 bool clamped = clamp_samples_per_pixel (fpu);
928 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
935 Editor::control_vertical_zoom_in_all ()
937 tav_zoom_smooth (false, true);
941 Editor::control_vertical_zoom_out_all ()
943 tav_zoom_smooth (true, true);
947 Editor::control_vertical_zoom_in_selected ()
949 tav_zoom_smooth (false, false);
953 Editor::control_vertical_zoom_out_selected ()
955 tav_zoom_smooth (true, false);
959 Editor::control_view (uint32_t view)
961 goto_visual_state (view);
965 Editor::control_unselect ()
967 selection->clear_tracks ();
971 Editor::control_select (uint32_t rid, Selection::Operation op)
973 /* handles the (static) signal from the ControlProtocol class that
974 * requests setting the selected track to a given RID
981 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
987 TimeAxisView* tav = axis_view_from_route (r);
992 selection->add (tav);
994 case Selection::Toggle:
995 selection->toggle (tav);
997 case Selection::Extend:
1000 selection->set (tav);
1004 selection->clear_tracks ();
1009 Editor::control_step_tracks_up ()
1011 scroll_tracks_up_line ();
1015 Editor::control_step_tracks_down ()
1017 scroll_tracks_down_line ();
1021 Editor::control_scroll (float fraction)
1023 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1029 double step = fraction * current_page_samples();
1032 _control_scroll_target is an optional<T>
1034 it acts like a pointer to an framepos_t, with
1035 a operator conversion to boolean to check
1036 that it has a value could possibly use
1037 playhead_cursor->current_frame to store the
1038 value and a boolean in the class to know
1039 when it's out of date
1042 if (!_control_scroll_target) {
1043 _control_scroll_target = _session->transport_frame();
1044 _dragging_playhead = true;
1047 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1048 *_control_scroll_target = 0;
1049 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1050 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1052 *_control_scroll_target += (framepos_t) floor (step);
1055 /* move visuals, we'll catch up with it later */
1057 playhead_cursor->set_position (*_control_scroll_target);
1058 UpdateAllTransportClocks (*_control_scroll_target);
1060 if (*_control_scroll_target > (current_page_samples() / 2)) {
1061 /* try to center PH in window */
1062 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1068 Now we do a timeout to actually bring the session to the right place
1069 according to the playhead. This is to avoid reading disk buffers on every
1070 call to control_scroll, which is driven by ScrollTimeline and therefore
1071 probably by a control surface wheel which can generate lots of events.
1073 /* cancel the existing timeout */
1075 control_scroll_connection.disconnect ();
1077 /* add the next timeout */
1079 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1083 Editor::deferred_control_scroll (framepos_t /*target*/)
1085 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1086 // reset for next stream
1087 _control_scroll_target = boost::none;
1088 _dragging_playhead = false;
1093 Editor::access_action (std::string action_group, std::string action_item)
1099 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1102 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1110 Editor::on_realize ()
1112 Window::on_realize ();
1115 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1116 start_lock_event_timing ();
1119 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1123 Editor::start_lock_event_timing ()
1125 /* check if we should lock the GUI every 30 seconds */
1127 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1131 Editor::generic_event_handler (GdkEvent* ev)
1134 case GDK_BUTTON_PRESS:
1135 case GDK_BUTTON_RELEASE:
1136 case GDK_MOTION_NOTIFY:
1138 case GDK_KEY_RELEASE:
1139 gettimeofday (&last_event_time, 0);
1148 Editor::lock_timeout_callback ()
1150 struct timeval now, delta;
1152 gettimeofday (&now, 0);
1154 timersub (&now, &last_event_time, &delta);
1156 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1158 /* don't call again. Returning false will effectively
1159 disconnect us from the timer callback.
1161 unlock() will call start_lock_event_timing() to get things
1171 Editor::map_position_change (framepos_t frame)
1173 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1175 if (_session == 0) {
1179 if (_follow_playhead) {
1180 center_screen (frame);
1183 playhead_cursor->set_position (frame);
1187 Editor::center_screen (framepos_t frame)
1189 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1191 /* if we're off the page, then scroll.
1194 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1195 center_screen_internal (frame, page);
1200 Editor::center_screen_internal (framepos_t frame, float page)
1205 frame -= (framepos_t) page;
1210 reset_x_origin (frame);
1215 Editor::update_title ()
1217 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1220 bool dirty = _session->dirty();
1222 string session_name;
1224 if (_session->snap_name() != _session->name()) {
1225 session_name = _session->snap_name();
1227 session_name = _session->name();
1231 session_name = "*" + session_name;
1234 WindowTitle title(session_name);
1235 title += Glib::get_application_name();
1236 set_title (title.get_string());
1238 /* ::session_going_away() will have taken care of it */
1243 Editor::set_session (Session *t)
1245 SessionHandlePtr::set_session (t);
1251 zoom_range_clock->set_session (_session);
1252 _playlist_selector->set_session (_session);
1253 nudge_clock->set_session (_session);
1254 _summary->set_session (_session);
1255 _group_tabs->set_session (_session);
1256 _route_groups->set_session (_session);
1257 _regions->set_session (_session);
1258 _snapshots->set_session (_session);
1259 _routes->set_session (_session);
1260 _locations->set_session (_session);
1262 if (rhythm_ferret) {
1263 rhythm_ferret->set_session (_session);
1266 if (analysis_window) {
1267 analysis_window->set_session (_session);
1271 sfbrowser->set_session (_session);
1274 compute_fixed_ruler_scale ();
1276 /* Make sure we have auto loop and auto punch ranges */
1278 Location* loc = _session->locations()->auto_loop_location();
1280 loc->set_name (_("Loop"));
1283 loc = _session->locations()->auto_punch_location();
1286 loc->set_name (_("Punch"));
1289 refresh_location_display ();
1291 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1292 the selected Marker; this needs the LocationMarker list to be available.
1294 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1295 set_state (*node, Stateful::loading_state_version);
1297 /* catch up with the playhead */
1299 _session->request_locate (playhead_cursor->current_frame ());
1300 _pending_initial_locate = true;
1304 /* These signals can all be emitted by a non-GUI thread. Therefore the
1305 handlers for them must not attempt to directly interact with the GUI,
1306 but use PBD::Signal<T>::connect() which accepts an event loop
1307 ("context") where the handler will be asked to run.
1310 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1311 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1312 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1313 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1314 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1315 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1316 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1317 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1318 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1319 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1320 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1321 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1322 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1323 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1325 playhead_cursor->show ();
1327 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1328 Config->map_parameters (pc);
1329 _session->config.map_parameters (pc);
1331 restore_ruler_visibility ();
1332 //tempo_map_changed (PropertyChange (0));
1333 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1335 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1336 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1339 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1340 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1343 switch (_snap_type) {
1344 case SnapToRegionStart:
1345 case SnapToRegionEnd:
1346 case SnapToRegionSync:
1347 case SnapToRegionBoundary:
1348 build_region_boundary_cache ();
1355 /* register for undo history */
1356 _session->register_with_memento_command_factory(id(), this);
1358 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1360 start_updating_meters ();
1364 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1366 if (a->get_name() == "RegionMenu") {
1367 /* When the main menu's region menu is opened, we setup the actions so that they look right
1368 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1369 so we resensitize all region actions when the entered regionview or the region selection
1370 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1371 happens after the region context menu is opened. So we set a flag here, too.
1375 sensitize_the_right_region_actions ();
1376 _last_region_menu_was_main = true;
1381 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1383 using namespace Menu_Helpers;
1385 void (Editor::*emf)(FadeShape);
1386 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1389 images = &_xfade_in_images;
1390 emf = &Editor::set_fade_in_shape;
1392 images = &_xfade_out_images;
1393 emf = &Editor::set_fade_out_shape;
1398 _("Linear (for highly correlated material)"),
1399 *(*images)[FadeLinear],
1400 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1408 _("Constant power"),
1409 *(*images)[FadeConstantPower],
1410 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1418 *(*images)[FadeSymmetric],
1419 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1423 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1428 *(*images)[FadeSlow],
1429 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1432 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1437 *(*images)[FadeFast],
1438 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1441 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1444 /** Pop up a context menu for when the user clicks on a start crossfade */
1446 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1448 using namespace Menu_Helpers;
1449 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1452 MenuList& items (xfade_in_context_menu.items());
1455 if (arv->audio_region()->fade_in_active()) {
1456 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1458 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1461 items.push_back (SeparatorElem());
1462 fill_xfade_menu (items, true);
1464 xfade_in_context_menu.popup (button, time);
1467 /** Pop up a context menu for when the user clicks on an end crossfade */
1469 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1471 using namespace Menu_Helpers;
1472 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1475 MenuList& items (xfade_out_context_menu.items());
1478 if (arv->audio_region()->fade_out_active()) {
1479 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1481 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1484 items.push_back (SeparatorElem());
1485 fill_xfade_menu (items, false);
1487 xfade_out_context_menu.popup (button, time);
1491 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1493 using namespace Menu_Helpers;
1494 Menu* (Editor::*build_menu_function)();
1497 switch (item_type) {
1499 case RegionViewName:
1500 case RegionViewNameHighlight:
1501 case LeftFrameHandle:
1502 case RightFrameHandle:
1503 if (with_selection) {
1504 build_menu_function = &Editor::build_track_selection_context_menu;
1506 build_menu_function = &Editor::build_track_region_context_menu;
1511 if (with_selection) {
1512 build_menu_function = &Editor::build_track_selection_context_menu;
1514 build_menu_function = &Editor::build_track_context_menu;
1519 if (clicked_routeview->track()) {
1520 build_menu_function = &Editor::build_track_context_menu;
1522 build_menu_function = &Editor::build_track_bus_context_menu;
1527 /* probably shouldn't happen but if it does, we don't care */
1531 menu = (this->*build_menu_function)();
1532 menu->set_name ("ArdourContextMenu");
1534 /* now handle specific situations */
1536 switch (item_type) {
1538 case RegionViewName:
1539 case RegionViewNameHighlight:
1540 case LeftFrameHandle:
1541 case RightFrameHandle:
1542 if (!with_selection) {
1543 if (region_edit_menu_split_item) {
1544 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1545 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1547 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1550 if (region_edit_menu_split_multichannel_item) {
1551 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1552 region_edit_menu_split_multichannel_item->set_sensitive (true);
1554 region_edit_menu_split_multichannel_item->set_sensitive (false);
1567 /* probably shouldn't happen but if it does, we don't care */
1571 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1573 /* Bounce to disk */
1575 using namespace Menu_Helpers;
1576 MenuList& edit_items = menu->items();
1578 edit_items.push_back (SeparatorElem());
1580 switch (clicked_routeview->audio_track()->freeze_state()) {
1581 case AudioTrack::NoFreeze:
1582 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1585 case AudioTrack::Frozen:
1586 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1589 case AudioTrack::UnFrozen:
1590 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1596 if (item_type == StreamItem && clicked_routeview) {
1597 clicked_routeview->build_underlay_menu(menu);
1600 /* When the region menu is opened, we setup the actions so that they look right
1603 sensitize_the_right_region_actions ();
1604 _last_region_menu_was_main = false;
1606 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1607 menu->popup (button, time);
1611 Editor::build_track_context_menu ()
1613 using namespace Menu_Helpers;
1615 MenuList& edit_items = track_context_menu.items();
1618 add_dstream_context_items (edit_items);
1619 return &track_context_menu;
1623 Editor::build_track_bus_context_menu ()
1625 using namespace Menu_Helpers;
1627 MenuList& edit_items = track_context_menu.items();
1630 add_bus_context_items (edit_items);
1631 return &track_context_menu;
1635 Editor::build_track_region_context_menu ()
1637 using namespace Menu_Helpers;
1638 MenuList& edit_items = track_region_context_menu.items();
1641 /* we've just cleared the track region context menu, so the menu that these
1642 two items were on will have disappeared; stop them dangling.
1644 region_edit_menu_split_item = 0;
1645 region_edit_menu_split_multichannel_item = 0;
1647 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1650 boost::shared_ptr<Track> tr;
1651 boost::shared_ptr<Playlist> pl;
1653 if ((tr = rtv->track())) {
1654 add_region_context_items (edit_items, tr);
1658 add_dstream_context_items (edit_items);
1660 return &track_region_context_menu;
1664 Editor::analyze_region_selection ()
1666 if (analysis_window == 0) {
1667 analysis_window = new AnalysisWindow();
1670 analysis_window->set_session(_session);
1672 analysis_window->show_all();
1675 analysis_window->set_regionmode();
1676 analysis_window->analyze();
1678 analysis_window->present();
1682 Editor::analyze_range_selection()
1684 if (analysis_window == 0) {
1685 analysis_window = new AnalysisWindow();
1688 analysis_window->set_session(_session);
1690 analysis_window->show_all();
1693 analysis_window->set_rangemode();
1694 analysis_window->analyze();
1696 analysis_window->present();
1700 Editor::build_track_selection_context_menu ()
1702 using namespace Menu_Helpers;
1703 MenuList& edit_items = track_selection_context_menu.items();
1704 edit_items.clear ();
1706 add_selection_context_items (edit_items);
1707 // edit_items.push_back (SeparatorElem());
1708 // add_dstream_context_items (edit_items);
1710 return &track_selection_context_menu;
1714 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1716 using namespace Menu_Helpers;
1718 /* OK, stick the region submenu at the top of the list, and then add
1722 RegionSelection rs = get_regions_from_selection_and_entered ();
1724 string::size_type pos = 0;
1725 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1727 /* we have to hack up the region name because "_" has a special
1728 meaning for menu titles.
1731 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1732 menu_item_name.replace (pos, 1, "__");
1736 if (_popup_region_menu_item == 0) {
1737 _popup_region_menu_item = new MenuItem (menu_item_name);
1738 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1739 _popup_region_menu_item->show ();
1741 _popup_region_menu_item->set_label (menu_item_name);
1744 const framepos_t position = get_preferred_edit_position (false, true);
1746 edit_items.push_back (*_popup_region_menu_item);
1747 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1748 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1750 edit_items.push_back (SeparatorElem());
1753 /** Add context menu items relevant to selection ranges.
1754 * @param edit_items List to add the items to.
1757 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1759 using namespace Menu_Helpers;
1761 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1762 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1764 edit_items.push_back (SeparatorElem());
1765 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1767 edit_items.push_back (SeparatorElem());
1769 edit_items.push_back (
1771 _("Move Range Start to Previous Region Boundary"),
1772 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1776 edit_items.push_back (
1778 _("Move Range Start to Next Region Boundary"),
1779 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1783 edit_items.push_back (
1785 _("Move Range End to Previous Region Boundary"),
1786 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1790 edit_items.push_back (
1792 _("Move Range End to Next Region Boundary"),
1793 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1797 edit_items.push_back (SeparatorElem());
1798 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1799 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1801 edit_items.push_back (SeparatorElem());
1802 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1804 edit_items.push_back (SeparatorElem());
1805 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1806 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1808 edit_items.push_back (SeparatorElem());
1809 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1811 edit_items.push_back (SeparatorElem());
1812 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1813 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1814 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1816 edit_items.push_back (SeparatorElem());
1817 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1818 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1819 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1820 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1821 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1822 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1823 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1829 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1831 using namespace Menu_Helpers;
1835 Menu *play_menu = manage (new Menu);
1836 MenuList& play_items = play_menu->items();
1837 play_menu->set_name ("ArdourContextMenu");
1839 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1840 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1841 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1842 play_items.push_back (SeparatorElem());
1843 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1845 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1849 Menu *select_menu = manage (new Menu);
1850 MenuList& select_items = select_menu->items();
1851 select_menu->set_name ("ArdourContextMenu");
1853 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1854 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1855 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1856 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1857 select_items.push_back (SeparatorElem());
1858 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1859 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1860 select_items.push_back (SeparatorElem());
1861 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1862 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1863 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1864 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1865 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1866 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1867 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1869 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1873 Menu *cutnpaste_menu = manage (new Menu);
1874 MenuList& cutnpaste_items = cutnpaste_menu->items();
1875 cutnpaste_menu->set_name ("ArdourContextMenu");
1877 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1878 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1879 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1881 cutnpaste_items.push_back (SeparatorElem());
1883 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1884 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1886 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1888 /* Adding new material */
1890 edit_items.push_back (SeparatorElem());
1891 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1892 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1896 Menu *nudge_menu = manage (new Menu());
1897 MenuList& nudge_items = nudge_menu->items();
1898 nudge_menu->set_name ("ArdourContextMenu");
1900 edit_items.push_back (SeparatorElem());
1901 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1902 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1903 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1904 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1906 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1910 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1912 using namespace Menu_Helpers;
1916 Menu *play_menu = manage (new Menu);
1917 MenuList& play_items = play_menu->items();
1918 play_menu->set_name ("ArdourContextMenu");
1920 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1921 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1922 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1926 Menu *select_menu = manage (new Menu);
1927 MenuList& select_items = select_menu->items();
1928 select_menu->set_name ("ArdourContextMenu");
1930 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1931 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1932 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1933 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1934 select_items.push_back (SeparatorElem());
1935 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1936 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1937 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1938 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1940 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1944 Menu *cutnpaste_menu = manage (new Menu);
1945 MenuList& cutnpaste_items = cutnpaste_menu->items();
1946 cutnpaste_menu->set_name ("ArdourContextMenu");
1948 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1949 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1950 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1952 Menu *nudge_menu = manage (new Menu());
1953 MenuList& nudge_items = nudge_menu->items();
1954 nudge_menu->set_name ("ArdourContextMenu");
1956 edit_items.push_back (SeparatorElem());
1957 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1958 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1959 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1960 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1962 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1966 Editor::snap_type() const
1972 Editor::snap_mode() const
1978 Editor::set_snap_to (SnapType st)
1980 unsigned int snap_ind = (unsigned int)st;
1984 if (snap_ind > snap_type_strings.size() - 1) {
1986 _snap_type = (SnapType)snap_ind;
1989 string str = snap_type_strings[snap_ind];
1991 if (str != snap_type_selector.get_text()) {
1992 snap_type_selector.set_text (str);
1997 switch (_snap_type) {
1998 case SnapToBeatDiv128:
1999 case SnapToBeatDiv64:
2000 case SnapToBeatDiv32:
2001 case SnapToBeatDiv28:
2002 case SnapToBeatDiv24:
2003 case SnapToBeatDiv20:
2004 case SnapToBeatDiv16:
2005 case SnapToBeatDiv14:
2006 case SnapToBeatDiv12:
2007 case SnapToBeatDiv10:
2008 case SnapToBeatDiv8:
2009 case SnapToBeatDiv7:
2010 case SnapToBeatDiv6:
2011 case SnapToBeatDiv5:
2012 case SnapToBeatDiv4:
2013 case SnapToBeatDiv3:
2014 case SnapToBeatDiv2: {
2015 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2016 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2018 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2019 current_bbt_points_begin, current_bbt_points_end);
2020 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2021 current_bbt_points_begin, current_bbt_points_end);
2022 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2026 case SnapToRegionStart:
2027 case SnapToRegionEnd:
2028 case SnapToRegionSync:
2029 case SnapToRegionBoundary:
2030 build_region_boundary_cache ();
2038 SnapChanged (); /* EMIT SIGNAL */
2042 Editor::set_snap_mode (SnapMode mode)
2044 string str = snap_mode_strings[(int)mode];
2046 if (_internal_editing) {
2047 internal_snap_mode = mode;
2049 pre_internal_snap_mode = mode;
2054 if (str != snap_mode_selector.get_text ()) {
2055 snap_mode_selector.set_text (str);
2061 Editor::set_edit_point_preference (EditPoint ep, bool force)
2063 bool changed = (_edit_point != ep);
2066 string str = edit_point_strings[(int)ep];
2068 if (str != edit_point_selector.get_text ()) {
2069 edit_point_selector.set_text (str);
2072 reset_canvas_cursor ();
2074 if (!force && !changed) {
2078 const char* action=NULL;
2080 switch (_edit_point) {
2081 case EditAtPlayhead:
2082 action = "edit-at-playhead";
2084 case EditAtSelectedMarker:
2085 action = "edit-at-marker";
2088 action = "edit-at-mouse";
2092 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2094 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2098 bool in_track_canvas;
2100 if (!mouse_frame (foo, in_track_canvas)) {
2101 in_track_canvas = false;
2104 reset_canvas_action_sensitivity (in_track_canvas);
2110 Editor::set_state (const XMLNode& node, int /*version*/)
2112 const XMLProperty* prop;
2119 g.base_width = default_width;
2120 g.base_height = default_height;
2124 if ((geometry = find_named_node (node, "geometry")) != 0) {
2128 if ((prop = geometry->property("x_size")) == 0) {
2129 prop = geometry->property ("x-size");
2132 g.base_width = atoi(prop->value());
2134 if ((prop = geometry->property("y_size")) == 0) {
2135 prop = geometry->property ("y-size");
2138 g.base_height = atoi(prop->value());
2141 if ((prop = geometry->property ("x_pos")) == 0) {
2142 prop = geometry->property ("x-pos");
2145 x = atoi (prop->value());
2148 if ((prop = geometry->property ("y_pos")) == 0) {
2149 prop = geometry->property ("y-pos");
2152 y = atoi (prop->value());
2156 set_default_size (g.base_width, g.base_height);
2159 if (_session && (prop = node.property ("playhead"))) {
2161 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2162 playhead_cursor->set_position (pos);
2164 playhead_cursor->set_position (0);
2167 if ((prop = node.property ("mixer-width"))) {
2168 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2171 if ((prop = node.property ("zoom-focus"))) {
2172 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2175 if ((prop = node.property ("zoom"))) {
2176 /* older versions of ardour used floating point samples_per_pixel */
2177 double f = PBD::atof (prop->value());
2178 reset_zoom (llrintf (f));
2180 reset_zoom (samples_per_pixel);
2183 if ((prop = node.property ("visible-track-count"))) {
2184 set_visible_track_count (PBD::atoi (prop->value()));
2187 if ((prop = node.property ("snap-to"))) {
2188 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2191 if ((prop = node.property ("snap-mode"))) {
2192 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2195 if ((prop = node.property ("internal-snap-to"))) {
2196 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2199 if ((prop = node.property ("internal-snap-mode"))) {
2200 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2203 if ((prop = node.property ("pre-internal-snap-to"))) {
2204 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2208 if ((prop = node.property ("pre-internal-snap-mode"))) {
2209 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2212 if ((prop = node.property ("mouse-mode"))) {
2213 MouseMode m = str2mousemode(prop->value());
2214 set_mouse_mode (m, true);
2216 set_mouse_mode (MouseObject, true);
2219 if ((prop = node.property ("left-frame")) != 0) {
2221 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2225 reset_x_origin (pos);
2229 if ((prop = node.property ("y-origin")) != 0) {
2230 reset_y_origin (atof (prop->value ()));
2233 if ((prop = node.property ("internal-edit"))) {
2234 bool yn = string_is_affirmative (prop->value());
2235 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2237 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2238 tact->set_active (!yn);
2239 tact->set_active (yn);
2243 if ((prop = node.property ("join-object-range"))) {
2244 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2245 bool yn = string_is_affirmative (prop->value());
2247 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2248 tact->set_active (!yn);
2249 tact->set_active (yn);
2251 set_mouse_mode(mouse_mode, true);
2254 if ((prop = node.property ("edit-point"))) {
2255 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2258 if ((prop = node.property ("show-measures"))) {
2259 bool yn = string_is_affirmative (prop->value());
2260 _show_measures = yn;
2261 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2263 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2264 /* do it twice to force the change */
2265 tact->set_active (!yn);
2266 tact->set_active (yn);
2270 if ((prop = node.property ("follow-playhead"))) {
2271 bool yn = string_is_affirmative (prop->value());
2272 set_follow_playhead (yn);
2273 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2275 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2276 if (tact->get_active() != yn) {
2277 tact->set_active (yn);
2282 if ((prop = node.property ("stationary-playhead"))) {
2283 bool yn = string_is_affirmative (prop->value());
2284 set_stationary_playhead (yn);
2285 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2287 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2288 if (tact->get_active() != yn) {
2289 tact->set_active (yn);
2294 if ((prop = node.property ("region-list-sort-type"))) {
2295 RegionListSortType st;
2296 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2299 if ((prop = node.property ("show-editor-mixer"))) {
2301 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2304 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2305 bool yn = string_is_affirmative (prop->value());
2307 /* do it twice to force the change */
2309 tact->set_active (!yn);
2310 tact->set_active (yn);
2313 if ((prop = node.property ("show-editor-list"))) {
2315 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2318 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2319 bool yn = string_is_affirmative (prop->value());
2321 /* do it twice to force the change */
2323 tact->set_active (!yn);
2324 tact->set_active (yn);
2327 if ((prop = node.property (X_("editor-list-page")))) {
2328 _the_notebook.set_current_page (atoi (prop->value ()));
2331 if ((prop = node.property (X_("show-marker-lines")))) {
2332 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2334 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2335 bool yn = string_is_affirmative (prop->value ());
2337 tact->set_active (!yn);
2338 tact->set_active (yn);
2341 XMLNodeList children = node.children ();
2342 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2343 selection->set_state (**i, Stateful::current_state_version);
2344 _regions->set_state (**i);
2347 if ((prop = node.property ("maximised"))) {
2348 bool yn = string_is_affirmative (prop->value());
2349 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2351 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2352 bool fs = tact && tact->get_active();
2354 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2358 if ((prop = node.property ("nudge-clock-value"))) {
2360 sscanf (prop->value().c_str(), "%" PRId64, &f);
2361 nudge_clock->set (f);
2363 nudge_clock->set_mode (AudioClock::Timecode);
2364 nudge_clock->set (_session->frame_rate() * 5, true);
2371 Editor::get_state ()
2373 XMLNode* node = new XMLNode ("Editor");
2376 id().print (buf, sizeof (buf));
2377 node->add_property ("id", buf);
2379 if (is_realized()) {
2380 Glib::RefPtr<Gdk::Window> win = get_window();
2382 int x, y, width, height;
2383 win->get_root_origin(x, y);
2384 win->get_size(width, height);
2386 XMLNode* geometry = new XMLNode ("geometry");
2388 snprintf(buf, sizeof(buf), "%d", width);
2389 geometry->add_property("x-size", string(buf));
2390 snprintf(buf, sizeof(buf), "%d", height);
2391 geometry->add_property("y-size", string(buf));
2392 snprintf(buf, sizeof(buf), "%d", x);
2393 geometry->add_property("x-pos", string(buf));
2394 snprintf(buf, sizeof(buf), "%d", y);
2395 geometry->add_property("y-pos", string(buf));
2396 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2397 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2398 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2399 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2400 geometry->add_property("edit-vertical-pane-pos", string(buf));
2402 node->add_child_nocopy (*geometry);
2405 maybe_add_mixer_strip_width (*node);
2407 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2409 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2410 node->add_property ("zoom", buf);
2411 node->add_property ("snap-to", enum_2_string (_snap_type));
2412 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2413 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2414 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2415 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2416 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2417 node->add_property ("edit-point", enum_2_string (_edit_point));
2418 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2419 node->add_property ("visible-track-count", buf);
2421 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2422 node->add_property ("playhead", buf);
2423 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2424 node->add_property ("left-frame", buf);
2425 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2426 node->add_property ("y-origin", buf);
2428 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2429 node->add_property ("maximised", _maximised ? "yes" : "no");
2430 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2431 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2432 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2433 node->add_property ("mouse-mode", enum2str(mouse_mode));
2434 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2435 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2437 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2439 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2440 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2443 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2445 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2446 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2449 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2450 node->add_property (X_("editor-list-page"), buf);
2452 if (button_bindings) {
2453 XMLNode* bb = new XMLNode (X_("Buttons"));
2454 button_bindings->save (*bb);
2455 node->add_child_nocopy (*bb);
2458 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2460 node->add_child_nocopy (selection->get_state ());
2461 node->add_child_nocopy (_regions->get_state ());
2463 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2464 node->add_property ("nudge-clock-value", buf);
2469 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2470 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2472 * @return pair: TimeAxisView that y is over, layer index.
2474 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2475 * in stacked or expanded region display mode, otherwise 0.
2477 std::pair<TimeAxisView *, double>
2478 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2480 if (!trackview_relative_offset) {
2481 y -= _trackview_group->canvas_origin().y;
2485 return std::make_pair ( (TimeAxisView *) 0, 0);
2488 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2490 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2497 return std::make_pair ( (TimeAxisView *) 0, 0);
2500 /** Snap a position to the grid, if appropriate, taking into account current
2501 * grid settings and also the state of any snap modifier keys that may be pressed.
2502 * @param start Position to snap.
2503 * @param event Event to get current key modifier information from, or 0.
2506 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2508 if (!_session || !event) {
2512 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2513 if (_snap_mode == SnapOff) {
2514 snap_to_internal (start, direction, for_mark);
2517 if (_snap_mode != SnapOff) {
2518 snap_to_internal (start, direction, for_mark);
2524 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2526 if (!_session || _snap_mode == SnapOff) {
2530 snap_to_internal (start, direction, for_mark);
2534 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2536 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2537 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2539 switch (_snap_type) {
2540 case SnapToTimecodeFrame:
2541 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2542 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2544 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2548 case SnapToTimecodeSeconds:
2549 if (_session->config.get_timecode_offset_negative()) {
2550 start += _session->config.get_timecode_offset ();
2552 start -= _session->config.get_timecode_offset ();
2554 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2555 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2557 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2560 if (_session->config.get_timecode_offset_negative()) {
2561 start -= _session->config.get_timecode_offset ();
2563 start += _session->config.get_timecode_offset ();
2567 case SnapToTimecodeMinutes:
2568 if (_session->config.get_timecode_offset_negative()) {
2569 start += _session->config.get_timecode_offset ();
2571 start -= _session->config.get_timecode_offset ();
2573 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2574 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2576 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2578 if (_session->config.get_timecode_offset_negative()) {
2579 start -= _session->config.get_timecode_offset ();
2581 start += _session->config.get_timecode_offset ();
2585 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2591 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2593 const framepos_t one_second = _session->frame_rate();
2594 const framepos_t one_minute = _session->frame_rate() * 60;
2595 framepos_t presnap = start;
2599 switch (_snap_type) {
2600 case SnapToTimecodeFrame:
2601 case SnapToTimecodeSeconds:
2602 case SnapToTimecodeMinutes:
2603 return timecode_snap_to_internal (start, direction, for_mark);
2606 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2607 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2609 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2614 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2615 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2617 start = (framepos_t) floor ((double) start / one_second) * one_second;
2622 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2623 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2625 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2630 start = _session->tempo_map().round_to_bar (start, direction);
2634 start = _session->tempo_map().round_to_beat (start, direction);
2637 case SnapToBeatDiv128:
2638 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2640 case SnapToBeatDiv64:
2641 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2643 case SnapToBeatDiv32:
2644 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2646 case SnapToBeatDiv28:
2647 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2649 case SnapToBeatDiv24:
2650 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2652 case SnapToBeatDiv20:
2653 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2655 case SnapToBeatDiv16:
2656 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2658 case SnapToBeatDiv14:
2659 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2661 case SnapToBeatDiv12:
2662 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2664 case SnapToBeatDiv10:
2665 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2667 case SnapToBeatDiv8:
2668 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2670 case SnapToBeatDiv7:
2671 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2673 case SnapToBeatDiv6:
2674 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2676 case SnapToBeatDiv5:
2677 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2679 case SnapToBeatDiv4:
2680 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2682 case SnapToBeatDiv3:
2683 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2685 case SnapToBeatDiv2:
2686 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2694 _session->locations()->marks_either_side (start, before, after);
2696 if (before == max_framepos && after == max_framepos) {
2697 /* No marks to snap to, so just don't snap */
2699 } else if (before == max_framepos) {
2701 } else if (after == max_framepos) {
2703 } else if (before != max_framepos && after != max_framepos) {
2704 /* have before and after */
2705 if ((start - before) < (after - start)) {
2714 case SnapToRegionStart:
2715 case SnapToRegionEnd:
2716 case SnapToRegionSync:
2717 case SnapToRegionBoundary:
2718 if (!region_boundary_cache.empty()) {
2720 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2721 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2723 if (direction > 0) {
2724 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2726 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2729 if (next != region_boundary_cache.begin ()) {
2734 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2735 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2737 if (start > (p + n) / 2) {
2746 switch (_snap_mode) {
2752 if (presnap > start) {
2753 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2757 } else if (presnap < start) {
2758 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2764 /* handled at entry */
2772 Editor::setup_toolbar ()
2774 HBox* mode_box = manage(new HBox);
2775 mode_box->set_border_width (2);
2776 mode_box->set_spacing(4);
2778 HBox* mouse_mode_box = manage (new HBox);
2779 HBox* mouse_mode_hbox = manage (new HBox);
2780 VBox* mouse_mode_vbox = manage (new VBox);
2781 Alignment* mouse_mode_align = manage (new Alignment);
2783 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2784 // mouse_mode_size_group->add_widget (smart_mode_button);
2785 mouse_mode_size_group->add_widget (mouse_move_button);
2786 mouse_mode_size_group->add_widget (mouse_select_button);
2787 mouse_mode_size_group->add_widget (mouse_zoom_button);
2788 mouse_mode_size_group->add_widget (mouse_gain_button);
2789 mouse_mode_size_group->add_widget (mouse_timefx_button);
2790 mouse_mode_size_group->add_widget (mouse_audition_button);
2791 mouse_mode_size_group->add_widget (mouse_draw_button);
2792 mouse_mode_size_group->add_widget (internal_edit_button);
2794 /* make them just a bit bigger */
2795 mouse_move_button.set_size_request (-1, 30);
2797 mouse_mode_hbox->set_spacing (2);
2799 if (!ARDOUR::Profile->get_trx()) {
2800 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2803 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2804 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2805 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2807 if (!ARDOUR::Profile->get_trx()) {
2808 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2809 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2810 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2811 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2812 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2815 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2817 mouse_mode_align->add (*mouse_mode_vbox);
2818 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2820 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2822 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2823 if (!Profile->get_sae()) {
2824 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2826 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2828 edit_mode_selector.set_name ("mouse mode button");
2829 edit_mode_selector.set_size_request (65, -1);
2830 edit_mode_selector.add_elements (ArdourButton::Inset);
2832 if (!ARDOUR::Profile->get_trx()) {
2833 mode_box->pack_start (edit_mode_selector, false, false);
2835 mode_box->pack_start (*mouse_mode_box, false, false);
2837 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2838 _mouse_mode_tearoff->set_name ("MouseModeBase");
2839 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2841 if (Profile->get_sae()) {
2842 _mouse_mode_tearoff->set_can_be_torn_off (false);
2845 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2846 &_mouse_mode_tearoff->tearoff_window()));
2847 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2848 &_mouse_mode_tearoff->tearoff_window(), 1));
2849 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2850 &_mouse_mode_tearoff->tearoff_window()));
2851 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2852 &_mouse_mode_tearoff->tearoff_window(), 1));
2856 _zoom_box.set_spacing (2);
2857 _zoom_box.set_border_width (2);
2861 zoom_in_button.set_name ("zoom button");
2862 // zoom_in_button.add_elements ( ArdourButton::Inset );
2863 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2864 zoom_in_button.set_image(::get_icon ("zoom_in"));
2865 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2866 zoom_in_button.set_related_action (act);
2868 zoom_out_button.set_name ("zoom button");
2869 // zoom_out_button.add_elements ( ArdourButton::Inset );
2870 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2871 zoom_out_button.set_image(::get_icon ("zoom_out"));
2872 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2873 zoom_out_button.set_related_action (act);
2875 zoom_out_full_button.set_name ("zoom button");
2876 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2877 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2878 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2879 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2880 zoom_out_full_button.set_related_action (act);
2882 zoom_focus_selector.set_name ("zoom button");
2883 zoom_focus_selector.set_size_request (80, -1);
2884 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2886 if (!ARDOUR::Profile->get_trx()) {
2887 _zoom_box.pack_start (zoom_out_button, false, false);
2888 _zoom_box.pack_start (zoom_in_button, false, false);
2889 _zoom_box.pack_start (zoom_out_full_button, false, false);
2890 _zoom_box.pack_start (zoom_focus_selector, false, false);
2892 mode_box->pack_start (zoom_out_button, false, false);
2893 mode_box->pack_start (zoom_in_button, false, false);
2896 /* Track zoom buttons */
2897 visible_tracks_selector.set_name ("zoom button");
2898 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2899 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2901 tav_expand_button.set_name ("zoom button");
2902 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2903 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2904 tav_expand_button.set_size_request (-1, 20);
2905 tav_expand_button.set_image(::get_icon ("tav_exp"));
2906 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2907 tav_expand_button.set_related_action (act);
2909 tav_shrink_button.set_name ("zoom button");
2910 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2911 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2912 tav_shrink_button.set_size_request (-1, 20);
2913 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2914 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2915 tav_shrink_button.set_related_action (act);
2917 if (!ARDOUR::Profile->get_trx()) {
2918 _zoom_box.pack_start (visible_tracks_selector);
2920 _zoom_box.pack_start (tav_shrink_button);
2921 _zoom_box.pack_start (tav_expand_button);
2923 if (!ARDOUR::Profile->get_trx()) {
2924 _zoom_tearoff = manage (new TearOff (_zoom_box));
2926 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927 &_zoom_tearoff->tearoff_window()));
2928 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929 &_zoom_tearoff->tearoff_window(), 0));
2930 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2931 &_zoom_tearoff->tearoff_window()));
2932 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2933 &_zoom_tearoff->tearoff_window(), 0));
2936 snap_box.set_spacing (2);
2937 snap_box.set_border_width (2);
2939 snap_type_selector.set_name ("mouse mode button");
2940 snap_type_selector.set_size_request (140, -1);
2941 snap_type_selector.add_elements (ArdourButton::Inset);
2943 snap_mode_selector.set_name ("mouse mode button");
2944 snap_mode_selector.set_size_request (85, -1);
2945 snap_mode_selector.add_elements (ArdourButton::Inset);
2947 edit_point_selector.set_name ("mouse mode button");
2948 edit_point_selector.set_size_request (85, -1);
2949 edit_point_selector.add_elements (ArdourButton::Inset);
2951 snap_box.pack_start (snap_mode_selector, false, false);
2952 snap_box.pack_start (snap_type_selector, false, false);
2953 snap_box.pack_start (edit_point_selector, false, false);
2957 HBox *nudge_box = manage (new HBox);
2958 nudge_box->set_spacing (2);
2959 nudge_box->set_border_width (2);
2961 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2962 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2964 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2965 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2967 nudge_box->pack_start (nudge_backward_button, false, false);
2968 nudge_box->pack_start (nudge_forward_button, false, false);
2969 nudge_box->pack_start (*nudge_clock, false, false);
2972 /* Pack everything in... */
2974 HBox* hbox = manage (new HBox);
2975 hbox->set_spacing(10);
2977 _tools_tearoff = manage (new TearOff (*hbox));
2978 _tools_tearoff->set_name ("MouseModeBase");
2979 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2981 if (Profile->get_sae()) {
2982 _tools_tearoff->set_can_be_torn_off (false);
2985 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2986 &_tools_tearoff->tearoff_window()));
2987 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2988 &_tools_tearoff->tearoff_window(), 0));
2989 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2990 &_tools_tearoff->tearoff_window()));
2991 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2992 &_tools_tearoff->tearoff_window(), 0));
2994 toolbar_hbox.set_spacing (10);
2995 toolbar_hbox.set_border_width (1);
2997 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2998 if (!ARDOUR::Profile->get_trx()) {
2999 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3000 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3003 if (!ARDOUR::Profile->get_trx()) {
3004 hbox->pack_start (snap_box, false, false);
3005 if (!Profile->get_small_screen()) {
3006 hbox->pack_start (*nudge_box, false, false);
3008 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3011 hbox->pack_start (panic_box, false, false);
3015 toolbar_base.set_name ("ToolBarBase");
3016 toolbar_base.add (toolbar_hbox);
3018 _toolbar_viewport.add (toolbar_base);
3019 /* stick to the required height but allow width to vary if there's not enough room */
3020 _toolbar_viewport.set_size_request (1, -1);
3022 toolbar_frame.set_shadow_type (SHADOW_OUT);
3023 toolbar_frame.set_name ("BaseFrame");
3024 toolbar_frame.add (_toolbar_viewport);
3028 Editor::build_edit_point_menu ()
3030 using namespace Menu_Helpers;
3032 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3033 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3034 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3038 Editor::build_edit_mode_menu ()
3040 using namespace Menu_Helpers;
3042 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Slide), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3043 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Splice), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3044 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_to_string(Lock), sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3048 Editor::build_snap_mode_menu ()
3050 using namespace Menu_Helpers;
3052 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3053 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3054 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3058 Editor::build_snap_type_menu ()
3060 using namespace Menu_Helpers;
3062 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3063 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3064 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3065 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3066 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3067 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3095 Editor::setup_tooltips ()
3097 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3098 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3099 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3100 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3101 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3102 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3103 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3104 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3105 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3106 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3107 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3108 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3109 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3110 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3111 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3112 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3113 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3114 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3115 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3116 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3117 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3118 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3119 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3120 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3124 Editor::convert_drop_to_paths (
3125 vector<string>& paths,
3126 const RefPtr<Gdk::DragContext>& /*context*/,
3129 const SelectionData& data,
3133 if (_session == 0) {
3137 vector<string> uris = data.get_uris();
3141 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3142 are actually URI lists. So do it by hand.
3145 if (data.get_target() != "text/plain") {
3149 /* Parse the "uri-list" format that Nautilus provides,
3150 where each pathname is delimited by \r\n.
3152 THERE MAY BE NO NULL TERMINATING CHAR!!!
3155 string txt = data.get_text();
3159 p = (char *) malloc (txt.length() + 1);
3160 txt.copy (p, txt.length(), 0);
3161 p[txt.length()] = '\0';
3167 while (g_ascii_isspace (*p))
3171 while (*q && (*q != '\n') && (*q != '\r')) {
3178 while (q > p && g_ascii_isspace (*q))
3183 uris.push_back (string (p, q - p + 1));
3187 p = strchr (p, '\n');
3199 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3200 if ((*i).substr (0,7) == "file://") {
3201 paths.push_back (Glib::filename_from_uri (*i));
3209 Editor::new_tempo_section ()
3214 Editor::map_transport_state ()
3216 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3218 if (_session && _session->transport_stopped()) {
3219 have_pending_keyboard_selection = false;
3222 update_loop_range_view ();
3228 Editor::begin_reversible_command (string name)
3231 _session->begin_reversible_command (name);
3236 Editor::begin_reversible_command (GQuark q)
3239 _session->begin_reversible_command (q);
3244 Editor::commit_reversible_command ()
3247 _session->commit_reversible_command ();
3252 Editor::history_changed ()
3256 if (undo_action && _session) {
3257 if (_session->undo_depth() == 0) {
3258 label = S_("Command|Undo");
3260 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3262 undo_action->property_label() = label;
3265 if (redo_action && _session) {
3266 if (_session->redo_depth() == 0) {
3269 label = string_compose(_("Redo (%1)"), _session->next_redo());
3271 redo_action->property_label() = label;
3276 Editor::duplicate_range (bool with_dialog)
3280 RegionSelection rs = get_regions_from_selection_and_entered ();
3282 if ( selection->time.length() == 0 && rs.empty()) {
3288 ArdourDialog win (_("Duplicate"));
3289 Label label (_("Number of duplications:"));
3290 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3291 SpinButton spinner (adjustment, 0.0, 1);
3294 win.get_vbox()->set_spacing (12);
3295 win.get_vbox()->pack_start (hbox);
3296 hbox.set_border_width (6);
3297 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3299 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3300 place, visually. so do this by hand.
3303 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3304 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3305 spinner.grab_focus();
3311 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3312 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3313 win.set_default_response (RESPONSE_ACCEPT);
3315 spinner.grab_focus ();
3317 switch (win.run ()) {
3318 case RESPONSE_ACCEPT:
3324 times = adjustment.get_value();
3327 if ((current_mouse_mode() == Editing::MouseRange)) {
3328 if (selection->time.length()) {
3329 duplicate_selection (times);
3331 } else if (get_smart_mode()) {
3332 if (selection->time.length()) {
3333 duplicate_selection (times);
3335 duplicate_some_regions (rs, times);
3337 duplicate_some_regions (rs, times);
3342 Editor::set_edit_mode (EditMode m)
3344 Config->set_edit_mode (m);
3348 Editor::cycle_edit_mode ()
3350 switch (Config->get_edit_mode()) {
3352 if (Profile->get_sae()) {
3353 Config->set_edit_mode (Lock);
3355 Config->set_edit_mode (Splice);
3359 Config->set_edit_mode (Lock);
3362 Config->set_edit_mode (Slide);
3368 Editor::edit_mode_selection_done ( EditMode m )
3370 Config->set_edit_mode ( m );
3374 Editor::snap_type_selection_done (SnapType snaptype)
3376 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3378 ract->set_active ();
3383 Editor::snap_mode_selection_done (SnapMode mode)
3385 RefPtr<RadioAction> ract = snap_mode_action (mode);
3388 ract->set_active (true);
3393 Editor::cycle_edit_point (bool with_marker)
3395 switch (_edit_point) {
3397 set_edit_point_preference (EditAtPlayhead);
3399 case EditAtPlayhead:
3401 set_edit_point_preference (EditAtSelectedMarker);
3403 set_edit_point_preference (EditAtMouse);
3406 case EditAtSelectedMarker:
3407 set_edit_point_preference (EditAtMouse);
3413 Editor::edit_point_selection_done (EditPoint ep)
3415 set_edit_point_preference ( ep );
3419 Editor::build_zoom_focus_menu ()
3421 using namespace Menu_Helpers;
3423 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3424 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3425 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3426 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3427 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3428 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3432 Editor::zoom_focus_selection_done ( ZoomFocus f )
3434 RefPtr<RadioAction> ract = zoom_focus_action (f);
3436 ract->set_active ();
3441 Editor::build_track_count_menu ()
3443 using namespace Menu_Helpers;
3445 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3446 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3447 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3448 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3449 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3450 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3451 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3452 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3453 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3454 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3455 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3456 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3460 Editor::set_visible_track_count (int32_t n)
3462 _visible_track_count = n;
3464 /* if the canvas hasn't really been allocated any size yet, just
3465 record the desired number of visible tracks and return. when canvas
3466 allocation happens, we will get called again and then we can do the
3470 if (_visible_canvas_height <= 1) {
3477 if (_visible_track_count > 0) {
3478 h = _visible_canvas_height / _visible_track_count;
3479 std::ostringstream s;
3480 s << _visible_track_count;
3482 } else if (_visible_track_count == 0) {
3483 h = _visible_canvas_height / track_views.size();
3486 /* negative value means that the visible track count has
3487 been overridden by explicit track height changes.
3489 visible_tracks_selector.set_text (X_("*"));
3493 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3494 (*i)->set_height (h);
3497 if (str != visible_tracks_selector.get_text()) {
3498 visible_tracks_selector.set_text (str);
3503 Editor::override_visible_track_count ()
3505 _visible_track_count = -_visible_track_count;
3509 Editor::edit_controls_button_release (GdkEventButton* ev)
3511 if (Keyboard::is_context_menu_event (ev)) {
3512 ARDOUR_UI::instance()->add_route (this);
3513 } else if (ev->button == 1) {
3514 selection->clear_tracks ();
3521 Editor::mouse_select_button_release (GdkEventButton* ev)
3523 /* this handles just right-clicks */
3525 if (ev->button != 3) {
3533 Editor::set_zoom_focus (ZoomFocus f)
3535 string str = zoom_focus_strings[(int)f];
3537 if (str != zoom_focus_selector.get_text()) {
3538 zoom_focus_selector.set_text (str);
3541 if (zoom_focus != f) {
3548 Editor::cycle_zoom_focus ()
3550 switch (zoom_focus) {
3552 set_zoom_focus (ZoomFocusRight);
3554 case ZoomFocusRight:
3555 set_zoom_focus (ZoomFocusCenter);
3557 case ZoomFocusCenter:
3558 set_zoom_focus (ZoomFocusPlayhead);
3560 case ZoomFocusPlayhead:
3561 set_zoom_focus (ZoomFocusMouse);
3563 case ZoomFocusMouse:
3564 set_zoom_focus (ZoomFocusEdit);
3567 set_zoom_focus (ZoomFocusLeft);
3573 Editor::ensure_float (Window& win)
3575 win.set_transient_for (*this);
3579 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3581 /* recover or initialize pane positions. do this here rather than earlier because
3582 we don't want the positions to change the child allocations, which they seem to do.
3588 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3597 XMLNode* geometry = find_named_node (*node, "geometry");
3599 if (which == static_cast<Paned*> (&edit_pane)) {
3601 if (done & Horizontal) {
3605 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3606 _notebook_shrunk = string_is_affirmative (prop->value ());
3609 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3610 /* initial allocation is 90% to canvas, 10% to notebook */
3611 pos = (int) floor (alloc.get_width() * 0.90f);
3612 snprintf (buf, sizeof(buf), "%d", pos);
3614 pos = atoi (prop->value());
3617 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3618 edit_pane.set_position (pos);
3621 done = (Pane) (done | Horizontal);
3623 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3625 if (done & Vertical) {
3629 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3630 /* initial allocation is 90% to canvas, 10% to summary */
3631 pos = (int) floor (alloc.get_height() * 0.90f);
3632 snprintf (buf, sizeof(buf), "%d", pos);
3635 pos = atoi (prop->value());
3638 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3639 editor_summary_pane.set_position (pos);
3642 done = (Pane) (done | Vertical);
3647 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3649 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3650 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3651 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3652 top_hbox.remove (toolbar_frame);
3657 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3659 if (toolbar_frame.get_parent() == 0) {
3660 top_hbox.pack_end (toolbar_frame);
3665 Editor::set_show_measures (bool yn)
3667 if (_show_measures != yn) {
3670 if ((_show_measures = yn) == true) {
3672 tempo_lines->show();
3675 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3676 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3678 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3679 draw_measures (begin, end);
3687 Editor::toggle_follow_playhead ()
3689 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3691 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3692 set_follow_playhead (tact->get_active());
3696 /** @param yn true to follow playhead, otherwise false.
3697 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3700 Editor::set_follow_playhead (bool yn, bool catch_up)
3702 if (_follow_playhead != yn) {
3703 if ((_follow_playhead = yn) == true && catch_up) {
3705 reset_x_origin_to_follow_playhead ();
3712 Editor::toggle_stationary_playhead ()
3714 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3716 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3717 set_stationary_playhead (tact->get_active());
3722 Editor::set_stationary_playhead (bool yn)
3724 if (_stationary_playhead != yn) {
3725 if ((_stationary_playhead = yn) == true) {
3727 // FIXME need a 3.0 equivalent of this 2.X call
3728 // update_current_screen ();
3735 Editor::playlist_selector () const
3737 return *_playlist_selector;
3741 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3745 switch (_snap_type) {
3750 case SnapToBeatDiv128:
3753 case SnapToBeatDiv64:
3756 case SnapToBeatDiv32:
3759 case SnapToBeatDiv28:
3762 case SnapToBeatDiv24:
3765 case SnapToBeatDiv20:
3768 case SnapToBeatDiv16:
3771 case SnapToBeatDiv14:
3774 case SnapToBeatDiv12:
3777 case SnapToBeatDiv10:
3780 case SnapToBeatDiv8:
3783 case SnapToBeatDiv7:
3786 case SnapToBeatDiv6:
3789 case SnapToBeatDiv5:
3792 case SnapToBeatDiv4:
3795 case SnapToBeatDiv3:
3798 case SnapToBeatDiv2:
3804 return _session->tempo_map().meter_at (position).divisions_per_bar();
3809 case SnapToTimecodeFrame:
3810 case SnapToTimecodeSeconds:
3811 case SnapToTimecodeMinutes:
3814 case SnapToRegionStart:
3815 case SnapToRegionEnd:
3816 case SnapToRegionSync:
3817 case SnapToRegionBoundary:
3827 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3831 ret = nudge_clock->current_duration (pos);
3832 next = ret + 1; /* XXXX fix me */
3838 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3840 ArdourDialog dialog (_("Playlist Deletion"));
3841 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3842 "If it is kept, its audio files will not be cleaned.\n"
3843 "If it is deleted, audio files used by it alone will be cleaned."),
3846 dialog.set_position (WIN_POS_CENTER);
3847 dialog.get_vbox()->pack_start (label);
3851 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3852 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3853 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3855 switch (dialog.run ()) {
3856 case RESPONSE_ACCEPT:
3857 /* delete the playlist */
3861 case RESPONSE_REJECT:
3862 /* keep the playlist */
3874 Editor::audio_region_selection_covers (framepos_t where)
3876 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3877 if ((*a)->region()->covers (where)) {
3886 Editor::prepare_for_cleanup ()
3888 cut_buffer->clear_regions ();
3889 cut_buffer->clear_playlists ();
3891 selection->clear_regions ();
3892 selection->clear_playlists ();
3894 _regions->suspend_redisplay ();
3898 Editor::finish_cleanup ()
3900 _regions->resume_redisplay ();
3904 Editor::transport_loop_location()
3907 return _session->locations()->auto_loop_location();
3914 Editor::transport_punch_location()
3917 return _session->locations()->auto_punch_location();
3924 Editor::control_layout_scroll (GdkEventScroll* ev)
3926 /* Just forward to the normal canvas scroll method. The coordinate
3927 systems are different but since the canvas is always larger than the
3928 track headers, and aligned with the trackview area, this will work.
3930 In the not too distant future this layout is going away anyway and
3931 headers will be on the canvas.
3933 return canvas_scroll_event (ev, false);
3937 Editor::session_state_saved (string)
3940 _snapshots->redisplay ();
3944 Editor::update_tearoff_visibility()
3946 bool visible = Config->get_keep_tearoffs();
3947 _mouse_mode_tearoff->set_visible (visible);
3948 _tools_tearoff->set_visible (visible);
3949 if (_zoom_tearoff) {
3950 _zoom_tearoff->set_visible (visible);
3955 Editor::maximise_editing_space ()
3967 Editor::restore_editing_space ()
3979 * Make new playlists for a given track and also any others that belong
3980 * to the same active route group with the `select' property.
3985 Editor::new_playlists (TimeAxisView* v)
3987 begin_reversible_command (_("new playlists"));
3988 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3989 _session->playlists->get (playlists);
3990 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
3991 commit_reversible_command ();
3995 * Use a copy of the current playlist for a given track and also any others that belong
3996 * to the same active route group with the `select' property.
4001 Editor::copy_playlists (TimeAxisView* v)
4003 begin_reversible_command (_("copy playlists"));
4004 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4005 _session->playlists->get (playlists);
4006 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4007 commit_reversible_command ();
4010 /** Clear the current playlist for a given track and also any others that belong
4011 * to the same active route group with the `select' property.
4016 Editor::clear_playlists (TimeAxisView* v)
4018 begin_reversible_command (_("clear playlists"));
4019 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4020 _session->playlists->get (playlists);
4021 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4022 commit_reversible_command ();
4026 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4028 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4032 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4034 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4038 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4040 atv.clear_playlist ();
4044 Editor::on_key_press_event (GdkEventKey* ev)
4046 return key_press_focus_accelerator_handler (*this, ev);
4050 Editor::on_key_release_event (GdkEventKey* ev)
4052 return Gtk::Window::on_key_release_event (ev);
4053 // return key_press_focus_accelerator_handler (*this, ev);
4056 /** Queue up a change to the viewport x origin.
4057 * @param frame New x origin.
4060 Editor::reset_x_origin (framepos_t frame)
4062 pending_visual_change.add (VisualChange::TimeOrigin);
4063 pending_visual_change.time_origin = frame;
4064 ensure_visual_change_idle_handler ();
4068 Editor::reset_y_origin (double y)
4070 pending_visual_change.add (VisualChange::YOrigin);
4071 pending_visual_change.y_origin = y;
4072 ensure_visual_change_idle_handler ();
4076 Editor::reset_zoom (framecnt_t spp)
4078 clamp_samples_per_pixel (spp);
4080 if (spp == samples_per_pixel) {
4084 pending_visual_change.add (VisualChange::ZoomLevel);
4085 pending_visual_change.samples_per_pixel = spp;
4086 ensure_visual_change_idle_handler ();
4090 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4092 reset_x_origin (frame);
4095 if (!no_save_visual) {
4096 undo_visual_stack.push_back (current_visual_state(false));
4100 Editor::VisualState::VisualState (bool with_tracks)
4101 : gui_state (with_tracks ? new GUIObjectState : 0)
4105 Editor::VisualState::~VisualState ()
4110 Editor::VisualState*
4111 Editor::current_visual_state (bool with_tracks)
4113 VisualState* vs = new VisualState (with_tracks);
4114 vs->y_position = vertical_adjustment.get_value();
4115 vs->samples_per_pixel = samples_per_pixel;
4116 vs->leftmost_frame = leftmost_frame;
4117 vs->zoom_focus = zoom_focus;
4120 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4127 Editor::undo_visual_state ()
4129 if (undo_visual_stack.empty()) {
4133 VisualState* vs = undo_visual_stack.back();
4134 undo_visual_stack.pop_back();
4137 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4139 use_visual_state (*vs);
4143 Editor::redo_visual_state ()
4145 if (redo_visual_stack.empty()) {
4149 VisualState* vs = redo_visual_stack.back();
4150 redo_visual_stack.pop_back();
4152 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4154 use_visual_state (*vs);
4158 Editor::swap_visual_state ()
4160 if (undo_visual_stack.empty()) {
4161 redo_visual_state ();
4163 undo_visual_state ();
4168 Editor::use_visual_state (VisualState& vs)
4170 PBD::Unwinder<bool> nsv (no_save_visual, true);
4171 DisplaySuspender ds;
4173 vertical_adjustment.set_value (vs.y_position);
4175 set_zoom_focus (vs.zoom_focus);
4176 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4179 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4181 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4182 (*i)->reset_visual_state ();
4186 _routes->update_visibility ();
4189 /** This is the core function that controls the zoom level of the canvas. It is called
4190 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4191 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4194 Editor::set_samples_per_pixel (framecnt_t spp)
4196 clamp_samples_per_pixel (spp);
4197 samples_per_pixel = spp;
4200 tempo_lines->tempo_map_changed();
4203 /* convert fpu to frame count */
4205 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4207 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4208 zoom_range_clock->set (frames);
4211 bool const showing_time_selection = selection->time.length() > 0;
4213 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4214 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4215 (*i)->reshow_selection (selection->time);
4219 ZoomChanged (); /* EMIT_SIGNAL */
4221 ArdourCanvas::GtkCanvasViewport* c;
4223 c = get_track_canvas();
4225 c->canvas()->zoomed ();
4228 if (playhead_cursor) {
4229 playhead_cursor->set_position (playhead_cursor->current_frame ());
4232 refresh_location_display();
4233 _summary->set_overlays_dirty ();
4235 update_marker_labels ();
4241 Editor::queue_visual_videotimeline_update ()
4244 * pending_visual_change.add (VisualChange::VideoTimeline);
4245 * or maybe even more specific: which videotimeline-image
4246 * currently it calls update_video_timeline() to update
4247 * _all outdated_ images on the video-timeline.
4248 * see 'exposeimg()' in video_image_frame.cc
4250 ensure_visual_change_idle_handler ();
4254 Editor::ensure_visual_change_idle_handler ()
4256 if (pending_visual_change.idle_handler_id < 0) {
4257 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4258 pending_visual_change.being_handled = false;
4263 Editor::_idle_visual_changer (void* arg)
4265 return static_cast<Editor*>(arg)->idle_visual_changer ();
4269 Editor::idle_visual_changer ()
4271 /* set_horizontal_position() below (and maybe other calls) call
4272 gtk_main_iteration(), so it's possible that a signal will be handled
4273 half-way through this method. If this signal wants an
4274 idle_visual_changer we must schedule another one after this one, so
4275 mark the idle_handler_id as -1 here to allow that. Also make a note
4276 that we are doing the visual change, so that changes in response to
4277 super-rapid-screen-update can be dropped if we are still processing
4281 pending_visual_change.idle_handler_id = -1;
4282 pending_visual_change.being_handled = true;
4284 VisualChange vc = pending_visual_change;
4286 pending_visual_change.pending = (VisualChange::Type) 0;
4288 visual_changer (vc);
4290 pending_visual_change.being_handled = false;
4292 return 0; /* this is always a one-shot call */
4296 Editor::visual_changer (const VisualChange& vc)
4298 double const last_time_origin = horizontal_position ();
4300 if (vc.pending & VisualChange::ZoomLevel) {
4301 set_samples_per_pixel (vc.samples_per_pixel);
4303 compute_fixed_ruler_scale ();
4305 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4306 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4308 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4309 current_bbt_points_begin, current_bbt_points_end);
4310 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4311 current_bbt_points_begin, current_bbt_points_end);
4312 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4314 update_video_timeline();
4317 if (vc.pending & VisualChange::TimeOrigin) {
4318 set_horizontal_position (vc.time_origin / samples_per_pixel);
4321 if (vc.pending & VisualChange::YOrigin) {
4322 vertical_adjustment.set_value (vc.y_origin);
4325 if (last_time_origin == horizontal_position ()) {
4326 /* changed signal not emitted */
4327 update_fixed_rulers ();
4328 redisplay_tempo (true);
4331 if (!(vc.pending & VisualChange::ZoomLevel)) {
4332 update_video_timeline();
4335 _summary->set_overlays_dirty ();
4338 struct EditorOrderTimeAxisSorter {
4339 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4340 return a->order () < b->order ();
4345 Editor::sort_track_selection (TrackViewList& sel)
4347 EditorOrderTimeAxisSorter cmp;
4352 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4355 framepos_t where = 0;
4356 EditPoint ep = _edit_point;
4358 if (from_context_menu && (ep == EditAtMouse)) {
4359 return canvas_event_sample (&context_click_event, 0, 0);
4362 if (entered_marker) {
4363 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4364 return entered_marker->position();
4367 if (ignore_playhead && ep == EditAtPlayhead) {
4368 ep = EditAtSelectedMarker;
4372 case EditAtPlayhead:
4373 where = _session->audible_frame();
4374 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4377 case EditAtSelectedMarker:
4378 if (!selection->markers.empty()) {
4380 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4383 where = loc->start();
4387 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4395 if (!mouse_frame (where, ignored)) {
4396 /* XXX not right but what can we do ? */
4400 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4408 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4410 if (!_session) return;
4412 begin_reversible_command (cmd);
4416 if ((tll = transport_loop_location()) == 0) {
4417 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4418 XMLNode &before = _session->locations()->get_state();
4419 _session->locations()->add (loc, true);
4420 _session->set_auto_loop_location (loc);
4421 XMLNode &after = _session->locations()->get_state();
4422 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4424 XMLNode &before = tll->get_state();
4425 tll->set_hidden (false, this);
4426 tll->set (start, end);
4427 XMLNode &after = tll->get_state();
4428 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4431 commit_reversible_command ();
4435 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4437 if (!_session) return;
4439 begin_reversible_command (cmd);
4443 if ((tpl = transport_punch_location()) == 0) {
4444 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4445 XMLNode &before = _session->locations()->get_state();
4446 _session->locations()->add (loc, true);
4447 _session->set_auto_punch_location (loc);
4448 XMLNode &after = _session->locations()->get_state();
4449 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4452 XMLNode &before = tpl->get_state();
4453 tpl->set_hidden (false, this);
4454 tpl->set (start, end);
4455 XMLNode &after = tpl->get_state();
4456 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4459 commit_reversible_command ();
4462 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4463 * @param rs List to which found regions are added.
4464 * @param where Time to look at.
4465 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4468 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4470 const TrackViewList* tracks;
4473 tracks = &track_views;
4478 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4480 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4483 boost::shared_ptr<Track> tr;
4484 boost::shared_ptr<Playlist> pl;
4486 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4488 boost::shared_ptr<RegionList> regions = pl->regions_at (
4489 (framepos_t) floor ( (double) where * tr->speed()));
4491 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4492 RegionView* rv = rtv->view()->find_view (*i);
4503 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4505 const TrackViewList* tracks;
4508 tracks = &track_views;
4513 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4514 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4516 boost::shared_ptr<Track> tr;
4517 boost::shared_ptr<Playlist> pl;
4519 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4521 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4522 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4524 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4526 RegionView* rv = rtv->view()->find_view (*i);
4537 /** Get regions using the following method:
4539 * Make a region list using the selected regions, unless
4540 * the edit point is `mouse' and the mouse is over an unselected
4541 * region. In this case, use just that region.
4543 * If the edit point is not 'mouse', and there are no regions selected,
4544 * search the list of selected tracks and return regions that are under
4545 * the edit point on these tracks. If there are no selected tracks and
4546 * 'No Selection = All Tracks' is active, search all tracks,
4548 * The rationale here is that the mouse edit point is special in that
4549 * its position describes both a time and a track; the other edit
4550 * modes only describe a time. Hence if the edit point is `mouse' we
4551 * ignore selected tracks, as we assume the user means something by
4552 * pointing at a particular track. Also in this case we take note of
4553 * the region directly under the edit point, as there is always just one
4554 * (rather than possibly several with non-mouse edit points).
4558 Editor::get_regions_from_selection_and_edit_point ()
4560 RegionSelection regions;
4562 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4563 regions.add (entered_regionview);
4565 regions = selection->regions;
4569 if (regions.empty() && _edit_point != EditAtMouse) {
4570 TrackViewList tracks = selection->tracks;
4572 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4573 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4574 * is enabled, so consider all tracks
4576 tracks = track_views;
4579 if (!tracks.empty()) {
4580 /* no region selected or entered, but some selected tracks:
4581 * act on all regions on the selected tracks at the edit point
4583 framepos_t const where = get_preferred_edit_position ();
4584 get_regions_at(regions, where, tracks);
4590 /** Start with regions that are selected, or the entered regionview if none are selected.
4591 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4592 * of the regions that we started with.
4596 Editor::get_regions_from_selection_and_entered ()
4598 RegionSelection regions = selection->regions;
4600 if (regions.empty() && entered_regionview) {
4601 regions.add (entered_regionview);
4608 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4610 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4612 RouteTimeAxisView* tatv;
4614 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4616 boost::shared_ptr<Playlist> pl;
4617 vector<boost::shared_ptr<Region> > results;
4619 boost::shared_ptr<Track> tr;
4621 if ((tr = tatv->track()) == 0) {
4626 if ((pl = (tr->playlist())) != 0) {
4627 if (src_comparison) {
4628 pl->get_source_equivalent_regions (region, results);
4630 pl->get_region_list_equivalent_regions (region, results);
4634 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4635 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4636 regions.push_back (marv);
4645 Editor::show_rhythm_ferret ()
4647 if (rhythm_ferret == 0) {
4648 rhythm_ferret = new RhythmFerret(*this);
4651 rhythm_ferret->set_session (_session);
4652 rhythm_ferret->show ();
4653 rhythm_ferret->present ();
4657 Editor::first_idle ()
4659 MessageDialog* dialog = 0;
4661 if (track_views.size() > 1) {
4662 dialog = new MessageDialog (
4664 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4668 ARDOUR_UI::instance()->flush_pending ();
4671 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4675 // first idle adds route children (automation tracks), so we need to redisplay here
4676 _routes->redisplay ();
4683 Editor::_idle_resize (gpointer arg)
4685 return ((Editor*)arg)->idle_resize ();
4689 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4691 if (resize_idle_id < 0) {
4692 resize_idle_id = g_idle_add (_idle_resize, this);
4693 _pending_resize_amount = 0;
4696 /* make a note of the smallest resulting height, so that we can clamp the
4697 lower limit at TimeAxisView::hSmall */
4699 int32_t min_resulting = INT32_MAX;
4701 _pending_resize_amount += h;
4702 _pending_resize_view = view;
4704 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4706 if (selection->tracks.contains (_pending_resize_view)) {
4707 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4708 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4712 if (min_resulting < 0) {
4717 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4718 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4722 /** Handle pending resizing of tracks */
4724 Editor::idle_resize ()
4726 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4728 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4729 selection->tracks.contains (_pending_resize_view)) {
4731 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4732 if (*i != _pending_resize_view) {
4733 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4738 _pending_resize_amount = 0;
4739 _group_tabs->set_dirty ();
4740 resize_idle_id = -1;
4748 ENSURE_GUI_THREAD (*this, &Editor::located);
4751 playhead_cursor->set_position (_session->audible_frame ());
4752 if (_follow_playhead && !_pending_initial_locate) {
4753 reset_x_origin_to_follow_playhead ();
4757 _pending_locate_request = false;
4758 _pending_initial_locate = false;
4762 Editor::region_view_added (RegionView *)
4764 _summary->set_background_dirty ();
4768 Editor::region_view_removed ()
4770 _summary->set_background_dirty ();
4774 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4776 TrackViewList::const_iterator j = track_views.begin ();
4777 while (j != track_views.end()) {
4778 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4779 if (rtv && rtv->route() == r) {
4790 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4794 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4795 TimeAxisView* tv = axis_view_from_route (*i);
4805 Editor::suspend_route_redisplay ()
4808 _routes->suspend_redisplay();
4813 Editor::resume_route_redisplay ()
4816 _routes->resume_redisplay();
4821 Editor::add_routes (RouteList& routes)
4823 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4825 RouteTimeAxisView *rtv;
4826 list<RouteTimeAxisView*> new_views;
4828 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4829 boost::shared_ptr<Route> route = (*x);
4831 if (route->is_auditioner() || route->is_monitor()) {
4835 DataType dt = route->input()->default_type();
4837 if (dt == ARDOUR::DataType::AUDIO) {
4838 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4839 rtv->set_route (route);
4840 } else if (dt == ARDOUR::DataType::MIDI) {
4841 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4842 rtv->set_route (route);
4844 throw unknown_type();
4847 new_views.push_back (rtv);
4848 track_views.push_back (rtv);
4850 rtv->effective_gain_display ();
4852 if (internal_editing()) {
4853 rtv->enter_internal_edit_mode ();
4855 rtv->leave_internal_edit_mode ();
4858 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4859 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4862 if (new_views.size() > 0) {
4863 _routes->routes_added (new_views);
4864 _summary->routes_added (new_views);
4867 if (show_editor_mixer_when_tracks_arrive) {
4868 show_editor_mixer (true);
4871 editor_list_button.set_sensitive (true);
4875 Editor::timeaxisview_deleted (TimeAxisView *tv)
4877 if (tv == entered_track) {
4881 if (_session && _session->deletion_in_progress()) {
4882 /* the situation is under control */
4886 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4888 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4890 _routes->route_removed (tv);
4892 TimeAxisView::Children c = tv->get_child_list ();
4893 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4894 if (entered_track == i->get()) {
4899 /* remove it from the list of track views */
4901 TrackViewList::iterator i;
4903 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4904 i = track_views.erase (i);
4907 /* update whatever the current mixer strip is displaying, if revelant */
4909 boost::shared_ptr<Route> route;
4912 route = rtav->route ();
4915 if (current_mixer_strip && current_mixer_strip->route() == route) {
4917 TimeAxisView* next_tv;
4919 if (track_views.empty()) {
4921 } else if (i == track_views.end()) {
4922 next_tv = track_views.front();
4929 set_selected_mixer_strip (*next_tv);
4931 /* make the editor mixer strip go away setting the
4932 * button to inactive (which also unticks the menu option)
4935 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4941 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4943 if (apply_to_selection) {
4944 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4946 TrackSelection::iterator j = i;
4949 hide_track_in_display (*i, false);
4954 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4956 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4957 // this will hide the mixer strip
4958 set_selected_mixer_strip (*tv);
4961 _routes->hide_track_in_display (*tv);
4966 Editor::sync_track_view_list_and_routes ()
4968 track_views = TrackViewList (_routes->views ());
4970 _summary->set_dirty ();
4971 _group_tabs->set_dirty ();
4973 return false; // do not call again (until needed)
4977 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4979 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4984 /** Find a RouteTimeAxisView by the ID of its route */
4986 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4988 RouteTimeAxisView* v;
4990 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4991 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4992 if(v->route()->id() == id) {
5002 Editor::fit_route_group (RouteGroup *g)
5004 TrackViewList ts = axis_views_from_routes (g->route_list ());
5009 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5011 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5014 _session->cancel_audition ();
5018 if (_session->is_auditioning()) {
5019 _session->cancel_audition ();
5020 if (r == last_audition_region) {
5025 _session->audition_region (r);
5026 last_audition_region = r;
5031 Editor::hide_a_region (boost::shared_ptr<Region> r)
5033 r->set_hidden (true);
5037 Editor::show_a_region (boost::shared_ptr<Region> r)
5039 r->set_hidden (false);
5043 Editor::audition_region_from_region_list ()
5045 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5049 Editor::hide_region_from_region_list ()
5051 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5055 Editor::show_region_in_region_list ()
5057 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5061 Editor::step_edit_status_change (bool yn)
5064 start_step_editing ();
5066 stop_step_editing ();
5071 Editor::start_step_editing ()
5073 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5077 Editor::stop_step_editing ()
5079 step_edit_connection.disconnect ();
5083 Editor::check_step_edit ()
5085 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5086 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5088 mtv->check_step_edit ();
5092 return true; // do it again, till we stop
5096 Editor::scroll_press (Direction dir)
5098 ++_scroll_callbacks;
5100 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5101 /* delay the first auto-repeat */
5107 scroll_backward (1);
5115 scroll_tracks_up_line ();
5119 scroll_tracks_down_line ();
5123 /* do hacky auto-repeat */
5124 if (!_scroll_connection.connected ()) {
5126 _scroll_connection = Glib::signal_timeout().connect (
5127 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5130 _scroll_callbacks = 0;
5137 Editor::scroll_release ()
5139 _scroll_connection.disconnect ();
5142 /** Queue a change for the Editor viewport x origin to follow the playhead */
5144 Editor::reset_x_origin_to_follow_playhead ()
5146 framepos_t const frame = playhead_cursor->current_frame ();
5148 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5150 if (_session->transport_speed() < 0) {
5152 if (frame > (current_page_samples() / 2)) {
5153 center_screen (frame-(current_page_samples()/2));
5155 center_screen (current_page_samples()/2);
5162 if (frame < leftmost_frame) {
5164 if (_session->transport_rolling()) {
5165 /* rolling; end up with the playhead at the right of the page */
5166 l = frame - current_page_samples ();
5168 /* not rolling: end up with the playhead 1/4 of the way along the page */
5169 l = frame - current_page_samples() / 4;
5173 if (_session->transport_rolling()) {
5174 /* rolling: end up with the playhead on the left of the page */
5177 /* not rolling: end up with the playhead 3/4 of the way along the page */
5178 l = frame - 3 * current_page_samples() / 4;
5186 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5192 Editor::super_rapid_screen_update ()
5194 if (!_session || !_session->engine().running()) {
5198 /* METERING / MIXER STRIPS */
5200 /* update track meters, if required */
5201 if (is_mapped() && meters_running) {
5202 RouteTimeAxisView* rtv;
5203 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5204 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5205 rtv->fast_update ();
5210 /* and any current mixer strip */
5211 if (current_mixer_strip) {
5212 current_mixer_strip->fast_update ();
5215 /* PLAYHEAD AND VIEWPORT */
5217 framepos_t const frame = _session->audible_frame();
5219 /* There are a few reasons why we might not update the playhead / viewport stuff:
5221 * 1. we don't update things when there's a pending locate request, otherwise
5222 * when the editor requests a locate there is a chance that this method
5223 * will move the playhead before the locate request is processed, causing
5225 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5226 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5229 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5231 last_update_frame = frame;
5233 if (!_dragging_playhead) {
5234 playhead_cursor->set_position (frame);
5237 if (!_stationary_playhead) {
5239 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5240 /* We only do this if we aren't already
5241 handling a visual change (ie if
5242 pending_visual_change.being_handled is
5243 false) so that these requests don't stack
5244 up there are too many of them to handle in
5247 reset_x_origin_to_follow_playhead ();
5252 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5256 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5257 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5258 if (target <= 0.0) {
5261 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5262 target = (target * 0.15) + (current * 0.85);
5268 set_horizontal_position (current);
5277 Editor::session_going_away ()
5279 _have_idled = false;
5281 _session_connections.drop_connections ();
5283 super_rapid_screen_update_connection.disconnect ();
5285 selection->clear ();
5286 cut_buffer->clear ();
5288 clicked_regionview = 0;
5289 clicked_axisview = 0;
5290 clicked_routeview = 0;
5291 entered_regionview = 0;
5293 last_update_frame = 0;
5296 playhead_cursor->hide ();
5298 /* rip everything out of the list displays */
5302 _route_groups->clear ();
5304 /* do this first so that deleting a track doesn't reset cms to null
5305 and thus cause a leak.
5308 if (current_mixer_strip) {
5309 if (current_mixer_strip->get_parent() != 0) {
5310 global_hpacker.remove (*current_mixer_strip);
5312 delete current_mixer_strip;
5313 current_mixer_strip = 0;
5316 /* delete all trackviews */
5318 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5321 track_views.clear ();
5323 zoom_range_clock->set_session (0);
5324 nudge_clock->set_session (0);
5326 editor_list_button.set_active(false);
5327 editor_list_button.set_sensitive(false);
5329 /* clear tempo/meter rulers */
5330 remove_metric_marks ();
5332 clear_marker_display ();
5334 stop_step_editing ();
5336 /* get rid of any existing editor mixer strip */
5338 WindowTitle title(Glib::get_application_name());
5339 title += _("Editor");
5341 set_title (title.get_string());
5343 SessionHandlePtr::session_going_away ();
5348 Editor::show_editor_list (bool yn)
5351 _the_notebook.show ();
5353 _the_notebook.hide ();
5358 Editor::change_region_layering_order (bool from_context_menu)
5360 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5362 if (!clicked_routeview) {
5363 if (layering_order_editor) {
5364 layering_order_editor->hide ();
5369 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5375 boost::shared_ptr<Playlist> pl = track->playlist();
5381 if (layering_order_editor == 0) {
5382 layering_order_editor = new RegionLayeringOrderEditor (*this);
5385 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5386 layering_order_editor->maybe_present ();
5390 Editor::update_region_layering_order_editor ()
5392 if (layering_order_editor && layering_order_editor->is_visible ()) {
5393 change_region_layering_order (true);
5398 Editor::setup_fade_images ()
5400 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5401 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5402 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5403 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5404 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5406 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5407 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5408 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5409 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5410 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5412 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5413 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5414 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5415 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5416 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5418 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5419 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5420 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5421 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5422 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5426 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5428 Editor::action_menu_item (std::string const & name)
5430 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5433 return *manage (a->create_menu_item ());
5437 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5439 EventBox* b = manage (new EventBox);
5440 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5441 Label* l = manage (new Label (name));
5445 _the_notebook.append_page (widget, *b);
5449 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5451 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5452 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5455 if (ev->type == GDK_2BUTTON_PRESS) {
5457 /* double-click on a notebook tab shrinks or expands the notebook */
5459 if (_notebook_shrunk) {
5460 if (pre_notebook_shrink_pane_width) {
5461 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5463 _notebook_shrunk = false;
5465 pre_notebook_shrink_pane_width = edit_pane.get_position();
5467 /* this expands the LHS of the edit pane to cover the notebook
5468 PAGE but leaves the tabs visible.
5470 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5471 _notebook_shrunk = true;
5479 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5481 using namespace Menu_Helpers;
5483 MenuList& items = _control_point_context_menu.items ();
5486 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5487 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5488 if (!can_remove_control_point (item)) {
5489 items.back().set_sensitive (false);
5492 _control_point_context_menu.popup (event->button.button, event->button.time);
5496 Editor::zoom_vertical_modifier_released()
5498 _stepping_axis_view = 0;
5502 Editor::ui_parameter_changed (string parameter)
5504 if (parameter == "icon-set") {
5505 while (!_cursor_stack.empty()) {
5506 _cursor_stack.pop();
5508 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());