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"
124 #include "verbose_cursor.h"
129 using namespace ARDOUR;
130 using namespace ARDOUR_UI_UTILS;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_edit_mode_strings[] = {
199 static const gchar *_zoom_focus_strings[] = {
209 #ifdef USE_RUBBERBAND
210 static const gchar *_rb_opt_strings[] = {
213 N_("Balanced multitimbral mixture"),
214 N_("Unpitched percussion with stable notes"),
215 N_("Crisp monophonic instrumental"),
216 N_("Unpitched solo percussion"),
217 N_("Resample without preserving pitch"),
223 pane_size_watcher (Paned* pane)
225 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
229 Quartz: impossible to access
231 so stop that by preventing it from ever getting too narrow. 35
232 pixels is basically a rough guess at the tab width.
237 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
239 gint pos = pane->get_position ();
241 if (pos > max_width_of_lhs) {
242 pane->set_position (max_width_of_lhs);
247 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
249 /* time display buttons */
250 , minsec_label (_("Mins:Secs"))
251 , bbt_label (_("Bars:Beats"))
252 , timecode_label (_("Timecode"))
253 , samples_label (_("Samples"))
254 , tempo_label (_("Tempo"))
255 , meter_label (_("Meter"))
256 , mark_label (_("Location Markers"))
257 , range_mark_label (_("Range Markers"))
258 , transport_mark_label (_("Loop/Punch Ranges"))
259 , cd_mark_label (_("CD Markers"))
260 , videotl_label (_("Video Timeline"))
261 , edit_packer (4, 4, true)
263 /* the values here don't matter: layout widgets
264 reset them as needed.
267 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
268 , horizontal_adjustment (0.0, 0.0, 1e16)
269 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
271 , controls_layout (unused_adjustment, vertical_adjustment)
273 /* tool bar related */
275 , toolbar_selection_clock_table (2,3)
276 , _mouse_mode_tearoff (0)
277 , automation_mode_button (_("mode"))
281 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
285 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
286 , meters_running(false)
287 , _pending_locate_request (false)
288 , _pending_initial_locate (false)
289 , _last_cut_copy_source_track (0)
291 , _region_selection_change_updates_region_list (true)
292 , _following_mixer_selection (false)
293 , _control_point_toggled_on_press (false)
294 , _stepping_axis_view (0)
298 /* we are a singleton */
300 PublicEditor::_instance = this;
304 selection = new Selection (this);
305 cut_buffer = new Selection (this);
307 clicked_regionview = 0;
308 clicked_axisview = 0;
309 clicked_routeview = 0;
310 clicked_control_point = 0;
311 last_update_frame = 0;
312 pre_press_cursor = 0;
313 _drags = new DragManager (this);
316 current_mixer_strip = 0;
319 snap_type_strings = I18N (_snap_type_strings);
320 snap_mode_strings = I18N (_snap_mode_strings);
321 zoom_focus_strings = I18N (_zoom_focus_strings);
322 edit_mode_strings = I18N (_edit_mode_strings);
323 edit_point_strings = I18N (_edit_point_strings);
324 #ifdef USE_RUBBERBAND
325 rb_opt_strings = I18N (_rb_opt_strings);
329 build_edit_mode_menu();
330 build_zoom_focus_menu();
331 build_track_count_menu();
332 build_snap_mode_menu();
333 build_snap_type_menu();
334 build_edit_point_menu();
336 snap_threshold = 5.0;
337 bbt_beat_subdivision = 4;
338 _visible_canvas_width = 0;
339 _visible_canvas_height = 0;
340 autoscroll_horizontal_allowed = false;
341 autoscroll_vertical_allowed = false;
346 current_interthread_info = 0;
347 _show_measures = true;
349 show_gain_after_trim = false;
351 have_pending_keyboard_selection = false;
352 _follow_playhead = true;
353 _stationary_playhead = false;
354 editor_ruler_menu = 0;
355 no_ruler_shown_update = false;
357 range_marker_menu = 0;
358 marker_menu_item = 0;
359 tempo_or_meter_marker_menu = 0;
360 transport_marker_menu = 0;
361 new_transport_marker_menu = 0;
362 editor_mixer_strip_width = Wide;
363 show_editor_mixer_when_tracks_arrive = false;
364 region_edit_menu_split_multichannel_item = 0;
365 region_edit_menu_split_item = 0;
368 current_stepping_trackview = 0;
370 entered_regionview = 0;
372 clear_entered_track = false;
375 button_release_can_deselect = true;
376 _dragging_playhead = false;
377 _dragging_edit_point = false;
378 select_new_marker = false;
380 layering_order_editor = 0;
381 no_save_visual = false;
383 within_track_canvas = false;
385 scrubbing_direction = 0;
389 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
390 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
391 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
392 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
393 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
395 zoom_focus = ZoomFocusLeft;
396 _edit_point = EditAtMouse;
397 _internal_editing = false;
398 current_canvas_cursor = 0;
399 _visible_track_count = 16;
401 samples_per_pixel = 2048; /* too early to use reset_zoom () */
403 _scroll_callbacks = 0;
405 bbt_label.set_name ("EditorRulerLabel");
406 bbt_label.set_size_request (-1, (int)timebar_height);
407 bbt_label.set_alignment (1.0, 0.5);
408 bbt_label.set_padding (5,0);
410 bbt_label.set_no_show_all();
411 minsec_label.set_name ("EditorRulerLabel");
412 minsec_label.set_size_request (-1, (int)timebar_height);
413 minsec_label.set_alignment (1.0, 0.5);
414 minsec_label.set_padding (5,0);
415 minsec_label.hide ();
416 minsec_label.set_no_show_all();
417 timecode_label.set_name ("EditorRulerLabel");
418 timecode_label.set_size_request (-1, (int)timebar_height);
419 timecode_label.set_alignment (1.0, 0.5);
420 timecode_label.set_padding (5,0);
421 timecode_label.hide ();
422 timecode_label.set_no_show_all();
423 samples_label.set_name ("EditorRulerLabel");
424 samples_label.set_size_request (-1, (int)timebar_height);
425 samples_label.set_alignment (1.0, 0.5);
426 samples_label.set_padding (5,0);
427 samples_label.hide ();
428 samples_label.set_no_show_all();
430 tempo_label.set_name ("EditorRulerLabel");
431 tempo_label.set_size_request (-1, (int)timebar_height);
432 tempo_label.set_alignment (1.0, 0.5);
433 tempo_label.set_padding (5,0);
435 tempo_label.set_no_show_all();
437 meter_label.set_name ("EditorRulerLabel");
438 meter_label.set_size_request (-1, (int)timebar_height);
439 meter_label.set_alignment (1.0, 0.5);
440 meter_label.set_padding (5,0);
442 meter_label.set_no_show_all();
444 if (Profile->get_trx()) {
445 mark_label.set_text (_("Markers"));
447 mark_label.set_name ("EditorRulerLabel");
448 mark_label.set_size_request (-1, (int)timebar_height);
449 mark_label.set_alignment (1.0, 0.5);
450 mark_label.set_padding (5,0);
452 mark_label.set_no_show_all();
454 cd_mark_label.set_name ("EditorRulerLabel");
455 cd_mark_label.set_size_request (-1, (int)timebar_height);
456 cd_mark_label.set_alignment (1.0, 0.5);
457 cd_mark_label.set_padding (5,0);
458 cd_mark_label.hide();
459 cd_mark_label.set_no_show_all();
461 videotl_bar_height = 4;
462 videotl_label.set_name ("EditorRulerLabel");
463 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
464 videotl_label.set_alignment (1.0, 0.5);
465 videotl_label.set_padding (5,0);
466 videotl_label.hide();
467 videotl_label.set_no_show_all();
469 range_mark_label.set_name ("EditorRulerLabel");
470 range_mark_label.set_size_request (-1, (int)timebar_height);
471 range_mark_label.set_alignment (1.0, 0.5);
472 range_mark_label.set_padding (5,0);
473 range_mark_label.hide();
474 range_mark_label.set_no_show_all();
476 transport_mark_label.set_name ("EditorRulerLabel");
477 transport_mark_label.set_size_request (-1, (int)timebar_height);
478 transport_mark_label.set_alignment (1.0, 0.5);
479 transport_mark_label.set_padding (5,0);
480 transport_mark_label.hide();
481 transport_mark_label.set_no_show_all();
483 initialize_canvas ();
485 _summary = new EditorSummary (this);
487 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
488 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
490 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
492 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
493 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
495 edit_controls_vbox.set_spacing (0);
496 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
497 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
499 HBox* h = manage (new HBox);
500 _group_tabs = new EditorGroupTabs (this);
501 if (!ARDOUR::Profile->get_trx()) {
502 h->pack_start (*_group_tabs, PACK_SHRINK);
504 h->pack_start (edit_controls_vbox);
505 controls_layout.add (*h);
507 controls_layout.set_name ("EditControlsBase");
508 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK|Gdk::SCROLL_MASK);
509 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
510 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
512 _cursors = new MouseCursors;
513 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
514 cerr << "Set cursor set to " << ARDOUR_UI::config()->get_icon_set() << endl;
516 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
518 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
519 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
520 pad_line_1->set_outline_color (0xFF0000FF);
526 edit_packer.set_col_spacings (0);
527 edit_packer.set_row_spacings (0);
528 edit_packer.set_homogeneous (false);
529 edit_packer.set_border_width (0);
530 edit_packer.set_name ("EditorWindow");
532 time_bars_event_box.add (time_bars_vbox);
533 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
534 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
536 /* labels for the time bars */
537 edit_packer.attach (time_bars_event_box, 0, 1, 0, 1, FILL, SHRINK, 0, 0);
539 edit_packer.attach (controls_layout, 0, 1, 1, 2, FILL, FILL|EXPAND, 0, 0);
541 edit_packer.attach (*_track_canvas_viewport, 1, 2, 0, 2, FILL|EXPAND, FILL|EXPAND, 0, 0);
543 bottom_hbox.set_border_width (2);
544 bottom_hbox.set_spacing (3);
546 _route_groups = new EditorRouteGroups (this);
547 _routes = new EditorRoutes (this);
548 _regions = new EditorRegions (this);
549 _snapshots = new EditorSnapshots (this);
550 _locations = new EditorLocations (this);
552 add_notebook_page (_("Regions"), _regions->widget ());
553 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
554 add_notebook_page (_("Snapshots"), _snapshots->widget ());
555 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
556 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
558 _the_notebook.set_show_tabs (true);
559 _the_notebook.set_scrollable (true);
560 _the_notebook.popup_disable ();
561 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
562 _the_notebook.show_all ();
564 _notebook_shrunk = false;
566 editor_summary_pane.pack1(edit_packer);
568 Button* summary_arrows_left_left = manage (new Button);
569 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
570 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
571 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
573 Button* summary_arrows_left_right = manage (new Button);
574 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
575 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
576 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 VBox* summary_arrows_left = manage (new VBox);
579 summary_arrows_left->pack_start (*summary_arrows_left_left);
580 summary_arrows_left->pack_start (*summary_arrows_left_right);
582 Button* summary_arrows_right_up = manage (new Button);
583 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
584 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
585 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
587 Button* summary_arrows_right_down = manage (new Button);
588 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
589 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
590 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
592 VBox* summary_arrows_right = manage (new VBox);
593 summary_arrows_right->pack_start (*summary_arrows_right_up);
594 summary_arrows_right->pack_start (*summary_arrows_right_down);
596 Frame* summary_frame = manage (new Frame);
597 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
599 summary_frame->add (*_summary);
600 summary_frame->show ();
602 _summary_hbox.pack_start (*summary_arrows_left, false, false);
603 _summary_hbox.pack_start (*summary_frame, true, true);
604 _summary_hbox.pack_start (*summary_arrows_right, false, false);
606 if (!ARDOUR::Profile->get_trx()) {
607 editor_summary_pane.pack2 (_summary_hbox);
610 edit_pane.pack1 (editor_summary_pane, true, true);
611 if (!ARDOUR::Profile->get_trx()) {
612 edit_pane.pack2 (_the_notebook, false, true);
615 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
617 /* XXX: editor_summary_pane might need similar to the edit_pane */
619 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
621 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
622 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
624 top_hbox.pack_start (toolbar_frame);
626 HBox *hbox = manage (new HBox);
627 hbox->pack_start (edit_pane, true, true);
629 global_vpacker.pack_start (top_hbox, false, false);
630 global_vpacker.pack_start (*hbox, true, true);
632 global_hpacker.pack_start (global_vpacker, true, true);
634 set_name ("EditorWindow");
635 add_accel_group (ActionManager::ui_manager->get_accel_group());
637 status_bar_hpacker.show ();
639 vpacker.pack_end (status_bar_hpacker, false, false);
640 vpacker.pack_end (global_hpacker, true, true);
642 /* register actions now so that set_state() can find them and set toggles/checks etc */
645 /* when we start using our own keybinding system for the editor, this
646 * will be uncommented
652 set_zoom_focus (zoom_focus);
653 set_visible_track_count (_visible_track_count);
654 _snap_type = SnapToBeat;
655 set_snap_to (_snap_type);
656 _snap_mode = SnapOff;
657 set_snap_mode (_snap_mode);
658 set_mouse_mode (MouseObject, true);
659 pre_internal_mouse_mode = MouseObject;
660 pre_internal_snap_type = _snap_type;
661 pre_internal_snap_mode = _snap_mode;
662 internal_snap_type = _snap_type;
663 internal_snap_mode = _snap_mode;
664 set_edit_point_preference (EditAtMouse, true);
666 _playlist_selector = new PlaylistSelector();
667 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
669 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
673 nudge_forward_button.set_name ("nudge button");
674 // nudge_forward_button.add_elements (ArdourButton::Inset);
675 nudge_forward_button.set_image(::get_icon("nudge_right"));
677 nudge_backward_button.set_name ("nudge button");
678 // nudge_backward_button.add_elements (ArdourButton::Inset);
679 nudge_backward_button.set_image(::get_icon("nudge_left"));
681 fade_context_menu.set_name ("ArdourContextMenu");
683 /* icons, titles, WM stuff */
685 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
686 Glib::RefPtr<Gdk::Pixbuf> icon;
688 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
689 window_icons.push_back (icon);
691 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
692 window_icons.push_back (icon);
694 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
695 window_icons.push_back (icon);
697 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
698 window_icons.push_back (icon);
700 if (!window_icons.empty()) {
701 // set_icon_list (window_icons);
702 set_default_icon_list (window_icons);
705 WindowTitle title(Glib::get_application_name());
706 title += _("Editor");
707 set_title (title.get_string());
708 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
711 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
713 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
714 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
716 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
718 /* allow external control surfaces/protocols to do various things */
720 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
721 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
722 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
723 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
724 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
725 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
726 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
727 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
728 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
729 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
730 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
731 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
732 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
733 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
735 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
736 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
737 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
738 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
739 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
741 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
743 /* problematic: has to return a value and thus cannot be x-thread */
745 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
747 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
748 ARDOUR_UI::config()->ParameterChanged.connect (sigc::mem_fun (*this, &Editor::ui_parameter_changed));
750 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
752 _ignore_region_action = false;
753 _last_region_menu_was_main = false;
754 _popup_region_menu_item = 0;
756 _ignore_follow_edits = false;
758 _show_marker_lines = false;
760 /* Button bindings */
762 button_bindings = new Bindings;
764 XMLNode* node = button_settings();
766 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
767 button_bindings->load (**i);
773 /* grab current parameter state */
774 boost::function<void (string)> pc (boost::bind (&Editor::ui_parameter_changed, this, _1));
775 ARDOUR_UI::config()->map_parameters (pc);
777 setup_fade_images ();
784 delete button_bindings;
786 delete _route_groups;
787 delete _track_canvas_viewport;
792 Editor::button_settings () const
794 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
795 XMLNode* node = find_named_node (*settings, X_("Buttons"));
798 node = new XMLNode (X_("Buttons"));
805 Editor::add_toplevel_controls (Container& cont)
807 vpacker.pack_start (cont, false, false);
812 Editor::get_smart_mode () const
814 return ((current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active());
818 Editor::catch_vanishing_regionview (RegionView *rv)
820 /* note: the selection will take care of the vanishing
821 audioregionview by itself.
824 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
828 if (clicked_regionview == rv) {
829 clicked_regionview = 0;
832 if (entered_regionview == rv) {
833 set_entered_regionview (0);
836 if (!_all_region_actions_sensitized) {
837 sensitize_all_region_actions (true);
842 Editor::set_entered_regionview (RegionView* rv)
844 if (rv == entered_regionview) {
848 if (entered_regionview) {
849 entered_regionview->exited ();
852 entered_regionview = rv;
854 if (entered_regionview != 0) {
855 entered_regionview->entered (internal_editing ());
858 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
859 /* This RegionView entry might have changed what region actions
860 are allowed, so sensitize them all in case a key is pressed.
862 sensitize_all_region_actions (true);
867 Editor::set_entered_track (TimeAxisView* tav)
870 entered_track->exited ();
876 entered_track->entered ();
881 Editor::show_window ()
883 if (!is_visible ()) {
886 /* XXX: this is a bit unfortunate; it would probably
887 be nicer if we could just call show () above rather
888 than needing the show_all ()
891 /* re-hide stuff if necessary */
892 editor_list_button_toggled ();
893 parameter_changed ("show-summary");
894 parameter_changed ("show-group-tabs");
895 parameter_changed ("show-zoom-tools");
897 /* now reset all audio_time_axis heights, because widgets might need
903 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
904 tv = (static_cast<TimeAxisView*>(*i));
908 if (current_mixer_strip) {
909 current_mixer_strip->hide_things ();
910 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
918 Editor::instant_save ()
920 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
925 _session->add_instant_xml(get_state());
927 Config->add_instant_xml(get_state());
932 Editor::control_vertical_zoom_in_all ()
934 tav_zoom_smooth (false, true);
938 Editor::control_vertical_zoom_out_all ()
940 tav_zoom_smooth (true, true);
944 Editor::control_vertical_zoom_in_selected ()
946 tav_zoom_smooth (false, false);
950 Editor::control_vertical_zoom_out_selected ()
952 tav_zoom_smooth (true, false);
956 Editor::control_view (uint32_t view)
958 goto_visual_state (view);
962 Editor::control_unselect ()
964 selection->clear_tracks ();
968 Editor::control_select (uint32_t rid, Selection::Operation op)
970 /* handles the (static) signal from the ControlProtocol class that
971 * requests setting the selected track to a given RID
978 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
984 TimeAxisView* tav = axis_view_from_route (r);
989 selection->add (tav);
991 case Selection::Toggle:
992 selection->toggle (tav);
994 case Selection::Extend:
997 selection->set (tav);
1001 selection->clear_tracks ();
1006 Editor::control_step_tracks_up ()
1008 scroll_tracks_up_line ();
1012 Editor::control_step_tracks_down ()
1014 scroll_tracks_down_line ();
1018 Editor::control_scroll (float fraction)
1020 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1026 double step = fraction * current_page_samples();
1029 _control_scroll_target is an optional<T>
1031 it acts like a pointer to an framepos_t, with
1032 a operator conversion to boolean to check
1033 that it has a value could possibly use
1034 playhead_cursor->current_frame to store the
1035 value and a boolean in the class to know
1036 when it's out of date
1039 if (!_control_scroll_target) {
1040 _control_scroll_target = _session->transport_frame();
1041 _dragging_playhead = true;
1044 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1045 *_control_scroll_target = 0;
1046 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1047 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1049 *_control_scroll_target += (framepos_t) floor (step);
1052 /* move visuals, we'll catch up with it later */
1054 playhead_cursor->set_position (*_control_scroll_target);
1055 UpdateAllTransportClocks (*_control_scroll_target);
1057 if (*_control_scroll_target > (current_page_samples() / 2)) {
1058 /* try to center PH in window */
1059 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1065 Now we do a timeout to actually bring the session to the right place
1066 according to the playhead. This is to avoid reading disk buffers on every
1067 call to control_scroll, which is driven by ScrollTimeline and therefore
1068 probably by a control surface wheel which can generate lots of events.
1070 /* cancel the existing timeout */
1072 control_scroll_connection.disconnect ();
1074 /* add the next timeout */
1076 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1080 Editor::deferred_control_scroll (framepos_t /*target*/)
1082 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1083 // reset for next stream
1084 _control_scroll_target = boost::none;
1085 _dragging_playhead = false;
1090 Editor::access_action (std::string action_group, std::string action_item)
1096 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1099 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1107 Editor::on_realize ()
1109 Window::on_realize ();
1112 if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1113 start_lock_event_timing ();
1116 signal_event().connect (sigc::mem_fun (*this, &Editor::generic_event_handler));
1120 Editor::start_lock_event_timing ()
1122 /* check if we should lock the GUI every 30 seconds */
1124 Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::lock_timeout_callback), 30 * 1000);
1128 Editor::generic_event_handler (GdkEvent* ev)
1131 case GDK_BUTTON_PRESS:
1132 case GDK_BUTTON_RELEASE:
1133 case GDK_MOTION_NOTIFY:
1135 case GDK_KEY_RELEASE:
1136 gettimeofday (&last_event_time, 0);
1145 Editor::lock_timeout_callback ()
1147 struct timeval now, delta;
1149 gettimeofday (&now, 0);
1151 timersub (&now, &last_event_time, &delta);
1153 if (delta.tv_sec > ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
1155 /* don't call again. Returning false will effectively
1156 disconnect us from the timer callback.
1158 unlock() will call start_lock_event_timing() to get things
1168 Editor::map_position_change (framepos_t frame)
1170 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1172 if (_session == 0) {
1176 if (_follow_playhead) {
1177 center_screen (frame);
1180 playhead_cursor->set_position (frame);
1184 Editor::center_screen (framepos_t frame)
1186 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1188 /* if we're off the page, then scroll.
1191 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1192 center_screen_internal (frame, page);
1197 Editor::center_screen_internal (framepos_t frame, float page)
1202 frame -= (framepos_t) page;
1207 reset_x_origin (frame);
1212 Editor::update_title ()
1214 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1217 bool dirty = _session->dirty();
1219 string session_name;
1221 if (_session->snap_name() != _session->name()) {
1222 session_name = _session->snap_name();
1224 session_name = _session->name();
1228 session_name = "*" + session_name;
1231 WindowTitle title(session_name);
1232 title += Glib::get_application_name();
1233 set_title (title.get_string());
1235 /* ::session_going_away() will have taken care of it */
1240 Editor::set_session (Session *t)
1242 SessionHandlePtr::set_session (t);
1248 _playlist_selector->set_session (_session);
1249 nudge_clock->set_session (_session);
1250 _summary->set_session (_session);
1251 _group_tabs->set_session (_session);
1252 _route_groups->set_session (_session);
1253 _regions->set_session (_session);
1254 _snapshots->set_session (_session);
1255 _routes->set_session (_session);
1256 _locations->set_session (_session);
1258 if (rhythm_ferret) {
1259 rhythm_ferret->set_session (_session);
1262 if (analysis_window) {
1263 analysis_window->set_session (_session);
1267 sfbrowser->set_session (_session);
1270 compute_fixed_ruler_scale ();
1272 /* Make sure we have auto loop and auto punch ranges */
1274 Location* loc = _session->locations()->auto_loop_location();
1276 loc->set_name (_("Loop"));
1279 loc = _session->locations()->auto_punch_location();
1282 loc->set_name (_("Punch"));
1285 refresh_location_display ();
1287 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1288 the selected Marker; this needs the LocationMarker list to be available.
1290 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1291 set_state (*node, Stateful::loading_state_version);
1293 /* catch up with the playhead */
1295 _session->request_locate (playhead_cursor->current_frame ());
1296 _pending_initial_locate = true;
1300 /* These signals can all be emitted by a non-GUI thread. Therefore the
1301 handlers for them must not attempt to directly interact with the GUI,
1302 but use PBD::Signal<T>::connect() which accepts an event loop
1303 ("context") where the handler will be asked to run.
1306 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1307 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1308 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1309 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1310 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1311 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1312 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1313 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1314 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1315 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1316 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1317 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1318 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1319 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1321 playhead_cursor->show ();
1323 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1324 Config->map_parameters (pc);
1325 _session->config.map_parameters (pc);
1327 restore_ruler_visibility ();
1328 //tempo_map_changed (PropertyChange (0));
1329 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1331 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1332 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1335 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1336 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1339 switch (_snap_type) {
1340 case SnapToRegionStart:
1341 case SnapToRegionEnd:
1342 case SnapToRegionSync:
1343 case SnapToRegionBoundary:
1344 build_region_boundary_cache ();
1351 /* register for undo history */
1352 _session->register_with_memento_command_factory(id(), this);
1354 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1356 start_updating_meters ();
1360 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1362 if (a->get_name() == "RegionMenu") {
1363 /* When the main menu's region menu is opened, we setup the actions so that they look right
1364 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1365 so we resensitize all region actions when the entered regionview or the region selection
1366 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1367 happens after the region context menu is opened. So we set a flag here, too.
1371 sensitize_the_right_region_actions ();
1372 _last_region_menu_was_main = true;
1377 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1379 using namespace Menu_Helpers;
1381 void (Editor::*emf)(FadeShape);
1382 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1385 images = &_xfade_in_images;
1386 emf = &Editor::set_fade_in_shape;
1388 images = &_xfade_out_images;
1389 emf = &Editor::set_fade_out_shape;
1394 _("Linear (for highly correlated material)"),
1395 *(*images)[FadeLinear],
1396 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1400 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1404 _("Constant power"),
1405 *(*images)[FadeConstantPower],
1406 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1409 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1414 *(*images)[FadeSymmetric],
1415 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1419 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1424 *(*images)[FadeSlow],
1425 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1428 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1433 *(*images)[FadeFast],
1434 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1437 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1440 /** Pop up a context menu for when the user clicks on a start crossfade */
1442 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1444 using namespace Menu_Helpers;
1445 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1448 MenuList& items (xfade_in_context_menu.items());
1451 if (arv->audio_region()->fade_in_active()) {
1452 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1454 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1457 items.push_back (SeparatorElem());
1458 fill_xfade_menu (items, true);
1460 xfade_in_context_menu.popup (button, time);
1463 /** Pop up a context menu for when the user clicks on an end crossfade */
1465 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType /*item_type*/)
1467 using namespace Menu_Helpers;
1468 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1471 MenuList& items (xfade_out_context_menu.items());
1474 if (arv->audio_region()->fade_out_active()) {
1475 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1477 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1480 items.push_back (SeparatorElem());
1481 fill_xfade_menu (items, false);
1483 xfade_out_context_menu.popup (button, time);
1487 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1489 using namespace Menu_Helpers;
1490 Menu* (Editor::*build_menu_function)();
1493 switch (item_type) {
1495 case RegionViewName:
1496 case RegionViewNameHighlight:
1497 case LeftFrameHandle:
1498 case RightFrameHandle:
1499 if (with_selection) {
1500 build_menu_function = &Editor::build_track_selection_context_menu;
1502 build_menu_function = &Editor::build_track_region_context_menu;
1507 if (with_selection) {
1508 build_menu_function = &Editor::build_track_selection_context_menu;
1510 build_menu_function = &Editor::build_track_context_menu;
1515 if (clicked_routeview->track()) {
1516 build_menu_function = &Editor::build_track_context_menu;
1518 build_menu_function = &Editor::build_track_bus_context_menu;
1523 /* probably shouldn't happen but if it does, we don't care */
1527 menu = (this->*build_menu_function)();
1528 menu->set_name ("ArdourContextMenu");
1530 /* now handle specific situations */
1532 switch (item_type) {
1534 case RegionViewName:
1535 case RegionViewNameHighlight:
1536 case LeftFrameHandle:
1537 case RightFrameHandle:
1538 if (!with_selection) {
1539 if (region_edit_menu_split_item) {
1540 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1541 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1543 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1546 if (region_edit_menu_split_multichannel_item) {
1547 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1548 region_edit_menu_split_multichannel_item->set_sensitive (true);
1550 region_edit_menu_split_multichannel_item->set_sensitive (false);
1563 /* probably shouldn't happen but if it does, we don't care */
1567 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1569 /* Bounce to disk */
1571 using namespace Menu_Helpers;
1572 MenuList& edit_items = menu->items();
1574 edit_items.push_back (SeparatorElem());
1576 switch (clicked_routeview->audio_track()->freeze_state()) {
1577 case AudioTrack::NoFreeze:
1578 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1581 case AudioTrack::Frozen:
1582 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1585 case AudioTrack::UnFrozen:
1586 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1592 if (item_type == StreamItem && clicked_routeview) {
1593 clicked_routeview->build_underlay_menu(menu);
1596 /* When the region menu is opened, we setup the actions so that they look right
1599 sensitize_the_right_region_actions ();
1600 _last_region_menu_was_main = false;
1602 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1603 menu->popup (button, time);
1607 Editor::build_track_context_menu ()
1609 using namespace Menu_Helpers;
1611 MenuList& edit_items = track_context_menu.items();
1614 add_dstream_context_items (edit_items);
1615 return &track_context_menu;
1619 Editor::build_track_bus_context_menu ()
1621 using namespace Menu_Helpers;
1623 MenuList& edit_items = track_context_menu.items();
1626 add_bus_context_items (edit_items);
1627 return &track_context_menu;
1631 Editor::build_track_region_context_menu ()
1633 using namespace Menu_Helpers;
1634 MenuList& edit_items = track_region_context_menu.items();
1637 /* we've just cleared the track region context menu, so the menu that these
1638 two items were on will have disappeared; stop them dangling.
1640 region_edit_menu_split_item = 0;
1641 region_edit_menu_split_multichannel_item = 0;
1643 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1646 boost::shared_ptr<Track> tr;
1647 boost::shared_ptr<Playlist> pl;
1649 if ((tr = rtv->track())) {
1650 add_region_context_items (edit_items, tr);
1654 add_dstream_context_items (edit_items);
1656 return &track_region_context_menu;
1660 Editor::analyze_region_selection ()
1662 if (analysis_window == 0) {
1663 analysis_window = new AnalysisWindow();
1666 analysis_window->set_session(_session);
1668 analysis_window->show_all();
1671 analysis_window->set_regionmode();
1672 analysis_window->analyze();
1674 analysis_window->present();
1678 Editor::analyze_range_selection()
1680 if (analysis_window == 0) {
1681 analysis_window = new AnalysisWindow();
1684 analysis_window->set_session(_session);
1686 analysis_window->show_all();
1689 analysis_window->set_rangemode();
1690 analysis_window->analyze();
1692 analysis_window->present();
1696 Editor::build_track_selection_context_menu ()
1698 using namespace Menu_Helpers;
1699 MenuList& edit_items = track_selection_context_menu.items();
1700 edit_items.clear ();
1702 add_selection_context_items (edit_items);
1703 // edit_items.push_back (SeparatorElem());
1704 // add_dstream_context_items (edit_items);
1706 return &track_selection_context_menu;
1710 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1712 using namespace Menu_Helpers;
1714 /* OK, stick the region submenu at the top of the list, and then add
1718 RegionSelection rs = get_regions_from_selection_and_entered ();
1720 string::size_type pos = 0;
1721 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1723 /* we have to hack up the region name because "_" has a special
1724 meaning for menu titles.
1727 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1728 menu_item_name.replace (pos, 1, "__");
1732 if (_popup_region_menu_item == 0) {
1733 _popup_region_menu_item = new MenuItem (menu_item_name);
1734 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1735 _popup_region_menu_item->show ();
1737 _popup_region_menu_item->set_label (menu_item_name);
1740 const framepos_t position = get_preferred_edit_position (false, true);
1742 edit_items.push_back (*_popup_region_menu_item);
1743 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1744 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1746 edit_items.push_back (SeparatorElem());
1749 /** Add context menu items relevant to selection ranges.
1750 * @param edit_items List to add the items to.
1753 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1755 using namespace Menu_Helpers;
1757 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1758 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1760 edit_items.push_back (SeparatorElem());
1761 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1763 edit_items.push_back (SeparatorElem());
1765 edit_items.push_back (
1767 _("Move Range Start to Previous Region Boundary"),
1768 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1772 edit_items.push_back (
1774 _("Move Range Start to Next Region Boundary"),
1775 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1779 edit_items.push_back (
1781 _("Move Range End to Previous Region Boundary"),
1782 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1786 edit_items.push_back (
1788 _("Move Range End to Next Region Boundary"),
1789 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1793 edit_items.push_back (SeparatorElem());
1794 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1795 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1797 edit_items.push_back (SeparatorElem());
1798 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1800 edit_items.push_back (SeparatorElem());
1801 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1802 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1804 edit_items.push_back (SeparatorElem());
1805 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1807 edit_items.push_back (SeparatorElem());
1808 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1809 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1810 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1812 edit_items.push_back (SeparatorElem());
1813 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1814 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1815 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1816 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1817 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1818 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1819 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1825 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1827 using namespace Menu_Helpers;
1831 Menu *play_menu = manage (new Menu);
1832 MenuList& play_items = play_menu->items();
1833 play_menu->set_name ("ArdourContextMenu");
1835 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1836 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1837 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1838 play_items.push_back (SeparatorElem());
1839 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1841 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1845 Menu *select_menu = manage (new Menu);
1846 MenuList& select_items = select_menu->items();
1847 select_menu->set_name ("ArdourContextMenu");
1849 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1850 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1851 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1852 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1853 select_items.push_back (SeparatorElem());
1854 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1855 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1856 select_items.push_back (SeparatorElem());
1857 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1858 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1859 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1860 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1861 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1862 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1863 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1865 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1869 Menu *cutnpaste_menu = manage (new Menu);
1870 MenuList& cutnpaste_items = cutnpaste_menu->items();
1871 cutnpaste_menu->set_name ("ArdourContextMenu");
1873 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1874 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1875 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1877 cutnpaste_items.push_back (SeparatorElem());
1879 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1880 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1882 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1884 /* Adding new material */
1886 edit_items.push_back (SeparatorElem());
1887 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1888 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1892 Menu *nudge_menu = manage (new Menu());
1893 MenuList& nudge_items = nudge_menu->items();
1894 nudge_menu->set_name ("ArdourContextMenu");
1896 edit_items.push_back (SeparatorElem());
1897 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1898 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1899 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1900 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1902 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1906 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1908 using namespace Menu_Helpers;
1912 Menu *play_menu = manage (new Menu);
1913 MenuList& play_items = play_menu->items();
1914 play_menu->set_name ("ArdourContextMenu");
1916 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1917 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1918 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1922 Menu *select_menu = manage (new Menu);
1923 MenuList& select_items = select_menu->items();
1924 select_menu->set_name ("ArdourContextMenu");
1926 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1927 select_items.push_back (MenuElem (_("Select All Objects"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_objects), Selection::Set)));
1928 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1929 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1930 select_items.push_back (SeparatorElem());
1931 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1932 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1933 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1934 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1936 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1940 Menu *cutnpaste_menu = manage (new Menu);
1941 MenuList& cutnpaste_items = cutnpaste_menu->items();
1942 cutnpaste_menu->set_name ("ArdourContextMenu");
1944 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1945 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1946 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1948 Menu *nudge_menu = manage (new Menu());
1949 MenuList& nudge_items = nudge_menu->items();
1950 nudge_menu->set_name ("ArdourContextMenu");
1952 edit_items.push_back (SeparatorElem());
1953 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1954 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1955 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1956 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1958 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1962 Editor::snap_type() const
1968 Editor::snap_mode() const
1974 Editor::set_snap_to (SnapType st)
1976 unsigned int snap_ind = (unsigned int)st;
1980 if (snap_ind > snap_type_strings.size() - 1) {
1982 _snap_type = (SnapType)snap_ind;
1985 string str = snap_type_strings[snap_ind];
1987 if (str != snap_type_selector.get_text()) {
1988 snap_type_selector.set_text (str);
1993 switch (_snap_type) {
1994 case SnapToBeatDiv128:
1995 case SnapToBeatDiv64:
1996 case SnapToBeatDiv32:
1997 case SnapToBeatDiv28:
1998 case SnapToBeatDiv24:
1999 case SnapToBeatDiv20:
2000 case SnapToBeatDiv16:
2001 case SnapToBeatDiv14:
2002 case SnapToBeatDiv12:
2003 case SnapToBeatDiv10:
2004 case SnapToBeatDiv8:
2005 case SnapToBeatDiv7:
2006 case SnapToBeatDiv6:
2007 case SnapToBeatDiv5:
2008 case SnapToBeatDiv4:
2009 case SnapToBeatDiv3:
2010 case SnapToBeatDiv2: {
2011 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2012 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2014 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2015 current_bbt_points_begin, current_bbt_points_end);
2016 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2017 current_bbt_points_begin, current_bbt_points_end);
2018 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2022 case SnapToRegionStart:
2023 case SnapToRegionEnd:
2024 case SnapToRegionSync:
2025 case SnapToRegionBoundary:
2026 build_region_boundary_cache ();
2034 SnapChanged (); /* EMIT SIGNAL */
2038 Editor::set_snap_mode (SnapMode mode)
2040 string str = snap_mode_strings[(int)mode];
2042 if (_internal_editing) {
2043 internal_snap_mode = mode;
2045 pre_internal_snap_mode = mode;
2050 if (str != snap_mode_selector.get_text ()) {
2051 snap_mode_selector.set_text (str);
2057 Editor::set_edit_point_preference (EditPoint ep, bool force)
2059 bool changed = (_edit_point != ep);
2062 string str = edit_point_strings[(int)ep];
2064 if (str != edit_point_selector.get_text ()) {
2065 edit_point_selector.set_text (str);
2068 reset_canvas_cursor ();
2070 if (!force && !changed) {
2074 const char* action=NULL;
2076 switch (_edit_point) {
2077 case EditAtPlayhead:
2078 action = "edit-at-playhead";
2080 case EditAtSelectedMarker:
2081 action = "edit-at-marker";
2084 action = "edit-at-mouse";
2088 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2090 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2094 bool in_track_canvas;
2096 if (!mouse_frame (foo, in_track_canvas)) {
2097 in_track_canvas = false;
2100 reset_canvas_action_sensitivity (in_track_canvas);
2106 Editor::set_state (const XMLNode& node, int /*version*/)
2108 const XMLProperty* prop;
2115 g.base_width = default_width;
2116 g.base_height = default_height;
2120 if ((geometry = find_named_node (node, "geometry")) != 0) {
2124 if ((prop = geometry->property("x_size")) == 0) {
2125 prop = geometry->property ("x-size");
2128 g.base_width = atoi(prop->value());
2130 if ((prop = geometry->property("y_size")) == 0) {
2131 prop = geometry->property ("y-size");
2134 g.base_height = atoi(prop->value());
2137 if ((prop = geometry->property ("x_pos")) == 0) {
2138 prop = geometry->property ("x-pos");
2141 x = atoi (prop->value());
2144 if ((prop = geometry->property ("y_pos")) == 0) {
2145 prop = geometry->property ("y-pos");
2148 y = atoi (prop->value());
2152 set_default_size (g.base_width, g.base_height);
2155 if (_session && (prop = node.property ("playhead"))) {
2157 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2158 playhead_cursor->set_position (pos);
2160 playhead_cursor->set_position (0);
2163 if ((prop = node.property ("mixer-width"))) {
2164 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2167 if ((prop = node.property ("zoom-focus"))) {
2168 zoom_focus_selection_done ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2171 if ((prop = node.property ("zoom"))) {
2172 /* older versions of ardour used floating point samples_per_pixel */
2173 double f = PBD::atof (prop->value());
2174 reset_zoom (llrintf (f));
2176 reset_zoom (samples_per_pixel);
2179 if ((prop = node.property ("visible-track-count"))) {
2180 set_visible_track_count (PBD::atoi (prop->value()));
2183 if ((prop = node.property ("snap-to"))) {
2184 snap_type_selection_done ((SnapType) string_2_enum (prop->value(), _snap_type));
2187 if ((prop = node.property ("snap-mode"))) {
2188 snap_mode_selection_done((SnapMode) string_2_enum (prop->value(), _snap_mode));
2191 if ((prop = node.property ("internal-snap-to"))) {
2192 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2195 if ((prop = node.property ("internal-snap-mode"))) {
2196 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2199 if ((prop = node.property ("pre-internal-snap-to"))) {
2200 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2204 if ((prop = node.property ("pre-internal-snap-mode"))) {
2205 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2208 if ((prop = node.property ("mouse-mode"))) {
2209 MouseMode m = str2mousemode(prop->value());
2210 set_mouse_mode (m, true);
2212 set_mouse_mode (MouseObject, true);
2215 if ((prop = node.property ("left-frame")) != 0) {
2217 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2221 reset_x_origin (pos);
2225 if ((prop = node.property ("y-origin")) != 0) {
2226 reset_y_origin (atof (prop->value ()));
2229 if ((prop = node.property ("internal-edit"))) {
2230 bool yn = string_is_affirmative (prop->value());
2231 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2233 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2234 tact->set_active (!yn);
2235 tact->set_active (yn);
2239 if ((prop = node.property ("join-object-range"))) {
2240 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2241 bool yn = string_is_affirmative (prop->value());
2243 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2244 tact->set_active (!yn);
2245 tact->set_active (yn);
2247 set_mouse_mode(mouse_mode, true);
2250 if ((prop = node.property ("edit-point"))) {
2251 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2254 if ((prop = node.property ("show-measures"))) {
2255 bool yn = string_is_affirmative (prop->value());
2256 _show_measures = yn;
2257 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2259 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2260 /* do it twice to force the change */
2261 tact->set_active (!yn);
2262 tact->set_active (yn);
2266 if ((prop = node.property ("follow-playhead"))) {
2267 bool yn = string_is_affirmative (prop->value());
2268 set_follow_playhead (yn);
2269 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2271 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2272 if (tact->get_active() != yn) {
2273 tact->set_active (yn);
2278 if ((prop = node.property ("stationary-playhead"))) {
2279 bool yn = string_is_affirmative (prop->value());
2280 set_stationary_playhead (yn);
2281 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2283 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2284 if (tact->get_active() != yn) {
2285 tact->set_active (yn);
2290 if ((prop = node.property ("region-list-sort-type"))) {
2291 RegionListSortType st;
2292 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2295 if ((prop = node.property ("show-editor-mixer"))) {
2297 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2300 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2301 bool yn = string_is_affirmative (prop->value());
2303 /* do it twice to force the change */
2305 tact->set_active (!yn);
2306 tact->set_active (yn);
2309 if ((prop = node.property ("show-editor-list"))) {
2311 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2314 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2315 bool yn = string_is_affirmative (prop->value());
2317 /* do it twice to force the change */
2319 tact->set_active (!yn);
2320 tact->set_active (yn);
2323 if ((prop = node.property (X_("editor-list-page")))) {
2324 _the_notebook.set_current_page (atoi (prop->value ()));
2327 if ((prop = node.property (X_("show-marker-lines")))) {
2328 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2330 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2331 bool yn = string_is_affirmative (prop->value ());
2333 tact->set_active (!yn);
2334 tact->set_active (yn);
2337 XMLNodeList children = node.children ();
2338 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2339 selection->set_state (**i, Stateful::current_state_version);
2340 _regions->set_state (**i);
2343 if ((prop = node.property ("maximised"))) {
2344 bool yn = string_is_affirmative (prop->value());
2345 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Common"), X_("ToggleMaximalEditor"));
2347 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2348 bool fs = tact && tact->get_active();
2350 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2354 if ((prop = node.property ("nudge-clock-value"))) {
2356 sscanf (prop->value().c_str(), "%" PRId64, &f);
2357 nudge_clock->set (f);
2359 nudge_clock->set_mode (AudioClock::Timecode);
2360 nudge_clock->set (_session->frame_rate() * 5, true);
2367 Editor::get_state ()
2369 XMLNode* node = new XMLNode ("Editor");
2372 id().print (buf, sizeof (buf));
2373 node->add_property ("id", buf);
2375 if (is_realized()) {
2376 Glib::RefPtr<Gdk::Window> win = get_window();
2378 int x, y, width, height;
2379 win->get_root_origin(x, y);
2380 win->get_size(width, height);
2382 XMLNode* geometry = new XMLNode ("geometry");
2384 snprintf(buf, sizeof(buf), "%d", width);
2385 geometry->add_property("x-size", string(buf));
2386 snprintf(buf, sizeof(buf), "%d", height);
2387 geometry->add_property("y-size", string(buf));
2388 snprintf(buf, sizeof(buf), "%d", x);
2389 geometry->add_property("x-pos", string(buf));
2390 snprintf(buf, sizeof(buf), "%d", y);
2391 geometry->add_property("y-pos", string(buf));
2392 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2393 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2394 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2395 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2396 geometry->add_property("edit-vertical-pane-pos", string(buf));
2398 node->add_child_nocopy (*geometry);
2401 maybe_add_mixer_strip_width (*node);
2403 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2405 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2406 node->add_property ("zoom", buf);
2407 node->add_property ("snap-to", enum_2_string (_snap_type));
2408 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2409 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2410 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2411 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2412 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2413 node->add_property ("edit-point", enum_2_string (_edit_point));
2414 snprintf (buf, sizeof(buf), "%d", _visible_track_count);
2415 node->add_property ("visible-track-count", buf);
2417 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2418 node->add_property ("playhead", buf);
2419 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2420 node->add_property ("left-frame", buf);
2421 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2422 node->add_property ("y-origin", buf);
2424 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2425 node->add_property ("maximised", _maximised ? "yes" : "no");
2426 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2427 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2428 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2429 node->add_property ("mouse-mode", enum2str(mouse_mode));
2430 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2431 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2433 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2435 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2436 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2439 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2441 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2442 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2445 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2446 node->add_property (X_("editor-list-page"), buf);
2448 if (button_bindings) {
2449 XMLNode* bb = new XMLNode (X_("Buttons"));
2450 button_bindings->save (*bb);
2451 node->add_child_nocopy (*bb);
2454 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2456 node->add_child_nocopy (selection->get_state ());
2457 node->add_child_nocopy (_regions->get_state ());
2459 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2460 node->add_property ("nudge-clock-value", buf);
2465 /** if @param trackview_relative_offset is true, @param y y is an offset into the trackview area, in pixel units
2466 * if @param trackview_relative_offset is false, @param y y is a global canvas * coordinate, in pixel units
2468 * @return pair: TimeAxisView that y is over, layer index.
2470 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2471 * in stacked or expanded region display mode, otherwise 0.
2473 std::pair<TimeAxisView *, double>
2474 Editor::trackview_by_y_position (double y, bool trackview_relative_offset) const
2476 if (!trackview_relative_offset) {
2477 y -= _trackview_group->canvas_origin().y;
2481 return std::make_pair ( (TimeAxisView *) 0, 0);
2484 for (TrackViewList::const_iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2486 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2493 return std::make_pair ( (TimeAxisView *) 0, 0);
2496 /** Snap a position to the grid, if appropriate, taking into account current
2497 * grid settings and also the state of any snap modifier keys that may be pressed.
2498 * @param start Position to snap.
2499 * @param event Event to get current key modifier information from, or 0.
2502 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2504 if (!_session || !event) {
2508 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2509 if (_snap_mode == SnapOff) {
2510 snap_to_internal (start, direction, for_mark);
2513 if (_snap_mode != SnapOff) {
2514 snap_to_internal (start, direction, for_mark);
2520 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2522 if (!_session || _snap_mode == SnapOff) {
2526 snap_to_internal (start, direction, for_mark);
2530 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2532 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2533 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2535 switch (_snap_type) {
2536 case SnapToTimecodeFrame:
2537 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2538 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2540 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2544 case SnapToTimecodeSeconds:
2545 if (_session->config.get_timecode_offset_negative()) {
2546 start += _session->config.get_timecode_offset ();
2548 start -= _session->config.get_timecode_offset ();
2550 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2551 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2553 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2556 if (_session->config.get_timecode_offset_negative()) {
2557 start -= _session->config.get_timecode_offset ();
2559 start += _session->config.get_timecode_offset ();
2563 case SnapToTimecodeMinutes:
2564 if (_session->config.get_timecode_offset_negative()) {
2565 start += _session->config.get_timecode_offset ();
2567 start -= _session->config.get_timecode_offset ();
2569 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2570 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2572 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2574 if (_session->config.get_timecode_offset_negative()) {
2575 start -= _session->config.get_timecode_offset ();
2577 start += _session->config.get_timecode_offset ();
2581 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2587 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2589 const framepos_t one_second = _session->frame_rate();
2590 const framepos_t one_minute = _session->frame_rate() * 60;
2591 framepos_t presnap = start;
2595 switch (_snap_type) {
2596 case SnapToTimecodeFrame:
2597 case SnapToTimecodeSeconds:
2598 case SnapToTimecodeMinutes:
2599 return timecode_snap_to_internal (start, direction, for_mark);
2602 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2603 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2605 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2610 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2611 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2613 start = (framepos_t) floor ((double) start / one_second) * one_second;
2618 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2619 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2621 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2626 start = _session->tempo_map().round_to_bar (start, direction);
2630 start = _session->tempo_map().round_to_beat (start, direction);
2633 case SnapToBeatDiv128:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2636 case SnapToBeatDiv64:
2637 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2639 case SnapToBeatDiv32:
2640 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2642 case SnapToBeatDiv28:
2643 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2645 case SnapToBeatDiv24:
2646 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2648 case SnapToBeatDiv20:
2649 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2651 case SnapToBeatDiv16:
2652 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2654 case SnapToBeatDiv14:
2655 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2657 case SnapToBeatDiv12:
2658 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2660 case SnapToBeatDiv10:
2661 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2663 case SnapToBeatDiv8:
2664 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2666 case SnapToBeatDiv7:
2667 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2669 case SnapToBeatDiv6:
2670 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2672 case SnapToBeatDiv5:
2673 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2675 case SnapToBeatDiv4:
2676 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2678 case SnapToBeatDiv3:
2679 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2681 case SnapToBeatDiv2:
2682 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2690 _session->locations()->marks_either_side (start, before, after);
2692 if (before == max_framepos && after == max_framepos) {
2693 /* No marks to snap to, so just don't snap */
2695 } else if (before == max_framepos) {
2697 } else if (after == max_framepos) {
2699 } else if (before != max_framepos && after != max_framepos) {
2700 /* have before and after */
2701 if ((start - before) < (after - start)) {
2710 case SnapToRegionStart:
2711 case SnapToRegionEnd:
2712 case SnapToRegionSync:
2713 case SnapToRegionBoundary:
2714 if (!region_boundary_cache.empty()) {
2716 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2717 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2719 if (direction > 0) {
2720 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2722 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2725 if (next != region_boundary_cache.begin ()) {
2730 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2731 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2733 if (start > (p + n) / 2) {
2742 switch (_snap_mode) {
2748 if (presnap > start) {
2749 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2753 } else if (presnap < start) {
2754 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2760 /* handled at entry */
2768 Editor::setup_toolbar ()
2770 HBox* mode_box = manage(new HBox);
2771 mode_box->set_border_width (2);
2772 mode_box->set_spacing(2);
2774 HBox* mouse_mode_box = manage (new HBox);
2775 HBox* mouse_mode_hbox = manage (new HBox);
2776 VBox* mouse_mode_vbox = manage (new VBox);
2777 Alignment* mouse_mode_align = manage (new Alignment);
2779 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2780 //mouse_mode_size_group->add_widget (smart_mode_button);
2781 mouse_mode_size_group->add_widget (mouse_move_button);
2782 mouse_mode_size_group->add_widget (mouse_cut_button);
2783 mouse_mode_size_group->add_widget (mouse_select_button);
2784 mouse_mode_size_group->add_widget (mouse_zoom_button);
2785 mouse_mode_size_group->add_widget (mouse_gain_button);
2786 mouse_mode_size_group->add_widget (mouse_timefx_button);
2787 mouse_mode_size_group->add_widget (mouse_audition_button);
2788 mouse_mode_size_group->add_widget (mouse_draw_button);
2789 mouse_mode_size_group->add_widget (internal_edit_button);
2791 if (!ARDOUR::Profile->get_small_screen()) {
2792 /* make them just a bit bigger */
2793 mouse_move_button.set_size_request (24, 30);
2795 /* make them just a bit taller */
2796 mouse_move_button.set_size_request (-1, 30);
2798 mouse_mode_hbox->set_spacing (2);
2800 if (!ARDOUR::Profile->get_trx()) {
2801 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2804 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2805 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2806 mouse_mode_hbox->pack_start (mouse_cut_button, false, false);
2807 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2809 if (!ARDOUR::Profile->get_trx()) {
2810 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2811 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2812 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2813 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2814 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 4);
2817 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2819 mouse_mode_align->add (*mouse_mode_vbox);
2820 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2822 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2824 edit_mode_selector.set_name ("mouse mode button");
2825 edit_mode_selector.add_elements (ArdourButton::Inset);
2827 if (!ARDOUR::Profile->get_trx()) {
2828 mode_box->pack_start (edit_mode_selector, false, false);
2830 mode_box->pack_start (*mouse_mode_box, false, false);
2832 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2833 _mouse_mode_tearoff->set_name ("MouseModeBase");
2834 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2836 if (Profile->get_sae() || Profile->get_mixbus() ) {
2837 _mouse_mode_tearoff->set_can_be_torn_off (false);
2840 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2841 &_mouse_mode_tearoff->tearoff_window()));
2842 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2843 &_mouse_mode_tearoff->tearoff_window(), 1));
2844 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2845 &_mouse_mode_tearoff->tearoff_window()));
2846 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2847 &_mouse_mode_tearoff->tearoff_window(), 1));
2851 _zoom_box.set_spacing (2);
2852 _zoom_box.set_border_width (2);
2856 zoom_in_button.set_name ("zoom button");
2857 // zoom_in_button.add_elements ( ArdourButton::Inset );
2858 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2859 zoom_in_button.set_image(::get_icon ("zoom_in"));
2860 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2861 zoom_in_button.set_related_action (act);
2863 zoom_out_button.set_name ("zoom button");
2864 // zoom_out_button.add_elements ( ArdourButton::Inset );
2865 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2866 zoom_out_button.set_image(::get_icon ("zoom_out"));
2867 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2868 zoom_out_button.set_related_action (act);
2870 zoom_out_full_button.set_name ("zoom button");
2871 // zoom_out_full_button.add_elements ( ArdourButton::Inset );
2872 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2873 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2874 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2875 zoom_out_full_button.set_related_action (act);
2877 zoom_focus_selector.set_name ("zoom button");
2878 // zoom_focus_selector.add_elements (ArdourButton::Inset);
2880 if (ARDOUR::Profile->get_mixbus()) {
2881 _zoom_box.pack_start (zoom_out_button, false, false);
2882 _zoom_box.pack_start (zoom_in_button, false, false);
2883 _zoom_box.pack_start (zoom_out_full_button, false, false);
2884 } else if (ARDOUR::Profile->get_trx()) {
2885 mode_box->pack_start (zoom_out_button, false, false);
2886 mode_box->pack_start (zoom_in_button, false, false);
2888 _zoom_box.pack_start (zoom_out_button, false, false);
2889 _zoom_box.pack_start (zoom_in_button, false, false);
2890 _zoom_box.pack_start (zoom_out_full_button, false, false);
2891 _zoom_box.pack_start (zoom_focus_selector, false, false);
2894 /* Track zoom buttons */
2895 visible_tracks_selector.set_name ("zoom button");
2896 // visible_tracks_selector.add_elements ( ArdourButton::Inset );
2897 set_size_request_to_display_given_text (visible_tracks_selector, _("all"), 40, 2);
2899 tav_expand_button.set_name ("zoom button");
2900 // tav_expand_button.add_elements ( ArdourButton::FlatFace );
2901 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2902 tav_expand_button.set_size_request (-1, 20);
2903 tav_expand_button.set_image(::get_icon ("tav_exp"));
2904 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2905 tav_expand_button.set_related_action (act);
2907 tav_shrink_button.set_name ("zoom button");
2908 // tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2909 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2910 tav_shrink_button.set_size_request (-1, 20);
2911 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2912 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2913 tav_shrink_button.set_related_action (act);
2915 if (!ARDOUR::Profile->get_trx()) {
2916 _zoom_box.pack_start (visible_tracks_selector);
2918 _zoom_box.pack_start (tav_shrink_button);
2919 _zoom_box.pack_start (tav_expand_button);
2921 if (!ARDOUR::Profile->get_trx()) {
2922 _zoom_tearoff = manage (new TearOff (_zoom_box));
2924 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_zoom_tearoff->tearoff_window()));
2926 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_zoom_tearoff->tearoff_window(), 0));
2928 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2929 &_zoom_tearoff->tearoff_window()));
2930 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2931 &_zoom_tearoff->tearoff_window(), 0));
2934 if (Profile->get_sae() || Profile->get_mixbus() ) {
2935 _zoom_tearoff->set_can_be_torn_off (false);
2938 snap_box.set_spacing (2);
2939 snap_box.set_border_width (2);
2941 snap_type_selector.set_name ("mouse mode button");
2942 snap_type_selector.add_elements (ArdourButton::Inset);
2944 snap_mode_selector.set_name ("mouse mode button");
2945 snap_mode_selector.add_elements (ArdourButton::Inset);
2947 edit_point_selector.set_name ("mouse mode button");
2948 edit_point_selector.add_elements (ArdourButton::Inset);
2950 snap_box.pack_start (snap_mode_selector, false, false);
2951 snap_box.pack_start (snap_type_selector, false, false);
2952 snap_box.pack_start (edit_point_selector, false, false);
2956 HBox *nudge_box = manage (new HBox);
2957 nudge_box->set_spacing (2);
2958 nudge_box->set_border_width (2);
2960 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2961 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2963 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2964 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2966 nudge_box->pack_start (nudge_backward_button, false, false);
2967 nudge_box->pack_start (nudge_forward_button, false, false);
2968 nudge_box->pack_start (*nudge_clock, false, false);
2971 /* Pack everything in... */
2973 HBox* hbox = manage (new HBox);
2974 hbox->set_spacing(2);
2976 _tools_tearoff = manage (new TearOff (*hbox));
2977 _tools_tearoff->set_name ("MouseModeBase");
2978 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2980 if (Profile->get_sae() || Profile->get_mixbus()) {
2981 _tools_tearoff->set_can_be_torn_off (false);
2984 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2985 &_tools_tearoff->tearoff_window()));
2986 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2987 &_tools_tearoff->tearoff_window(), 0));
2988 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2989 &_tools_tearoff->tearoff_window()));
2990 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2991 &_tools_tearoff->tearoff_window(), 0));
2993 toolbar_hbox.set_spacing (2);
2994 toolbar_hbox.set_border_width (1);
2996 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2997 if (!ARDOUR::Profile->get_trx()) {
2998 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2999 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3002 if (!ARDOUR::Profile->get_trx()) {
3003 hbox->pack_start (snap_box, false, false);
3004 if (!Profile->get_small_screen()) {
3005 hbox->pack_start (*nudge_box, false, false);
3007 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3010 hbox->pack_start (panic_box, false, false);
3014 toolbar_base.set_name ("ToolBarBase");
3015 toolbar_base.add (toolbar_hbox);
3017 _toolbar_viewport.add (toolbar_base);
3018 /* stick to the required height but allow width to vary if there's not enough room */
3019 _toolbar_viewport.set_size_request (1, -1);
3021 toolbar_frame.set_shadow_type (SHADOW_OUT);
3022 toolbar_frame.set_name ("BaseFrame");
3023 toolbar_frame.add (_toolbar_viewport);
3027 Editor::build_edit_point_menu ()
3029 using namespace Menu_Helpers;
3031 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtPlayhead)));
3032 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtSelectedMarker], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtSelectedMarker)));
3033 edit_point_selector.AddMenuElem (MenuElem ( edit_point_strings[(int)EditAtMouse], sigc::bind (sigc::mem_fun(*this, &Editor::edit_point_selection_done), (EditPoint) EditAtMouse)));
3035 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, 30, 2);
3039 Editor::build_edit_mode_menu ()
3041 using namespace Menu_Helpers;
3043 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Slide], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Slide)));
3044 // edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Splice], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Splice)));
3045 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Ripple], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Ripple)));
3046 edit_mode_selector.AddMenuElem (MenuElem ( edit_mode_strings[(int)Lock], sigc::bind (sigc::mem_fun(*this, &Editor::edit_mode_selection_done), (EditMode) Lock)));
3048 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, 30, 2);
3052 Editor::build_snap_mode_menu ()
3054 using namespace Menu_Helpers;
3056 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapOff], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapOff)));
3057 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapNormal], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapNormal)));
3058 snap_mode_selector.AddMenuElem (MenuElem ( snap_mode_strings[(int)SnapMagnetic], sigc::bind (sigc::mem_fun(*this, &Editor::snap_mode_selection_done), (SnapMode) SnapMagnetic)));
3060 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, 34, 2);
3064 Editor::build_snap_type_menu ()
3066 using namespace Menu_Helpers;
3068 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToCDFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToCDFrame)));
3069 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeFrame], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeFrame)));
3070 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeSeconds)));
3071 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToTimecodeMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToTimecodeMinutes)));
3072 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToSeconds], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToSeconds)));
3073 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMinutes], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMinutes)));
3074 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv128], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv128)));
3075 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv64], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv64)));
3076 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv32], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv32)));
3077 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv28], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv28)));
3078 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv24], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv24)));
3079 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv20], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv20)));
3080 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv16], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv16)));
3081 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv14], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv14)));
3082 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv12], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv12)));
3083 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv10], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv10)));
3084 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv8], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv8)));
3085 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv7], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv7)));
3086 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv6], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv6)));
3087 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv5], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv5)));
3088 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv4], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv4)));
3089 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv3], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv3)));
3090 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeatDiv2], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeatDiv2)));
3091 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBeat], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBeat)));
3092 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToBar], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToBar)));
3093 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToMark], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToMark)));
3094 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionStart], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionStart)));
3095 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionEnd], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionEnd)));
3096 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionSync], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionSync)));
3097 snap_type_selector.AddMenuElem (MenuElem ( snap_type_strings[(int)SnapToRegionBoundary], sigc::bind (sigc::mem_fun(*this, &Editor::snap_type_selection_done), (SnapType) SnapToRegionBoundary)));
3099 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, 34, 2);
3104 Editor::setup_tooltips ()
3106 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3107 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3108 ARDOUR_UI::instance()->set_tip (mouse_cut_button, _("Cut Mode (split Regions)"));
3109 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3110 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3111 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3112 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3113 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3114 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3115 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3116 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3117 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3118 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3119 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3120 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3121 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3122 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3123 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3124 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3125 ARDOUR_UI::instance()->set_tip (visible_tracks_selector, _("Number of visible tracks"));
3126 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3127 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3128 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3129 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3130 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3134 Editor::convert_drop_to_paths (
3135 vector<string>& paths,
3136 const RefPtr<Gdk::DragContext>& /*context*/,
3139 const SelectionData& data,
3143 if (_session == 0) {
3147 vector<string> uris = data.get_uris();
3151 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3152 are actually URI lists. So do it by hand.
3155 if (data.get_target() != "text/plain") {
3159 /* Parse the "uri-list" format that Nautilus provides,
3160 where each pathname is delimited by \r\n.
3162 THERE MAY BE NO NULL TERMINATING CHAR!!!
3165 string txt = data.get_text();
3169 p = (char *) malloc (txt.length() + 1);
3170 txt.copy (p, txt.length(), 0);
3171 p[txt.length()] = '\0';
3177 while (g_ascii_isspace (*p))
3181 while (*q && (*q != '\n') && (*q != '\r')) {
3188 while (q > p && g_ascii_isspace (*q))
3193 uris.push_back (string (p, q - p + 1));
3197 p = strchr (p, '\n');
3209 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3210 if ((*i).substr (0,7) == "file://") {
3211 paths.push_back (Glib::filename_from_uri (*i));
3219 Editor::new_tempo_section ()
3224 Editor::map_transport_state ()
3226 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3228 if (_session && _session->transport_stopped()) {
3229 have_pending_keyboard_selection = false;
3232 update_loop_range_view ();
3238 Editor::begin_reversible_command (string name)
3241 _session->begin_reversible_command (name);
3246 Editor::begin_reversible_command (GQuark q)
3249 _session->begin_reversible_command (q);
3254 Editor::commit_reversible_command ()
3257 _session->commit_reversible_command ();
3262 Editor::history_changed ()
3266 if (undo_action && _session) {
3267 if (_session->undo_depth() == 0) {
3268 label = S_("Command|Undo");
3270 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3272 undo_action->property_label() = label;
3275 if (redo_action && _session) {
3276 if (_session->redo_depth() == 0) {
3279 label = string_compose(_("Redo (%1)"), _session->next_redo());
3281 redo_action->property_label() = label;
3286 Editor::duplicate_range (bool with_dialog)
3290 RegionSelection rs = get_regions_from_selection_and_entered ();
3292 if ( selection->time.length() == 0 && rs.empty()) {
3298 ArdourDialog win (_("Duplicate"));
3299 Label label (_("Number of duplications:"));
3300 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3301 SpinButton spinner (adjustment, 0.0, 1);
3304 win.get_vbox()->set_spacing (12);
3305 win.get_vbox()->pack_start (hbox);
3306 hbox.set_border_width (6);
3307 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3309 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3310 place, visually. so do this by hand.
3313 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3314 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3315 spinner.grab_focus();
3321 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3322 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3323 win.set_default_response (RESPONSE_ACCEPT);
3325 spinner.grab_focus ();
3327 switch (win.run ()) {
3328 case RESPONSE_ACCEPT:
3334 times = adjustment.get_value();
3337 if ((current_mouse_mode() == Editing::MouseRange)) {
3338 if (selection->time.length()) {
3339 duplicate_selection (times);
3341 } else if (get_smart_mode()) {
3342 if (selection->time.length()) {
3343 duplicate_selection (times);
3345 duplicate_some_regions (rs, times);
3347 duplicate_some_regions (rs, times);
3352 Editor::set_edit_mode (EditMode m)
3354 Config->set_edit_mode (m);
3358 Editor::cycle_edit_mode ()
3360 switch (Config->get_edit_mode()) {
3362 if (Profile->get_sae()) {
3363 Config->set_edit_mode (Lock);
3365 Config->set_edit_mode (Ripple);
3370 Config->set_edit_mode (Lock);
3373 Config->set_edit_mode (Slide);
3379 Editor::edit_mode_selection_done ( EditMode m )
3381 Config->set_edit_mode ( m );
3385 Editor::snap_type_selection_done (SnapType snaptype)
3387 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3389 ract->set_active ();
3394 Editor::snap_mode_selection_done (SnapMode mode)
3396 RefPtr<RadioAction> ract = snap_mode_action (mode);
3399 ract->set_active (true);
3404 Editor::cycle_edit_point (bool with_marker)
3406 switch (_edit_point) {
3408 set_edit_point_preference (EditAtPlayhead);
3410 case EditAtPlayhead:
3412 set_edit_point_preference (EditAtSelectedMarker);
3414 set_edit_point_preference (EditAtMouse);
3417 case EditAtSelectedMarker:
3418 set_edit_point_preference (EditAtMouse);
3424 Editor::edit_point_selection_done (EditPoint ep)
3426 set_edit_point_preference ( ep );
3430 Editor::build_zoom_focus_menu ()
3432 using namespace Menu_Helpers;
3434 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusLeft], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusLeft)));
3435 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusRight], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusRight)));
3436 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusCenter], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusCenter)));
3437 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusPlayhead], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusPlayhead)));
3438 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusMouse], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusMouse)));
3439 zoom_focus_selector.AddMenuElem (MenuElem ( zoom_focus_strings[(int)ZoomFocusEdit], sigc::bind (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done), (ZoomFocus) ZoomFocusEdit)));
3441 set_size_request_to_display_given_text (zoom_focus_selector, longest (zoom_focus_strings), 30, 2);
3445 Editor::zoom_focus_selection_done ( ZoomFocus f )
3447 RefPtr<RadioAction> ract = zoom_focus_action (f);
3449 ract->set_active ();
3454 Editor::build_track_count_menu ()
3456 using namespace Menu_Helpers;
3458 visible_tracks_selector.AddMenuElem (MenuElem (X_("1"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 1)));
3459 visible_tracks_selector.AddMenuElem (MenuElem (X_("2"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 2)));
3460 visible_tracks_selector.AddMenuElem (MenuElem (X_("3"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 3)));
3461 visible_tracks_selector.AddMenuElem (MenuElem (X_("4"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 4)));
3462 visible_tracks_selector.AddMenuElem (MenuElem (X_("8"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 8)));
3463 visible_tracks_selector.AddMenuElem (MenuElem (X_("12"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 12)));
3464 visible_tracks_selector.AddMenuElem (MenuElem (X_("16"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 16)));
3465 visible_tracks_selector.AddMenuElem (MenuElem (X_("20"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 20)));
3466 visible_tracks_selector.AddMenuElem (MenuElem (X_("24"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 24)));
3467 visible_tracks_selector.AddMenuElem (MenuElem (X_("32"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 32)));
3468 visible_tracks_selector.AddMenuElem (MenuElem (X_("64"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 64)));
3469 visible_tracks_selector.AddMenuElem (MenuElem (_("all"), sigc::bind (sigc::mem_fun(*this, &Editor::set_visible_track_count), 0)));
3473 Editor::set_visible_track_count (int32_t n)
3475 _visible_track_count = n;
3477 /* if the canvas hasn't really been allocated any size yet, just
3478 record the desired number of visible tracks and return. when canvas
3479 allocation happens, we will get called again and then we can do the
3483 if (_visible_canvas_height <= 1) {
3490 if (_visible_track_count > 0) {
3491 h = _visible_canvas_height / _visible_track_count;
3492 std::ostringstream s;
3493 s << _visible_track_count;
3495 } else if (_visible_track_count == 0) {
3496 h = _visible_canvas_height / track_views.size();
3499 /* negative value means that the visible track count has
3500 been overridden by explicit track height changes.
3502 visible_tracks_selector.set_text (X_("*"));
3506 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
3507 (*i)->set_height (h);
3510 if (str != visible_tracks_selector.get_text()) {
3511 visible_tracks_selector.set_text (str);
3516 Editor::override_visible_track_count ()
3518 _visible_track_count = -_visible_track_count;
3522 Editor::edit_controls_button_release (GdkEventButton* ev)
3524 if (Keyboard::is_context_menu_event (ev)) {
3525 ARDOUR_UI::instance()->add_route (this);
3526 } else if (ev->button == 1) {
3527 selection->clear_tracks ();
3534 Editor::mouse_select_button_release (GdkEventButton* ev)
3536 /* this handles just right-clicks */
3538 if (ev->button != 3) {
3546 Editor::set_zoom_focus (ZoomFocus f)
3548 string str = zoom_focus_strings[(int)f];
3550 if (str != zoom_focus_selector.get_text()) {
3551 zoom_focus_selector.set_text (str);
3554 if (zoom_focus != f) {
3561 Editor::cycle_zoom_focus ()
3563 switch (zoom_focus) {
3565 set_zoom_focus (ZoomFocusRight);
3567 case ZoomFocusRight:
3568 set_zoom_focus (ZoomFocusCenter);
3570 case ZoomFocusCenter:
3571 set_zoom_focus (ZoomFocusPlayhead);
3573 case ZoomFocusPlayhead:
3574 set_zoom_focus (ZoomFocusMouse);
3576 case ZoomFocusMouse:
3577 set_zoom_focus (ZoomFocusEdit);
3580 set_zoom_focus (ZoomFocusLeft);
3586 Editor::ensure_float (Window& win)
3588 win.set_transient_for (*this);
3592 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3594 /* recover or initialize pane positions. do this here rather than earlier because
3595 we don't want the positions to change the child allocations, which they seem to do.
3601 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3610 XMLNode* geometry = find_named_node (*node, "geometry");
3612 if (which == static_cast<Paned*> (&edit_pane)) {
3614 if (done & Horizontal) {
3618 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3619 _notebook_shrunk = string_is_affirmative (prop->value ());
3622 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3623 /* initial allocation is 90% to canvas, 10% to notebook */
3624 pos = (int) floor (alloc.get_width() * 0.90f);
3625 snprintf (buf, sizeof(buf), "%d", pos);
3627 pos = atoi (prop->value());
3630 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3631 edit_pane.set_position (pos);
3634 done = (Pane) (done | Horizontal);
3636 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3638 if (done & Vertical) {
3642 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3643 /* initial allocation is 90% to canvas, 10% to summary */
3644 pos = (int) floor (alloc.get_height() * 0.90f);
3645 snprintf (buf, sizeof(buf), "%d", pos);
3648 pos = atoi (prop->value());
3651 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3652 editor_summary_pane.set_position (pos);
3655 done = (Pane) (done | Vertical);
3660 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3662 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3663 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3664 (_zoom_tearoff && (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible()))) {
3665 top_hbox.remove (toolbar_frame);
3670 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3672 if (toolbar_frame.get_parent() == 0) {
3673 top_hbox.pack_end (toolbar_frame);
3678 Editor::set_show_measures (bool yn)
3680 if (_show_measures != yn) {
3683 if ((_show_measures = yn) == true) {
3685 tempo_lines->show();
3688 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3689 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3691 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3692 draw_measures (begin, end);
3700 Editor::toggle_follow_playhead ()
3702 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3704 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3705 set_follow_playhead (tact->get_active());
3709 /** @param yn true to follow playhead, otherwise false.
3710 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3713 Editor::set_follow_playhead (bool yn, bool catch_up)
3715 if (_follow_playhead != yn) {
3716 if ((_follow_playhead = yn) == true && catch_up) {
3718 reset_x_origin_to_follow_playhead ();
3725 Editor::toggle_stationary_playhead ()
3727 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3729 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3730 set_stationary_playhead (tact->get_active());
3735 Editor::set_stationary_playhead (bool yn)
3737 if (_stationary_playhead != yn) {
3738 if ((_stationary_playhead = yn) == true) {
3740 // FIXME need a 3.0 equivalent of this 2.X call
3741 // update_current_screen ();
3748 Editor::playlist_selector () const
3750 return *_playlist_selector;
3754 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3758 switch (_snap_type) {
3763 case SnapToBeatDiv128:
3766 case SnapToBeatDiv64:
3769 case SnapToBeatDiv32:
3772 case SnapToBeatDiv28:
3775 case SnapToBeatDiv24:
3778 case SnapToBeatDiv20:
3781 case SnapToBeatDiv16:
3784 case SnapToBeatDiv14:
3787 case SnapToBeatDiv12:
3790 case SnapToBeatDiv10:
3793 case SnapToBeatDiv8:
3796 case SnapToBeatDiv7:
3799 case SnapToBeatDiv6:
3802 case SnapToBeatDiv5:
3805 case SnapToBeatDiv4:
3808 case SnapToBeatDiv3:
3811 case SnapToBeatDiv2:
3817 return _session->tempo_map().meter_at (position).divisions_per_bar();
3822 case SnapToTimecodeFrame:
3823 case SnapToTimecodeSeconds:
3824 case SnapToTimecodeMinutes:
3827 case SnapToRegionStart:
3828 case SnapToRegionEnd:
3829 case SnapToRegionSync:
3830 case SnapToRegionBoundary:
3840 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3844 ret = nudge_clock->current_duration (pos);
3845 next = ret + 1; /* XXXX fix me */
3851 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3853 ArdourDialog dialog (_("Playlist Deletion"));
3854 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3855 "If it is kept, its audio files will not be cleaned.\n"
3856 "If it is deleted, audio files used by it alone will be cleaned."),
3859 dialog.set_position (WIN_POS_CENTER);
3860 dialog.get_vbox()->pack_start (label);
3864 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3865 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3866 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3868 switch (dialog.run ()) {
3869 case RESPONSE_ACCEPT:
3870 /* delete the playlist */
3874 case RESPONSE_REJECT:
3875 /* keep the playlist */
3887 Editor::audio_region_selection_covers (framepos_t where)
3889 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3890 if ((*a)->region()->covers (where)) {
3899 Editor::prepare_for_cleanup ()
3901 cut_buffer->clear_regions ();
3902 cut_buffer->clear_playlists ();
3904 selection->clear_regions ();
3905 selection->clear_playlists ();
3907 _regions->suspend_redisplay ();
3911 Editor::finish_cleanup ()
3913 _regions->resume_redisplay ();
3917 Editor::transport_loop_location()
3920 return _session->locations()->auto_loop_location();
3927 Editor::transport_punch_location()
3930 return _session->locations()->auto_punch_location();
3937 Editor::control_layout_scroll (GdkEventScroll* ev)
3939 /* Just forward to the normal canvas scroll method. The coordinate
3940 systems are different but since the canvas is always larger than the
3941 track headers, and aligned with the trackview area, this will work.
3943 In the not too distant future this layout is going away anyway and
3944 headers will be on the canvas.
3946 return canvas_scroll_event (ev, false);
3950 Editor::session_state_saved (string)
3953 _snapshots->redisplay ();
3957 Editor::update_tearoff_visibility()
3959 bool visible = Config->get_keep_tearoffs();
3960 _mouse_mode_tearoff->set_visible (visible);
3961 _tools_tearoff->set_visible (visible);
3962 if (_zoom_tearoff) {
3963 _zoom_tearoff->set_visible (visible);
3968 Editor::maximise_editing_space ()
3980 Editor::restore_editing_space ()
3992 * Make new playlists for a given track and also any others that belong
3993 * to the same active route group with the `select' property.
3998 Editor::new_playlists (TimeAxisView* v)
4000 begin_reversible_command (_("new playlists"));
4001 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4002 _session->playlists->get (playlists);
4003 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4004 commit_reversible_command ();
4008 * Use a copy of the current playlist for a given track and also any others that belong
4009 * to the same active route group with the `select' property.
4014 Editor::copy_playlists (TimeAxisView* v)
4016 begin_reversible_command (_("copy playlists"));
4017 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4018 _session->playlists->get (playlists);
4019 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4020 commit_reversible_command ();
4023 /** Clear the current playlist for a given track and also any others that belong
4024 * to the same active route group with the `select' property.
4029 Editor::clear_playlists (TimeAxisView* v)
4031 begin_reversible_command (_("clear playlists"));
4032 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4033 _session->playlists->get (playlists);
4034 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4035 commit_reversible_command ();
4039 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4041 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4045 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4047 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4051 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4053 atv.clear_playlist ();
4057 Editor::on_key_press_event (GdkEventKey* ev)
4059 return key_press_focus_accelerator_handler (*this, ev);
4063 Editor::on_key_release_event (GdkEventKey* ev)
4065 return Gtk::Window::on_key_release_event (ev);
4066 // return key_press_focus_accelerator_handler (*this, ev);
4069 /** Queue up a change to the viewport x origin.
4070 * @param frame New x origin.
4073 Editor::reset_x_origin (framepos_t frame)
4075 pending_visual_change.add (VisualChange::TimeOrigin);
4076 pending_visual_change.time_origin = frame;
4077 ensure_visual_change_idle_handler ();
4081 Editor::reset_y_origin (double y)
4083 pending_visual_change.add (VisualChange::YOrigin);
4084 pending_visual_change.y_origin = y;
4085 ensure_visual_change_idle_handler ();
4089 Editor::reset_zoom (framecnt_t spp)
4091 if (spp == samples_per_pixel) {
4095 pending_visual_change.add (VisualChange::ZoomLevel);
4096 pending_visual_change.samples_per_pixel = spp;
4097 ensure_visual_change_idle_handler ();
4101 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4103 reset_x_origin (frame);
4106 if (!no_save_visual) {
4107 undo_visual_stack.push_back (current_visual_state(false));
4111 Editor::VisualState::VisualState (bool with_tracks)
4112 : gui_state (with_tracks ? new GUIObjectState : 0)
4116 Editor::VisualState::~VisualState ()
4121 Editor::VisualState*
4122 Editor::current_visual_state (bool with_tracks)
4124 VisualState* vs = new VisualState (with_tracks);
4125 vs->y_position = vertical_adjustment.get_value();
4126 vs->samples_per_pixel = samples_per_pixel;
4127 vs->leftmost_frame = leftmost_frame;
4128 vs->zoom_focus = zoom_focus;
4131 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4138 Editor::undo_visual_state ()
4140 if (undo_visual_stack.empty()) {
4144 VisualState* vs = undo_visual_stack.back();
4145 undo_visual_stack.pop_back();
4148 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4150 use_visual_state (*vs);
4154 Editor::redo_visual_state ()
4156 if (redo_visual_stack.empty()) {
4160 VisualState* vs = redo_visual_stack.back();
4161 redo_visual_stack.pop_back();
4163 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4165 use_visual_state (*vs);
4169 Editor::swap_visual_state ()
4171 if (undo_visual_stack.empty()) {
4172 redo_visual_state ();
4174 undo_visual_state ();
4179 Editor::use_visual_state (VisualState& vs)
4181 PBD::Unwinder<bool> nsv (no_save_visual, true);
4182 DisplaySuspender ds;
4184 vertical_adjustment.set_value (vs.y_position);
4186 set_zoom_focus (vs.zoom_focus);
4187 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4190 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4192 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4193 (*i)->reset_visual_state ();
4197 _routes->update_visibility ();
4200 /** This is the core function that controls the zoom level of the canvas. It is called
4201 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4202 * @param spp new number of samples per pixel
4205 Editor::set_samples_per_pixel (framecnt_t spp)
4211 const framecnt_t three_days = 3 * 24 * 60 * 60 * (_session ? _session->frame_rate() : 48000);
4212 const framecnt_t lots_of_pixels = 4000;
4214 /* if the zoom level is greater than what you'd get trying to display 3
4215 * days of audio on a really big screen, then it's too big.
4218 if (spp * lots_of_pixels > three_days) {
4222 samples_per_pixel = spp;
4225 tempo_lines->tempo_map_changed();
4228 bool const showing_time_selection = selection->time.length() > 0;
4230 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4231 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4232 (*i)->reshow_selection (selection->time);
4236 ZoomChanged (); /* EMIT_SIGNAL */
4238 ArdourCanvas::GtkCanvasViewport* c;
4240 c = get_track_canvas();
4242 c->canvas()->zoomed ();
4245 if (playhead_cursor) {
4246 playhead_cursor->set_position (playhead_cursor->current_frame ());
4249 refresh_location_display();
4250 _summary->set_overlays_dirty ();
4252 update_marker_labels ();
4258 Editor::queue_visual_videotimeline_update ()
4261 * pending_visual_change.add (VisualChange::VideoTimeline);
4262 * or maybe even more specific: which videotimeline-image
4263 * currently it calls update_video_timeline() to update
4264 * _all outdated_ images on the video-timeline.
4265 * see 'exposeimg()' in video_image_frame.cc
4267 ensure_visual_change_idle_handler ();
4271 Editor::ensure_visual_change_idle_handler ()
4273 if (pending_visual_change.idle_handler_id < 0) {
4274 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4275 pending_visual_change.being_handled = false;
4280 Editor::_idle_visual_changer (void* arg)
4282 return static_cast<Editor*>(arg)->idle_visual_changer ();
4286 Editor::idle_visual_changer ()
4288 /* set_horizontal_position() below (and maybe other calls) call
4289 gtk_main_iteration(), so it's possible that a signal will be handled
4290 half-way through this method. If this signal wants an
4291 idle_visual_changer we must schedule another one after this one, so
4292 mark the idle_handler_id as -1 here to allow that. Also make a note
4293 that we are doing the visual change, so that changes in response to
4294 super-rapid-screen-update can be dropped if we are still processing
4298 pending_visual_change.idle_handler_id = -1;
4299 pending_visual_change.being_handled = true;
4301 VisualChange vc = pending_visual_change;
4303 pending_visual_change.pending = (VisualChange::Type) 0;
4305 visual_changer (vc);
4307 pending_visual_change.being_handled = false;
4309 return 0; /* this is always a one-shot call */
4313 Editor::visual_changer (const VisualChange& vc)
4315 double const last_time_origin = horizontal_position ();
4317 if (vc.pending & VisualChange::ZoomLevel) {
4318 set_samples_per_pixel (vc.samples_per_pixel);
4320 compute_fixed_ruler_scale ();
4322 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4323 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4325 compute_current_bbt_points (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4326 current_bbt_points_begin, current_bbt_points_end);
4327 compute_bbt_ruler_scale (vc.time_origin, pending_visual_change.time_origin + current_page_samples(),
4328 current_bbt_points_begin, current_bbt_points_end);
4329 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4331 update_video_timeline();
4334 if (vc.pending & VisualChange::TimeOrigin) {
4335 set_horizontal_position (vc.time_origin / samples_per_pixel);
4338 if (vc.pending & VisualChange::YOrigin) {
4339 vertical_adjustment.set_value (vc.y_origin);
4342 if (last_time_origin == horizontal_position ()) {
4343 /* changed signal not emitted */
4344 update_fixed_rulers ();
4345 redisplay_tempo (true);
4348 if (!(vc.pending & VisualChange::ZoomLevel)) {
4349 update_video_timeline();
4352 _summary->set_overlays_dirty ();
4355 struct EditorOrderTimeAxisSorter {
4356 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4357 return a->order () < b->order ();
4362 Editor::sort_track_selection (TrackViewList& sel)
4364 EditorOrderTimeAxisSorter cmp;
4369 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4372 framepos_t where = 0;
4373 EditPoint ep = _edit_point;
4375 if (from_context_menu && (ep == EditAtMouse)) {
4376 return canvas_event_sample (&context_click_event, 0, 0);
4379 if (entered_marker) {
4380 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4381 return entered_marker->position();
4384 if (ignore_playhead && ep == EditAtPlayhead) {
4385 ep = EditAtSelectedMarker;
4389 case EditAtPlayhead:
4390 where = _session->audible_frame();
4391 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4394 case EditAtSelectedMarker:
4395 if (!selection->markers.empty()) {
4397 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4400 where = loc->start();
4404 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4412 if (!mouse_frame (where, ignored)) {
4413 /* XXX not right but what can we do ? */
4417 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4425 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4427 if (!_session) return;
4429 begin_reversible_command (cmd);
4433 if ((tll = transport_loop_location()) == 0) {
4434 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4435 XMLNode &before = _session->locations()->get_state();
4436 _session->locations()->add (loc, true);
4437 _session->set_auto_loop_location (loc);
4438 XMLNode &after = _session->locations()->get_state();
4439 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4441 XMLNode &before = tll->get_state();
4442 tll->set_hidden (false, this);
4443 tll->set (start, end);
4444 XMLNode &after = tll->get_state();
4445 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4448 commit_reversible_command ();
4452 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4454 if (!_session) return;
4456 begin_reversible_command (cmd);
4460 if ((tpl = transport_punch_location()) == 0) {
4461 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4462 XMLNode &before = _session->locations()->get_state();
4463 _session->locations()->add (loc, true);
4464 _session->set_auto_punch_location (loc);
4465 XMLNode &after = _session->locations()->get_state();
4466 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4469 XMLNode &before = tpl->get_state();
4470 tpl->set_hidden (false, this);
4471 tpl->set (start, end);
4472 XMLNode &after = tpl->get_state();
4473 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4476 commit_reversible_command ();
4479 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4480 * @param rs List to which found regions are added.
4481 * @param where Time to look at.
4482 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4485 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4487 const TrackViewList* tracks;
4490 tracks = &track_views;
4495 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4497 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4500 boost::shared_ptr<Track> tr;
4501 boost::shared_ptr<Playlist> pl;
4503 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4505 boost::shared_ptr<RegionList> regions = pl->regions_at (
4506 (framepos_t) floor ( (double) where * tr->speed()));
4508 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4509 RegionView* rv = rtv->view()->find_view (*i);
4520 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4522 const TrackViewList* tracks;
4525 tracks = &track_views;
4530 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4531 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4533 boost::shared_ptr<Track> tr;
4534 boost::shared_ptr<Playlist> pl;
4536 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4538 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4539 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4541 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4543 RegionView* rv = rtv->view()->find_view (*i);
4554 /** Get regions using the following method:
4556 * Make a region list using:
4557 * (a) any selected regions
4558 * (b) the intersection of any selected tracks and the edit point(*)
4559 * (c) if neither exists, and edit_point == mouse, then whatever region is under the mouse
4561 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4563 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4567 Editor::get_regions_from_selection_and_edit_point ()
4569 RegionSelection regions;
4571 if (_edit_point == EditAtMouse && entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4572 regions.add (entered_regionview);
4574 regions = selection->regions;
4577 if ( regions.empty() ) {
4578 TrackViewList tracks = selection->tracks;
4580 if (!tracks.empty()) {
4581 /* no region selected or entered, but some selected tracks:
4582 * act on all regions on the selected tracks at the edit point
4584 framepos_t const where = get_preferred_edit_position ();
4585 get_regions_at(regions, where, tracks);
4592 /** Get regions using the following method:
4594 * Make a region list using:
4595 * (a) any selected regions
4596 * (b) the intersection of any selected tracks and the edit point(*)
4597 * (c) if neither exists, then whatever region is under the mouse
4599 * (*) NOTE: in this case, if 'No Selection = All Tracks' is active, search all tracks
4601 * Note that we have forced the rule that selected regions and selected tracks are mutually exclusive
4604 Editor::get_regions_from_selection_and_mouse (framepos_t pos)
4606 RegionSelection regions;
4608 if (entered_regionview && selection->tracks.empty() && selection->regions.empty() ) {
4609 regions.add (entered_regionview);
4611 regions = selection->regions;
4614 if ( regions.empty() ) {
4615 TrackViewList tracks = selection->tracks;
4617 if (!tracks.empty()) {
4618 /* no region selected or entered, but some selected tracks:
4619 * act on all regions on the selected tracks at the edit point
4621 get_regions_at(regions, pos, tracks);
4628 /** Start with regions that are selected, or the entered regionview if none are selected.
4629 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4630 * of the regions that we started with.
4634 Editor::get_regions_from_selection_and_entered ()
4636 RegionSelection regions = selection->regions;
4638 if (regions.empty() && entered_regionview) {
4639 regions.add (entered_regionview);
4646 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4648 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4650 RouteTimeAxisView* tatv;
4652 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4654 boost::shared_ptr<Playlist> pl;
4655 vector<boost::shared_ptr<Region> > results;
4657 boost::shared_ptr<Track> tr;
4659 if ((tr = tatv->track()) == 0) {
4664 if ((pl = (tr->playlist())) != 0) {
4665 if (src_comparison) {
4666 pl->get_source_equivalent_regions (region, results);
4668 pl->get_region_list_equivalent_regions (region, results);
4672 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4673 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4674 regions.push_back (marv);
4683 Editor::show_rhythm_ferret ()
4685 if (rhythm_ferret == 0) {
4686 rhythm_ferret = new RhythmFerret(*this);
4689 rhythm_ferret->set_session (_session);
4690 rhythm_ferret->show ();
4691 rhythm_ferret->present ();
4695 Editor::first_idle ()
4697 MessageDialog* dialog = 0;
4699 if (track_views.size() > 1) {
4700 dialog = new MessageDialog (
4702 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4706 ARDOUR_UI::instance()->flush_pending ();
4709 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4713 // first idle adds route children (automation tracks), so we need to redisplay here
4714 _routes->redisplay ();
4721 Editor::_idle_resize (gpointer arg)
4723 return ((Editor*)arg)->idle_resize ();
4727 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4729 if (resize_idle_id < 0) {
4730 resize_idle_id = g_idle_add (_idle_resize, this);
4731 _pending_resize_amount = 0;
4734 /* make a note of the smallest resulting height, so that we can clamp the
4735 lower limit at TimeAxisView::hSmall */
4737 int32_t min_resulting = INT32_MAX;
4739 _pending_resize_amount += h;
4740 _pending_resize_view = view;
4742 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4744 if (selection->tracks.contains (_pending_resize_view)) {
4745 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4746 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4750 if (min_resulting < 0) {
4755 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4756 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4760 /** Handle pending resizing of tracks */
4762 Editor::idle_resize ()
4764 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4766 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4767 selection->tracks.contains (_pending_resize_view)) {
4769 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4770 if (*i != _pending_resize_view) {
4771 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4776 _pending_resize_amount = 0;
4777 _group_tabs->set_dirty ();
4778 resize_idle_id = -1;
4786 ENSURE_GUI_THREAD (*this, &Editor::located);
4789 playhead_cursor->set_position (_session->audible_frame ());
4790 if (_follow_playhead && !_pending_initial_locate) {
4791 reset_x_origin_to_follow_playhead ();
4795 _pending_locate_request = false;
4796 _pending_initial_locate = false;
4800 Editor::region_view_added (RegionView *)
4802 _summary->set_background_dirty ();
4806 Editor::region_view_removed ()
4808 _summary->set_background_dirty ();
4812 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4814 TrackViewList::const_iterator j = track_views.begin ();
4815 while (j != track_views.end()) {
4816 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4817 if (rtv && rtv->route() == r) {
4828 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4832 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4833 TimeAxisView* tv = axis_view_from_route (*i);
4843 Editor::suspend_route_redisplay ()
4846 _routes->suspend_redisplay();
4851 Editor::resume_route_redisplay ()
4854 _routes->resume_redisplay();
4859 Editor::add_routes (RouteList& routes)
4861 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4863 RouteTimeAxisView *rtv;
4864 list<RouteTimeAxisView*> new_views;
4866 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4867 boost::shared_ptr<Route> route = (*x);
4869 if (route->is_auditioner() || route->is_monitor()) {
4873 DataType dt = route->input()->default_type();
4875 if (dt == ARDOUR::DataType::AUDIO) {
4876 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4877 rtv->set_route (route);
4878 } else if (dt == ARDOUR::DataType::MIDI) {
4879 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4880 rtv->set_route (route);
4882 throw unknown_type();
4885 new_views.push_back (rtv);
4886 track_views.push_back (rtv);
4888 rtv->effective_gain_display ();
4890 if (internal_editing()) {
4891 rtv->enter_internal_edit_mode ();
4893 rtv->leave_internal_edit_mode ();
4896 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4897 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4900 if (new_views.size() > 0) {
4901 _routes->routes_added (new_views);
4902 _summary->routes_added (new_views);
4905 if (show_editor_mixer_when_tracks_arrive) {
4906 show_editor_mixer (true);
4909 editor_list_button.set_sensitive (true);
4913 Editor::timeaxisview_deleted (TimeAxisView *tv)
4915 if (tv == entered_track) {
4919 if (_session && _session->deletion_in_progress()) {
4920 /* the situation is under control */
4924 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4926 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4928 _routes->route_removed (tv);
4930 TimeAxisView::Children c = tv->get_child_list ();
4931 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4932 if (entered_track == i->get()) {
4937 /* remove it from the list of track views */
4939 TrackViewList::iterator i;
4941 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4942 i = track_views.erase (i);
4945 /* update whatever the current mixer strip is displaying, if revelant */
4947 boost::shared_ptr<Route> route;
4950 route = rtav->route ();
4953 if (current_mixer_strip && current_mixer_strip->route() == route) {
4955 TimeAxisView* next_tv;
4957 if (track_views.empty()) {
4959 } else if (i == track_views.end()) {
4960 next_tv = track_views.front();
4967 set_selected_mixer_strip (*next_tv);
4969 /* make the editor mixer strip go away setting the
4970 * button to inactive (which also unticks the menu option)
4973 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4979 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4981 if (apply_to_selection) {
4982 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4984 TrackSelection::iterator j = i;
4987 hide_track_in_display (*i, false);
4992 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4994 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4995 // this will hide the mixer strip
4996 set_selected_mixer_strip (*tv);
4999 _routes->hide_track_in_display (*tv);
5004 Editor::sync_track_view_list_and_routes ()
5006 track_views = TrackViewList (_routes->views ());
5008 _summary->set_dirty ();
5009 _group_tabs->set_dirty ();
5011 return false; // do not call again (until needed)
5015 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5017 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5022 /** Find a RouteTimeAxisView by the ID of its route */
5024 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5026 RouteTimeAxisView* v;
5028 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5029 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5030 if(v->route()->id() == id) {
5040 Editor::fit_route_group (RouteGroup *g)
5042 TrackViewList ts = axis_views_from_routes (g->route_list ());
5047 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5049 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5052 _session->cancel_audition ();
5056 if (_session->is_auditioning()) {
5057 _session->cancel_audition ();
5058 if (r == last_audition_region) {
5063 _session->audition_region (r);
5064 last_audition_region = r;
5069 Editor::hide_a_region (boost::shared_ptr<Region> r)
5071 r->set_hidden (true);
5075 Editor::show_a_region (boost::shared_ptr<Region> r)
5077 r->set_hidden (false);
5081 Editor::audition_region_from_region_list ()
5083 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5087 Editor::hide_region_from_region_list ()
5089 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5093 Editor::show_region_in_region_list ()
5095 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5099 Editor::step_edit_status_change (bool yn)
5102 start_step_editing ();
5104 stop_step_editing ();
5109 Editor::start_step_editing ()
5111 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5115 Editor::stop_step_editing ()
5117 step_edit_connection.disconnect ();
5121 Editor::check_step_edit ()
5123 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5124 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5126 mtv->check_step_edit ();
5130 return true; // do it again, till we stop
5134 Editor::scroll_press (Direction dir)
5136 ++_scroll_callbacks;
5138 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5139 /* delay the first auto-repeat */
5145 scroll_backward (1);
5153 scroll_tracks_up_line ();
5157 scroll_tracks_down_line ();
5161 /* do hacky auto-repeat */
5162 if (!_scroll_connection.connected ()) {
5164 _scroll_connection = Glib::signal_timeout().connect (
5165 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5168 _scroll_callbacks = 0;
5175 Editor::scroll_release ()
5177 _scroll_connection.disconnect ();
5180 /** Queue a change for the Editor viewport x origin to follow the playhead */
5182 Editor::reset_x_origin_to_follow_playhead ()
5184 framepos_t const frame = playhead_cursor->current_frame ();
5186 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5188 if (_session->transport_speed() < 0) {
5190 if (frame > (current_page_samples() / 2)) {
5191 center_screen (frame-(current_page_samples()/2));
5193 center_screen (current_page_samples()/2);
5200 if (frame < leftmost_frame) {
5202 if (_session->transport_rolling()) {
5203 /* rolling; end up with the playhead at the right of the page */
5204 l = frame - current_page_samples ();
5206 /* not rolling: end up with the playhead 1/4 of the way along the page */
5207 l = frame - current_page_samples() / 4;
5211 if (_session->transport_rolling()) {
5212 /* rolling: end up with the playhead on the left of the page */
5215 /* not rolling: end up with the playhead 3/4 of the way along the page */
5216 l = frame - 3 * current_page_samples() / 4;
5224 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5230 Editor::super_rapid_screen_update ()
5232 if (!_session || !_session->engine().running()) {
5236 /* METERING / MIXER STRIPS */
5238 /* update track meters, if required */
5239 if (is_mapped() && meters_running) {
5240 RouteTimeAxisView* rtv;
5241 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5242 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5243 rtv->fast_update ();
5248 /* and any current mixer strip */
5249 if (current_mixer_strip) {
5250 current_mixer_strip->fast_update ();
5253 /* PLAYHEAD AND VIEWPORT */
5255 framepos_t const frame = _session->audible_frame();
5257 /* There are a few reasons why we might not update the playhead / viewport stuff:
5259 * 1. we don't update things when there's a pending locate request, otherwise
5260 * when the editor requests a locate there is a chance that this method
5261 * will move the playhead before the locate request is processed, causing
5263 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5264 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5267 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5269 last_update_frame = frame;
5271 if (!_dragging_playhead) {
5272 playhead_cursor->set_position (frame);
5275 if (!_stationary_playhead) {
5277 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5278 /* We only do this if we aren't already
5279 handling a visual change (ie if
5280 pending_visual_change.being_handled is
5281 false) so that these requests don't stack
5282 up there are too many of them to handle in
5285 reset_x_origin_to_follow_playhead ();
5290 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5294 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5295 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5296 if (target <= 0.0) {
5299 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5300 target = (target * 0.15) + (current * 0.85);
5306 set_horizontal_position (current);
5315 Editor::session_going_away ()
5317 _have_idled = false;
5319 _session_connections.drop_connections ();
5321 super_rapid_screen_update_connection.disconnect ();
5323 selection->clear ();
5324 cut_buffer->clear ();
5326 clicked_regionview = 0;
5327 clicked_axisview = 0;
5328 clicked_routeview = 0;
5329 entered_regionview = 0;
5331 last_update_frame = 0;
5334 playhead_cursor->hide ();
5336 /* rip everything out of the list displays */
5340 _route_groups->clear ();
5342 /* do this first so that deleting a track doesn't reset cms to null
5343 and thus cause a leak.
5346 if (current_mixer_strip) {
5347 if (current_mixer_strip->get_parent() != 0) {
5348 global_hpacker.remove (*current_mixer_strip);
5350 delete current_mixer_strip;
5351 current_mixer_strip = 0;
5354 /* delete all trackviews */
5356 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5359 track_views.clear ();
5361 nudge_clock->set_session (0);
5363 editor_list_button.set_active(false);
5364 editor_list_button.set_sensitive(false);
5366 /* clear tempo/meter rulers */
5367 remove_metric_marks ();
5369 clear_marker_display ();
5371 stop_step_editing ();
5373 /* get rid of any existing editor mixer strip */
5375 WindowTitle title(Glib::get_application_name());
5376 title += _("Editor");
5378 set_title (title.get_string());
5380 SessionHandlePtr::session_going_away ();
5385 Editor::show_editor_list (bool yn)
5388 _the_notebook.show ();
5390 _the_notebook.hide ();
5395 Editor::change_region_layering_order (bool from_context_menu)
5397 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5399 if (!clicked_routeview) {
5400 if (layering_order_editor) {
5401 layering_order_editor->hide ();
5406 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5412 boost::shared_ptr<Playlist> pl = track->playlist();
5418 if (layering_order_editor == 0) {
5419 layering_order_editor = new RegionLayeringOrderEditor (*this);
5422 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5423 layering_order_editor->maybe_present ();
5427 Editor::update_region_layering_order_editor ()
5429 if (layering_order_editor && layering_order_editor->is_visible ()) {
5430 change_region_layering_order (true);
5435 Editor::setup_fade_images ()
5437 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5438 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5439 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5440 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5441 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5443 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5444 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5445 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5446 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5447 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5449 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5450 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-symmetric")));
5451 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5452 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5453 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-constant-power")));
5455 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5456 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-symmetric")));
5457 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5458 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5459 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-constant-power")));
5463 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5465 Editor::action_menu_item (std::string const & name)
5467 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5470 return *manage (a->create_menu_item ());
5474 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5476 EventBox* b = manage (new EventBox);
5477 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5478 Label* l = manage (new Label (name));
5482 _the_notebook.append_page (widget, *b);
5486 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5488 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5489 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5492 if (ev->type == GDK_2BUTTON_PRESS) {
5494 /* double-click on a notebook tab shrinks or expands the notebook */
5496 if (_notebook_shrunk) {
5497 if (pre_notebook_shrink_pane_width) {
5498 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5500 _notebook_shrunk = false;
5502 pre_notebook_shrink_pane_width = edit_pane.get_position();
5504 /* this expands the LHS of the edit pane to cover the notebook
5505 PAGE but leaves the tabs visible.
5507 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5508 _notebook_shrunk = true;
5516 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5518 using namespace Menu_Helpers;
5520 MenuList& items = _control_point_context_menu.items ();
5523 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5524 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5525 if (!can_remove_control_point (item)) {
5526 items.back().set_sensitive (false);
5529 _control_point_context_menu.popup (event->button.button, event->button.time);
5533 Editor::zoom_vertical_modifier_released()
5535 _stepping_axis_view = 0;
5539 Editor::ui_parameter_changed (string parameter)
5541 if (parameter == "icon-set") {
5542 while (!_cursor_stack.empty()) {
5543 _cursor_stack.pop();
5545 _cursors->set_cursor_set (ARDOUR_UI::config()->get_icon_set());
5546 } else if (parameter == "draggable-playhead") {
5547 if (_verbose_cursor) {
5548 playhead_cursor->set_sensitive (ARDOUR_UI::config()->get_draggable_playhead());