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"
48 #include <glibmm/miscutils.h>
49 #include <gtkmm/image.h>
50 #include <gdkmm/color.h>
51 #include <gdkmm/bitmap.h>
53 #include "gtkmm2ext/bindings.h"
54 #include "gtkmm2ext/grouped_buttons.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/tearoff.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/window_title.h"
59 #include "gtkmm2ext/choice.h"
60 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioplaylist.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/midi_region.h"
67 #include "ardour/plugin_manager.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_directory.h"
71 #include "ardour/session_route.h"
72 #include "ardour/session_state_utils.h"
73 #include "ardour/tempo.h"
74 #include "ardour/utils.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/audioengine.h"
78 #include "control_protocol/control_protocol.h"
82 #include "analysis_window.h"
83 #include "audio_clock.h"
84 #include "audio_region_view.h"
85 #include "audio_streamview.h"
86 #include "audio_time_axis.h"
87 #include "automation_time_axis.h"
88 #include "bundle_manager.h"
89 #include "button_joiner.h"
90 #include "canvas-noevent-text.h"
91 #include "canvas_impl.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 "simpleline.h"
122 #include "tempo_lines.h"
123 #include "time_axis_view.h"
129 #include "imageframe_socket_handler.h"
133 using namespace ARDOUR;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 const double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
148 N_("Timecode Frames"),
149 N_("Timecode Seconds"),
150 N_("Timecode Minutes"),
180 static const gchar *_snap_mode_strings[] = {
187 static const gchar *_edit_point_strings[] = {
194 static const gchar *_zoom_focus_strings[] = {
204 #ifdef USE_RUBBERBAND
205 static const gchar *_rb_opt_strings[] = {
208 N_("Balanced multitimbral mixture"),
209 N_("Unpitched percussion with stable notes"),
210 N_("Crisp monophonic instrumental"),
211 N_("Unpitched solo percussion"),
212 N_("Resample without preserving pitch"),
218 show_me_the_size (Requisition* r, const char* what)
220 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
225 pane_size_watcher (Paned* pane)
227 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
228 it is no longer accessible. so stop that. this doesn't happen on X11,
229 just the quartz backend.
234 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
236 gint pos = pane->get_position ();
238 if (pos > max_width_of_lhs) {
239 pane->set_position (max_width_of_lhs);
245 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
247 /* time display buttons */
248 , minsec_label (_("Mins:Secs"))
249 , bbt_label (_("Bars:Beats"))
250 , timecode_label (_("Timecode"))
251 , samples_label (_("Samples"))
252 , tempo_label (_("Tempo"))
253 , meter_label (_("Meter"))
254 , mark_label (_("Location Markers"))
255 , range_mark_label (_("Range Markers"))
256 , transport_mark_label (_("Loop/Punch Ranges"))
257 , cd_mark_label (_("CD Markers"))
258 , edit_packer (4, 4, true)
260 /* the values here don't matter: layout widgets
261 reset them as needed.
264 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
266 /* tool bar related */
268 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
270 , toolbar_selection_clock_table (2,3)
272 , automation_mode_button (_("mode"))
274 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
277 , image_socket_listener(0)
282 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
283 , meters_running(false)
284 , _pending_locate_request (false)
285 , _pending_initial_locate (false)
286 , _last_cut_copy_source_track (0)
288 , _region_selection_change_updates_region_list (true)
289 , _following_mixer_selection (false)
293 /* we are a singleton */
295 PublicEditor::_instance = this;
299 selection = new Selection (this);
300 cut_buffer = new Selection (this);
302 clicked_regionview = 0;
303 clicked_axisview = 0;
304 clicked_routeview = 0;
305 clicked_control_point = 0;
306 last_update_frame = 0;
307 pre_press_cursor = 0;
308 _drags = new DragManager (this);
309 current_mixer_strip = 0;
312 snap_type_strings = I18N (_snap_type_strings);
313 snap_mode_strings = I18N (_snap_mode_strings);
314 zoom_focus_strings = I18N (_zoom_focus_strings);
315 edit_point_strings = I18N (_edit_point_strings);
316 #ifdef USE_RUBBERBAND
317 rb_opt_strings = I18N (_rb_opt_strings);
321 snap_threshold = 5.0;
322 bbt_beat_subdivision = 4;
325 last_autoscroll_x = 0;
326 last_autoscroll_y = 0;
327 autoscroll_active = false;
328 autoscroll_timeout_tag = -1;
333 current_interthread_info = 0;
334 _show_measures = true;
336 show_gain_after_trim = false;
338 have_pending_keyboard_selection = false;
339 _follow_playhead = true;
340 _stationary_playhead = false;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
368 no_save_visual = false;
370 within_track_canvas = false;
372 scrubbing_direction = 0;
376 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
377 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
378 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
379 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
380 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
382 _edit_point = EditAtMouse;
383 _internal_editing = false;
384 current_canvas_cursor = 0;
386 frames_per_unit = 2048; /* too early to use reset_zoom () */
388 _scroll_callbacks = 0;
390 zoom_focus = ZoomFocusLeft;
391 set_zoom_focus (ZoomFocusLeft);
392 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
394 bbt_label.set_name ("EditorTimeButton");
395 bbt_label.set_size_request (-1, (int)timebar_height);
396 bbt_label.set_alignment (1.0, 0.5);
397 bbt_label.set_padding (5,0);
399 bbt_label.set_no_show_all();
400 minsec_label.set_name ("EditorTimeButton");
401 minsec_label.set_size_request (-1, (int)timebar_height);
402 minsec_label.set_alignment (1.0, 0.5);
403 minsec_label.set_padding (5,0);
404 minsec_label.hide ();
405 minsec_label.set_no_show_all();
406 timecode_label.set_name ("EditorTimeButton");
407 timecode_label.set_size_request (-1, (int)timebar_height);
408 timecode_label.set_alignment (1.0, 0.5);
409 timecode_label.set_padding (5,0);
410 timecode_label.hide ();
411 timecode_label.set_no_show_all();
412 samples_label.set_name ("EditorTimeButton");
413 samples_label.set_size_request (-1, (int)timebar_height);
414 samples_label.set_alignment (1.0, 0.5);
415 samples_label.set_padding (5,0);
416 samples_label.hide ();
417 samples_label.set_no_show_all();
419 tempo_label.set_name ("EditorTimeButton");
420 tempo_label.set_size_request (-1, (int)timebar_height);
421 tempo_label.set_alignment (1.0, 0.5);
422 tempo_label.set_padding (5,0);
424 tempo_label.set_no_show_all();
426 meter_label.set_name ("EditorTimeButton");
427 meter_label.set_size_request (-1, (int)timebar_height);
428 meter_label.set_alignment (1.0, 0.5);
429 meter_label.set_padding (5,0);
431 meter_label.set_no_show_all();
433 mark_label.set_name ("EditorTimeButton");
434 mark_label.set_size_request (-1, (int)timebar_height);
435 mark_label.set_alignment (1.0, 0.5);
436 mark_label.set_padding (5,0);
438 mark_label.set_no_show_all();
440 cd_mark_label.set_name ("EditorTimeButton");
441 cd_mark_label.set_size_request (-1, (int)timebar_height);
442 cd_mark_label.set_alignment (1.0, 0.5);
443 cd_mark_label.set_padding (5,0);
444 cd_mark_label.hide();
445 cd_mark_label.set_no_show_all();
447 range_mark_label.set_name ("EditorTimeButton");
448 range_mark_label.set_size_request (-1, (int)timebar_height);
449 range_mark_label.set_alignment (1.0, 0.5);
450 range_mark_label.set_padding (5,0);
451 range_mark_label.hide();
452 range_mark_label.set_no_show_all();
454 transport_mark_label.set_name ("EditorTimeButton");
455 transport_mark_label.set_size_request (-1, (int)timebar_height);
456 transport_mark_label.set_alignment (1.0, 0.5);
457 transport_mark_label.set_padding (5,0);
458 transport_mark_label.hide();
459 transport_mark_label.set_no_show_all();
461 initialize_rulers ();
462 initialize_canvas ();
464 _summary = new EditorSummary (this);
466 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
467 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
469 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
471 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
472 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
474 edit_controls_vbox.set_spacing (0);
475 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
476 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
478 HBox* h = manage (new HBox);
479 _group_tabs = new EditorGroupTabs (this);
480 h->pack_start (*_group_tabs, PACK_SHRINK);
481 h->pack_start (edit_controls_vbox);
482 controls_layout.add (*h);
484 controls_layout.set_name ("EditControlsBase");
485 controls_layout.add_events (Gdk::SCROLL_MASK);
486 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
488 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
489 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
491 _cursors = new MouseCursors;
493 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
494 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
495 0.0, 1.0, 100.0, 1.0));
497 pad_line_1->property_color_rgba() = 0xFF0000FF;
502 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
503 time_canvas_vbox.set_size_request (-1, -1);
505 ruler_label_event_box.add (ruler_label_vbox);
506 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
507 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
509 time_button_event_box.add (time_button_vbox);
510 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
511 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
513 /* these enable us to have a dedicated window (for cursor setting, etc.)
514 for the canvas areas.
517 track_canvas_event_box.add (*track_canvas);
519 time_canvas_event_box.add (time_canvas_vbox);
520 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
522 edit_packer.set_col_spacings (0);
523 edit_packer.set_row_spacings (0);
524 edit_packer.set_homogeneous (false);
525 edit_packer.set_border_width (0);
526 edit_packer.set_name ("EditorWindow");
528 /* labels for the rulers */
529 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
530 /* labels for the marker "tracks" */
531 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
533 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
535 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
537 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
539 bottom_hbox.set_border_width (2);
540 bottom_hbox.set_spacing (3);
542 _route_groups = new EditorRouteGroups (this);
543 _routes = new EditorRoutes (this);
544 _regions = new EditorRegions (this);
545 _snapshots = new EditorSnapshots (this);
546 _locations = new EditorLocations (this);
548 add_notebook_page (_("Regions"), _regions->widget ());
549 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
550 add_notebook_page (_("Snapshots"), _snapshots->widget ());
551 add_notebook_page (_("Route Groups"), _route_groups->widget ());
552 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
554 _the_notebook.set_show_tabs (true);
555 _the_notebook.set_scrollable (true);
556 _the_notebook.popup_disable ();
557 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
558 _the_notebook.show_all ();
560 _notebook_shrunk = false;
562 editor_summary_pane.pack1(edit_packer);
564 Button* summary_arrows_left_left = manage (new Button);
565 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
566 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
567 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 Button* summary_arrows_left_right = manage (new Button);
570 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
571 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
572 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
574 VBox* summary_arrows_left = manage (new VBox);
575 summary_arrows_left->pack_start (*summary_arrows_left_left);
576 summary_arrows_left->pack_start (*summary_arrows_left_right);
578 Button* summary_arrows_right_up = manage (new Button);
579 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
580 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
581 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 Button* summary_arrows_right_down = manage (new Button);
584 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
585 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
586 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
588 VBox* summary_arrows_right = manage (new VBox);
589 summary_arrows_right->pack_start (*summary_arrows_right_up);
590 summary_arrows_right->pack_start (*summary_arrows_right_down);
592 Frame* summary_frame = manage (new Frame);
593 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
595 summary_frame->add (*_summary);
596 summary_frame->show ();
598 _summary_hbox.pack_start (*summary_arrows_left, false, false);
599 _summary_hbox.pack_start (*summary_frame, true, true);
600 _summary_hbox.pack_start (*summary_arrows_right, false, false);
602 editor_summary_pane.pack2 (_summary_hbox);
604 edit_pane.pack1 (editor_summary_pane, true, true);
605 edit_pane.pack2 (_the_notebook, false, true);
607 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
609 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
611 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
613 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
614 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
616 top_hbox.pack_start (toolbar_frame);
618 HBox *hbox = manage (new HBox);
619 hbox->pack_start (edit_pane, true, true);
621 global_vpacker.pack_start (top_hbox, false, false);
622 global_vpacker.pack_start (*hbox, true, true);
624 global_hpacker.pack_start (global_vpacker, true, true);
626 set_name ("EditorWindow");
627 add_accel_group (ActionManager::ui_manager->get_accel_group());
629 status_bar_hpacker.show ();
631 vpacker.pack_end (status_bar_hpacker, false, false);
632 vpacker.pack_end (global_hpacker, true, true);
634 /* register actions now so that set_state() can find them and set toggles/checks etc */
637 /* when we start using our own keybinding system for the editor, this
638 * will be uncommented
644 _snap_type = SnapToBeat;
645 set_snap_to (_snap_type);
646 _snap_mode = SnapOff;
647 set_snap_mode (_snap_mode);
648 set_mouse_mode (MouseObject, true);
649 pre_internal_mouse_mode = MouseObject;
650 pre_internal_snap_type = _snap_type;
651 pre_internal_snap_mode = _snap_mode;
652 internal_snap_type = _snap_type;
653 internal_snap_mode = _snap_mode;
654 set_edit_point_preference (EditAtMouse, true);
656 _playlist_selector = new PlaylistSelector();
657 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
659 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
663 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
664 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
666 nudge_forward_button.set_name ("TransportButton");
667 nudge_backward_button.set_name ("TransportButton");
669 fade_context_menu.set_name ("ArdourContextMenu");
671 /* icons, titles, WM stuff */
673 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
674 Glib::RefPtr<Gdk::Pixbuf> icon;
676 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
683 window_icons.push_back (icon);
685 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
686 window_icons.push_back (icon);
688 if (!window_icons.empty()) {
689 // set_icon_list (window_icons);
690 set_default_icon_list (window_icons);
693 WindowTitle title(Glib::get_application_name());
694 title += _("Editor");
695 set_title (title.get_string());
696 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
699 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
701 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
702 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
704 /* allow external control surfaces/protocols to do various things */
706 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
707 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
708 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
709 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
710 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
711 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
712 ControlProtocol::GotoView.connect (*this, invalidator (*this), ui_bind (&Editor::control_view, this, _1), gui_context());
713 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
714 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), ui_bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
715 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), ui_bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
716 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), ui_bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
717 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), ui_bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
719 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
720 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
721 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
722 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), ui_bind (&Editor::control_unselect, this), gui_context());
724 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
726 /* problematic: has to return a value and thus cannot be x-thread */
728 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
730 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
732 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
734 _ignore_region_action = false;
735 _last_region_menu_was_main = false;
736 _popup_region_menu_item = 0;
738 _show_marker_lines = false;
739 _over_region_trim_target = false;
741 /* Button bindings */
743 button_bindings = new Bindings;
745 XMLNode* node = button_settings();
747 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
748 button_bindings->load (**i);
755 setup_fade_images ();
761 if(image_socket_listener) {
762 if(image_socket_listener->is_connected())
764 image_socket_listener->close_connection() ;
767 delete image_socket_listener ;
768 image_socket_listener = 0 ;
772 delete button_bindings;
774 delete _route_groups;
780 Editor::button_settings () const
782 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
783 XMLNode* node = find_named_node (*settings, X_("Buttons"));
786 cerr << "new empty Button node\n";
787 node = new XMLNode (X_("Buttons"));
794 Editor::add_toplevel_controls (Container& cont)
796 vpacker.pack_start (cont, false, false);
801 Editor::catch_vanishing_regionview (RegionView *rv)
803 /* note: the selection will take care of the vanishing
804 audioregionview by itself.
807 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
811 if (clicked_regionview == rv) {
812 clicked_regionview = 0;
815 if (entered_regionview == rv) {
816 set_entered_regionview (0);
819 if (!_all_region_actions_sensitized) {
820 sensitize_all_region_actions (true);
823 _over_region_trim_target = false;
827 Editor::set_entered_regionview (RegionView* rv)
829 if (rv == entered_regionview) {
833 if (entered_regionview) {
834 entered_regionview->exited ();
837 if ((entered_regionview = rv) != 0) {
838 entered_regionview->entered (internal_editing ());
841 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
842 /* This RegionView entry might have changed what region actions
843 are allowed, so sensitize them all in case a key is pressed.
845 sensitize_all_region_actions (true);
850 Editor::set_entered_track (TimeAxisView* tav)
853 entered_track->exited ();
856 if ((entered_track = tav) != 0) {
857 entered_track->entered ();
862 Editor::show_window ()
864 if (!is_visible ()) {
867 /* XXX: this is a bit unfortunate; it would probably
868 be nicer if we could just call show () above rather
869 than needing the show_all ()
872 /* re-hide stuff if necessary */
873 editor_list_button_toggled ();
874 parameter_changed ("show-summary");
875 parameter_changed ("show-group-tabs");
876 parameter_changed ("show-zoom-tools");
878 /* now reset all audio_time_axis heights, because widgets might need
884 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
885 tv = (static_cast<TimeAxisView*>(*i));
889 if (current_mixer_strip) {
890 current_mixer_strip->hide_things ();
891 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
899 Editor::instant_save ()
901 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
906 _session->add_instant_xml(get_state());
908 Config->add_instant_xml(get_state());
913 Editor::zoom_adjustment_changed ()
919 double fpu = zoom_range_clock->current_duration() / _canvas_width;
923 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
924 } else if (fpu > _session->current_end_frame() / _canvas_width) {
925 fpu = _session->current_end_frame() / _canvas_width;
926 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
933 Editor::control_vertical_zoom_in_all ()
935 tav_zoom_smooth (false, true);
939 Editor::control_vertical_zoom_out_all ()
941 tav_zoom_smooth (true, true);
945 Editor::control_vertical_zoom_in_selected ()
947 tav_zoom_smooth (false, false);
951 Editor::control_vertical_zoom_out_selected ()
953 tav_zoom_smooth (true, false);
957 Editor::control_view (uint32_t view)
959 goto_visual_state (view);
963 Editor::control_unselect ()
965 selection->clear_tracks ();
969 Editor::control_select (uint32_t rid, Selection::Operation op)
971 /* handles the (static) signal from the ControlProtocol class that
972 * requests setting the selected track to a given RID
979 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
985 TimeAxisView* tav = axis_view_from_route (r);
990 selection->add (tav);
992 case Selection::Toggle:
993 selection->toggle (tav);
995 case Selection::Extend:
998 selection->set (tav);
1002 selection->clear_tracks ();
1007 Editor::control_scroll (float fraction)
1009 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1015 double step = fraction * current_page_frames();
1018 _control_scroll_target is an optional<T>
1020 it acts like a pointer to an framepos_t, with
1021 a operator conversion to boolean to check
1022 that it has a value could possibly use
1023 playhead_cursor->current_frame to store the
1024 value and a boolean in the class to know
1025 when it's out of date
1028 if (!_control_scroll_target) {
1029 _control_scroll_target = _session->transport_frame();
1030 _dragging_playhead = true;
1033 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1034 *_control_scroll_target = 0;
1035 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1036 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1038 *_control_scroll_target += (framepos_t) floor (step);
1041 /* move visuals, we'll catch up with it later */
1043 playhead_cursor->set_position (*_control_scroll_target);
1044 UpdateAllTransportClocks (*_control_scroll_target);
1046 if (*_control_scroll_target > (current_page_frames() / 2)) {
1047 /* try to center PH in window */
1048 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1054 Now we do a timeout to actually bring the session to the right place
1055 according to the playhead. This is to avoid reading disk buffers on every
1056 call to control_scroll, which is driven by ScrollTimeline and therefore
1057 probably by a control surface wheel which can generate lots of events.
1059 /* cancel the existing timeout */
1061 control_scroll_connection.disconnect ();
1063 /* add the next timeout */
1065 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1069 Editor::deferred_control_scroll (framepos_t /*target*/)
1071 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1072 // reset for next stream
1073 _control_scroll_target = boost::none;
1074 _dragging_playhead = false;
1079 Editor::access_action (std::string action_group, std::string action_item)
1085 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1088 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1096 Editor::on_realize ()
1098 Window::on_realize ();
1103 Editor::map_position_change (framepos_t frame)
1105 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1107 if (_session == 0) {
1111 if (_follow_playhead) {
1112 center_screen (frame);
1115 playhead_cursor->set_position (frame);
1119 Editor::center_screen (framepos_t frame)
1121 double page = _canvas_width * frames_per_unit;
1123 /* if we're off the page, then scroll.
1126 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1127 center_screen_internal (frame, page);
1132 Editor::center_screen_internal (framepos_t frame, float page)
1137 frame -= (framepos_t) page;
1142 reset_x_origin (frame);
1147 Editor::update_title ()
1149 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1152 bool dirty = _session->dirty();
1154 string session_name;
1156 if (_session->snap_name() != _session->name()) {
1157 session_name = _session->snap_name();
1159 session_name = _session->name();
1163 session_name = "*" + session_name;
1166 WindowTitle title(session_name);
1167 title += Glib::get_application_name();
1168 set_title (title.get_string());
1173 Editor::set_session (Session *t)
1175 SessionHandlePtr::set_session (t);
1181 zoom_range_clock->set_session (_session);
1182 _playlist_selector->set_session (_session);
1183 nudge_clock->set_session (_session);
1184 _summary->set_session (_session);
1185 _group_tabs->set_session (_session);
1186 _route_groups->set_session (_session);
1187 _regions->set_session (_session);
1188 _snapshots->set_session (_session);
1189 _routes->set_session (_session);
1190 _locations->set_session (_session);
1192 if (rhythm_ferret) {
1193 rhythm_ferret->set_session (_session);
1196 if (analysis_window) {
1197 analysis_window->set_session (_session);
1201 sfbrowser->set_session (_session);
1204 compute_fixed_ruler_scale ();
1206 /* Make sure we have auto loop and auto punch ranges */
1208 Location* loc = _session->locations()->auto_loop_location();
1210 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1212 if (loc->start() == loc->end()) {
1213 loc->set_end (loc->start() + 1);
1216 _session->locations()->add (loc, false);
1217 _session->set_auto_loop_location (loc);
1220 loc->set_name (_("Loop"));
1223 loc = _session->locations()->auto_punch_location();
1226 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1228 if (loc->start() == loc->end()) {
1229 loc->set_end (loc->start() + 1);
1232 _session->locations()->add (loc, false);
1233 _session->set_auto_punch_location (loc);
1236 loc->set_name (_("Punch"));
1239 refresh_location_display ();
1241 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1242 the selected Marker; this needs the LocationMarker list to be available.
1244 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1245 set_state (*node, Stateful::loading_state_version);
1247 /* catch up with the playhead */
1249 _session->request_locate (playhead_cursor->current_frame);
1250 _pending_initial_locate = true;
1254 /* These signals can all be emitted by a non-GUI thread. Therefore the
1255 handlers for them must not attempt to directly interact with the GUI,
1256 but use Gtkmm2ext::UI::instance()->call_slot();
1259 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1260 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1261 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1262 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1263 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1264 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1265 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1266 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1267 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1268 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1269 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1270 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1271 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display, this), gui_context());
1272 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1274 playhead_cursor->canvas_item.show ();
1276 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1277 Config->map_parameters (pc);
1278 _session->config.map_parameters (pc);
1280 restore_ruler_visibility ();
1281 //tempo_map_changed (PropertyChange (0));
1282 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1284 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1285 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1288 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1289 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1292 switch (_snap_type) {
1293 case SnapToRegionStart:
1294 case SnapToRegionEnd:
1295 case SnapToRegionSync:
1296 case SnapToRegionBoundary:
1297 build_region_boundary_cache ();
1304 /* register for undo history */
1305 _session->register_with_memento_command_factory(id(), this);
1307 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1309 start_updating_meters ();
1313 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1315 if (a->get_name() == "RegionMenu") {
1316 /* When the main menu's region menu is opened, we setup the actions so that they look right
1317 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1318 so we resensitize all region actions when the entered regionview or the region selection
1319 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1320 happens after the region context menu is opened. So we set a flag here, too.
1324 sensitize_the_right_region_actions ();
1325 _last_region_menu_was_main = true;
1329 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1331 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1333 using namespace Menu_Helpers;
1334 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1337 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1341 MenuList& items (fade_context_menu.items());
1345 switch (item_type) {
1347 case FadeInHandleItem:
1348 if (arv->audio_region()->fade_in_active()) {
1349 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1351 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1354 items.push_back (SeparatorElem());
1356 if (Profile->get_sae()) {
1358 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1359 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1366 *_fade_in_images[FadeLinear],
1367 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1371 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1376 *_fade_in_images[FadeFast],
1377 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1380 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1385 *_fade_in_images[FadeLogB],
1386 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1389 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1394 *_fade_in_images[FadeLogA],
1395 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1398 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1403 *_fade_in_images[FadeSlow],
1404 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1407 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1413 case FadeOutHandleItem:
1414 if (arv->audio_region()->fade_out_active()) {
1415 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1417 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1420 items.push_back (SeparatorElem());
1422 if (Profile->get_sae()) {
1423 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1424 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1430 *_fade_out_images[FadeLinear],
1431 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1435 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1440 *_fade_out_images[FadeFast],
1441 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1444 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1449 *_fade_out_images[FadeLogB],
1450 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1453 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1458 *_fade_out_images[FadeLogA],
1459 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1462 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1467 *_fade_out_images[FadeSlow],
1468 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1471 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1477 fatal << _("programming error: ")
1478 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1483 fade_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_dialog), 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)));
1822 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1824 using namespace Menu_Helpers;
1828 Menu *play_menu = manage (new Menu);
1829 MenuList& play_items = play_menu->items();
1830 play_menu->set_name ("ArdourContextMenu");
1832 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1833 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1834 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1835 play_items.push_back (SeparatorElem());
1836 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1838 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1842 Menu *select_menu = manage (new Menu);
1843 MenuList& select_items = select_menu->items();
1844 select_menu->set_name ("ArdourContextMenu");
1846 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1847 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1848 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1849 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1850 select_items.push_back (SeparatorElem());
1851 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1852 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1853 select_items.push_back (SeparatorElem());
1854 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1855 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1856 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1857 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1858 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1859 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1860 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1862 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1866 Menu *cutnpaste_menu = manage (new Menu);
1867 MenuList& cutnpaste_items = cutnpaste_menu->items();
1868 cutnpaste_menu->set_name ("ArdourContextMenu");
1870 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1871 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1872 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1874 cutnpaste_items.push_back (SeparatorElem());
1876 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1877 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1879 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1881 /* Adding new material */
1883 edit_items.push_back (SeparatorElem());
1884 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1885 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1889 Menu *nudge_menu = manage (new Menu());
1890 MenuList& nudge_items = nudge_menu->items();
1891 nudge_menu->set_name ("ArdourContextMenu");
1893 edit_items.push_back (SeparatorElem());
1894 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1895 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1896 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1897 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1899 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1903 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1905 using namespace Menu_Helpers;
1909 Menu *play_menu = manage (new Menu);
1910 MenuList& play_items = play_menu->items();
1911 play_menu->set_name ("ArdourContextMenu");
1913 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1914 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1915 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1919 Menu *select_menu = manage (new Menu);
1920 MenuList& select_items = select_menu->items();
1921 select_menu->set_name ("ArdourContextMenu");
1923 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1924 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1925 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1926 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1927 select_items.push_back (SeparatorElem());
1928 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1929 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1930 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1931 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1933 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1937 Menu *cutnpaste_menu = manage (new Menu);
1938 MenuList& cutnpaste_items = cutnpaste_menu->items();
1939 cutnpaste_menu->set_name ("ArdourContextMenu");
1941 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1942 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1943 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1945 Menu *nudge_menu = manage (new Menu());
1946 MenuList& nudge_items = nudge_menu->items();
1947 nudge_menu->set_name ("ArdourContextMenu");
1949 edit_items.push_back (SeparatorElem());
1950 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1951 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1952 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1953 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1955 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1959 Editor::snap_type() const
1965 Editor::snap_mode() const
1971 Editor::set_snap_to (SnapType st)
1973 unsigned int snap_ind = (unsigned int)st;
1977 if (snap_ind > snap_type_strings.size() - 1) {
1979 _snap_type = (SnapType)snap_ind;
1982 string str = snap_type_strings[snap_ind];
1984 if (str != snap_type_selector.get_active_text()) {
1985 snap_type_selector.set_active_text (str);
1990 switch (_snap_type) {
1991 case SnapToBeatDiv128:
1992 case SnapToBeatDiv64:
1993 case SnapToBeatDiv32:
1994 case SnapToBeatDiv28:
1995 case SnapToBeatDiv24:
1996 case SnapToBeatDiv20:
1997 case SnapToBeatDiv16:
1998 case SnapToBeatDiv14:
1999 case SnapToBeatDiv12:
2000 case SnapToBeatDiv10:
2001 case SnapToBeatDiv8:
2002 case SnapToBeatDiv7:
2003 case SnapToBeatDiv6:
2004 case SnapToBeatDiv5:
2005 case SnapToBeatDiv4:
2006 case SnapToBeatDiv3:
2007 case SnapToBeatDiv2:
2008 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2009 update_tempo_based_rulers ();
2012 case SnapToRegionStart:
2013 case SnapToRegionEnd:
2014 case SnapToRegionSync:
2015 case SnapToRegionBoundary:
2016 build_region_boundary_cache ();
2024 SnapChanged (); /* EMIT SIGNAL */
2028 Editor::set_snap_mode (SnapMode mode)
2031 string str = snap_mode_strings[(int)mode];
2033 if (str != snap_mode_selector.get_active_text ()) {
2034 snap_mode_selector.set_active_text (str);
2040 Editor::set_edit_point_preference (EditPoint ep, bool force)
2042 bool changed = (_edit_point != ep);
2045 string str = edit_point_strings[(int)ep];
2047 if (str != edit_point_selector.get_active_text ()) {
2048 edit_point_selector.set_active_text (str);
2051 set_canvas_cursor ();
2053 if (!force && !changed) {
2057 const char* action=NULL;
2059 switch (_edit_point) {
2060 case EditAtPlayhead:
2061 action = "edit-at-playhead";
2063 case EditAtSelectedMarker:
2064 action = "edit-at-marker";
2067 action = "edit-at-mouse";
2071 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2073 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2077 bool in_track_canvas;
2079 if (!mouse_frame (foo, in_track_canvas)) {
2080 in_track_canvas = false;
2083 reset_canvas_action_sensitivity (in_track_canvas);
2089 Editor::set_state (const XMLNode& node, int /*version*/)
2091 const XMLProperty* prop;
2098 g.base_width = default_width;
2099 g.base_height = default_height;
2103 if ((geometry = find_named_node (node, "geometry")) != 0) {
2107 if ((prop = geometry->property("x_size")) == 0) {
2108 prop = geometry->property ("x-size");
2111 g.base_width = atoi(prop->value());
2113 if ((prop = geometry->property("y_size")) == 0) {
2114 prop = geometry->property ("y-size");
2117 g.base_height = atoi(prop->value());
2120 if ((prop = geometry->property ("x_pos")) == 0) {
2121 prop = geometry->property ("x-pos");
2124 x = atoi (prop->value());
2127 if ((prop = geometry->property ("y_pos")) == 0) {
2128 prop = geometry->property ("y-pos");
2131 y = atoi (prop->value());
2135 set_default_size (g.base_width, g.base_height);
2138 if (_session && (prop = node.property ("playhead"))) {
2140 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2141 playhead_cursor->set_position (pos);
2143 playhead_cursor->set_position (0);
2146 if ((prop = node.property ("mixer-width"))) {
2147 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2150 if ((prop = node.property ("zoom-focus"))) {
2151 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2154 if ((prop = node.property ("zoom"))) {
2155 reset_zoom (PBD::atof (prop->value()));
2157 reset_zoom (frames_per_unit);
2160 if ((prop = node.property ("snap-to"))) {
2161 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2164 if ((prop = node.property ("snap-mode"))) {
2165 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2168 if ((prop = node.property ("internal-snap-to"))) {
2169 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2172 if ((prop = node.property ("internal-snap-mode"))) {
2173 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2176 if ((prop = node.property ("pre-internal-snap-to"))) {
2177 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2180 if ((prop = node.property ("pre-internal-snap-mode"))) {
2181 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2184 if ((prop = node.property ("mouse-mode"))) {
2185 MouseMode m = str2mousemode(prop->value());
2186 set_mouse_mode (m, true);
2188 set_mouse_mode (MouseObject, true);
2191 if ((prop = node.property ("left-frame")) != 0) {
2193 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2197 reset_x_origin (pos);
2201 if ((prop = node.property ("y-origin")) != 0) {
2202 reset_y_origin (atof (prop->value ()));
2205 if ((prop = node.property ("internal-edit"))) {
2206 bool yn = string_is_affirmative (prop->value());
2207 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2209 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2210 tact->set_active (!yn);
2211 tact->set_active (yn);
2215 if ((prop = node.property ("join-object-range"))) {
2216 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2219 if ((prop = node.property ("edit-point"))) {
2220 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2223 if ((prop = node.property ("show-measures"))) {
2224 bool yn = string_is_affirmative (prop->value());
2225 _show_measures = yn;
2226 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2228 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2229 /* do it twice to force the change */
2230 tact->set_active (!yn);
2231 tact->set_active (yn);
2235 if ((prop = node.property ("follow-playhead"))) {
2236 bool yn = string_is_affirmative (prop->value());
2237 set_follow_playhead (yn);
2238 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2240 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2241 if (tact->get_active() != yn) {
2242 tact->set_active (yn);
2247 if ((prop = node.property ("stationary-playhead"))) {
2248 bool yn = string_is_affirmative (prop->value());
2249 set_stationary_playhead (yn);
2250 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2252 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2253 if (tact->get_active() != yn) {
2254 tact->set_active (yn);
2259 if ((prop = node.property ("region-list-sort-type"))) {
2260 RegionListSortType st;
2261 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2264 if ((prop = node.property ("show-editor-mixer"))) {
2266 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2269 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2270 bool yn = string_is_affirmative (prop->value());
2272 /* do it twice to force the change */
2274 tact->set_active (!yn);
2275 tact->set_active (yn);
2278 if ((prop = node.property ("show-editor-list"))) {
2280 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2283 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2284 bool yn = string_is_affirmative (prop->value());
2286 /* do it twice to force the change */
2288 tact->set_active (!yn);
2289 tact->set_active (yn);
2292 if ((prop = node.property (X_("editor-list-page")))) {
2293 _the_notebook.set_current_page (atoi (prop->value ()));
2296 if ((prop = node.property (X_("show-marker-lines")))) {
2297 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2299 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2300 bool yn = string_is_affirmative (prop->value ());
2302 tact->set_active (!yn);
2303 tact->set_active (yn);
2306 XMLNodeList children = node.children ();
2307 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2308 selection->set_state (**i, Stateful::current_state_version);
2309 _regions->set_state (**i);
2312 if ((prop = node.property ("maximised"))) {
2313 bool yn = string_is_affirmative (prop->value());
2315 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2319 if ((prop = node.property ("nudge-clock-value"))) {
2321 sscanf (prop->value().c_str(), "%" PRId64, &f);
2322 nudge_clock->set (f);
2324 nudge_clock->set_mode (AudioClock::Timecode);
2325 nudge_clock->set (_session->frame_rate() * 5, true);
2332 Editor::get_state ()
2334 XMLNode* node = new XMLNode ("Editor");
2337 id().print (buf, sizeof (buf));
2338 node->add_property ("id", buf);
2340 if (is_realized()) {
2341 Glib::RefPtr<Gdk::Window> win = get_window();
2343 int x, y, width, height;
2344 win->get_root_origin(x, y);
2345 win->get_size(width, height);
2347 XMLNode* geometry = new XMLNode ("geometry");
2349 snprintf(buf, sizeof(buf), "%d", width);
2350 geometry->add_property("x-size", string(buf));
2351 snprintf(buf, sizeof(buf), "%d", height);
2352 geometry->add_property("y-size", string(buf));
2353 snprintf(buf, sizeof(buf), "%d", x);
2354 geometry->add_property("x-pos", string(buf));
2355 snprintf(buf, sizeof(buf), "%d", y);
2356 geometry->add_property("y-pos", string(buf));
2357 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2358 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2359 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2360 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2361 geometry->add_property("edit-vertical-pane-pos", string(buf));
2363 node->add_child_nocopy (*geometry);
2366 maybe_add_mixer_strip_width (*node);
2368 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2369 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2370 node->add_property ("zoom", buf);
2371 node->add_property ("snap-to", enum_2_string (_snap_type));
2372 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2373 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2374 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2375 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2376 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2377 node->add_property ("edit-point", enum_2_string (_edit_point));
2379 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2380 node->add_property ("playhead", buf);
2381 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2382 node->add_property ("left-frame", buf);
2383 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2384 node->add_property ("y-origin", buf);
2386 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2387 node->add_property ("maximised", _maximised ? "yes" : "no");
2388 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2389 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2390 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2391 node->add_property ("mouse-mode", enum2str(mouse_mode));
2392 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2393 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2395 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2397 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2398 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2401 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2403 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2404 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2407 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2408 node->add_property (X_("editor-list-page"), buf);
2410 if (button_bindings) {
2411 XMLNode* bb = new XMLNode (X_("Buttons"));
2412 button_bindings->save (*bb);
2413 node->add_child_nocopy (*bb);
2416 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2418 node->add_child_nocopy (selection->get_state ());
2419 node->add_child_nocopy (_regions->get_state ());
2421 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2422 node->add_property ("nudge-clock-value", buf);
2429 /** @param y y offset from the top of all trackviews.
2430 * @return pair: TimeAxisView that y is over, layer index.
2431 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2432 * in stacked or expanded region display mode, otherwise 0.
2434 std::pair<TimeAxisView *, double>
2435 Editor::trackview_by_y_position (double y)
2437 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2439 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2445 return std::make_pair ( (TimeAxisView *) 0, 0);
2448 /** Snap a position to the grid, if appropriate, taking into account current
2449 * grid settings and also the state of any snap modifier keys that may be pressed.
2450 * @param start Position to snap.
2451 * @param event Event to get current key modifier information from, or 0.
2454 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2456 if (!_session || !event) {
2460 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2461 if (_snap_mode == SnapOff) {
2462 snap_to_internal (start, direction, for_mark);
2465 if (_snap_mode != SnapOff) {
2466 snap_to_internal (start, direction, for_mark);
2472 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2474 if (!_session || _snap_mode == SnapOff) {
2478 snap_to_internal (start, direction, for_mark);
2482 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2484 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2485 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2487 switch (_snap_type) {
2488 case SnapToTimecodeFrame:
2489 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2490 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2492 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2496 case SnapToTimecodeSeconds:
2497 if (_session->config.get_timecode_offset_negative()) {
2498 start += _session->config.get_timecode_offset ();
2500 start -= _session->config.get_timecode_offset ();
2502 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2503 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2505 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2508 if (_session->config.get_timecode_offset_negative()) {
2509 start -= _session->config.get_timecode_offset ();
2511 start += _session->config.get_timecode_offset ();
2515 case SnapToTimecodeMinutes:
2516 if (_session->config.get_timecode_offset_negative()) {
2517 start += _session->config.get_timecode_offset ();
2519 start -= _session->config.get_timecode_offset ();
2521 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2522 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2524 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2526 if (_session->config.get_timecode_offset_negative()) {
2527 start -= _session->config.get_timecode_offset ();
2529 start += _session->config.get_timecode_offset ();
2533 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2539 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2541 const framepos_t one_second = _session->frame_rate();
2542 const framepos_t one_minute = _session->frame_rate() * 60;
2543 framepos_t presnap = start;
2547 switch (_snap_type) {
2548 case SnapToTimecodeFrame:
2549 case SnapToTimecodeSeconds:
2550 case SnapToTimecodeMinutes:
2551 return timecode_snap_to_internal (start, direction, for_mark);
2554 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2555 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2557 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2562 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2563 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2565 start = (framepos_t) floor ((double) start / one_second) * one_second;
2570 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2571 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2573 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2578 start = _session->tempo_map().round_to_bar (start, direction);
2582 start = _session->tempo_map().round_to_beat (start, direction);
2585 case SnapToBeatDiv128:
2586 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2588 case SnapToBeatDiv64:
2589 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2591 case SnapToBeatDiv32:
2592 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2594 case SnapToBeatDiv28:
2595 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2597 case SnapToBeatDiv24:
2598 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2600 case SnapToBeatDiv20:
2601 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2603 case SnapToBeatDiv16:
2604 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2606 case SnapToBeatDiv14:
2607 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2609 case SnapToBeatDiv12:
2610 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2612 case SnapToBeatDiv10:
2613 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2615 case SnapToBeatDiv8:
2616 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2618 case SnapToBeatDiv7:
2619 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2621 case SnapToBeatDiv6:
2622 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2624 case SnapToBeatDiv5:
2625 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2627 case SnapToBeatDiv4:
2628 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2630 case SnapToBeatDiv3:
2631 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2633 case SnapToBeatDiv2:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2642 _session->locations()->marks_either_side (start, before, after);
2644 if (before == max_framepos) {
2646 } else if (after == max_framepos) {
2648 } else if (before != max_framepos && after != max_framepos) {
2649 /* have before and after */
2650 if ((start - before) < (after - start)) {
2659 case SnapToRegionStart:
2660 case SnapToRegionEnd:
2661 case SnapToRegionSync:
2662 case SnapToRegionBoundary:
2663 if (!region_boundary_cache.empty()) {
2665 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2666 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2668 if (direction > 0) {
2669 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2671 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2674 if (next != region_boundary_cache.begin ()) {
2679 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2680 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2682 if (start > (p + n) / 2) {
2691 switch (_snap_mode) {
2697 if (presnap > start) {
2698 if (presnap > (start + unit_to_frame(snap_threshold))) {
2702 } else if (presnap < start) {
2703 if (presnap < (start - unit_to_frame(snap_threshold))) {
2709 /* handled at entry */
2717 Editor::setup_toolbar ()
2719 HBox* mode_box = manage(new HBox);
2720 mode_box->set_border_width (2);
2721 mode_box->set_spacing(4);
2723 HBox* mouse_mode_box = manage (new HBox);
2724 HBox* mouse_mode_hbox1 = manage (new HBox);
2725 HBox* mouse_mode_hbox2 = manage (new HBox);
2726 VBox* mouse_mode_vbox1 = manage (new VBox);
2727 VBox* mouse_mode_vbox2 = manage (new VBox);
2728 Alignment* mouse_mode_align1 = manage (new Alignment);
2729 Alignment* mouse_mode_align2 = manage (new Alignment);
2731 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2732 mouse_mode_size_group->add_widget (mouse_move_button);
2733 mouse_mode_size_group->add_widget (mouse_select_button);
2734 mouse_mode_size_group->add_widget (mouse_zoom_button);
2735 mouse_mode_size_group->add_widget (mouse_gain_button);
2736 mouse_mode_size_group->add_widget (mouse_timefx_button);
2737 mouse_mode_size_group->add_widget (mouse_audition_button);
2738 mouse_mode_size_group->add_widget (mouse_draw_button);
2739 mouse_mode_size_group->add_widget (internal_edit_button);
2741 /* make them just a bit bigger */
2742 mouse_move_button.set_size_request (-1, 25);
2744 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2745 smart_mode_joiner->set_related_action (smart_mode_action);
2747 mouse_mode_hbox2->set_spacing (2);
2748 mouse_mode_box->set_spacing (2);
2750 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2751 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2752 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2753 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2754 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2755 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2756 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2758 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2759 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2761 mouse_mode_align1->add (*mouse_mode_vbox1);
2762 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2763 mouse_mode_align2->add (*mouse_mode_vbox2);
2764 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2766 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2767 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2769 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2770 if (!Profile->get_sae()) {
2771 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2773 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2775 edit_mode_selector.set_name ("EditModeSelector");
2776 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2777 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2779 mode_box->pack_start (edit_mode_selector, false, false);
2780 mode_box->pack_start (*mouse_mode_box, false, false);
2782 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2783 _mouse_mode_tearoff->set_name ("MouseModeBase");
2784 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2786 if (Profile->get_sae()) {
2787 _mouse_mode_tearoff->set_can_be_torn_off (false);
2790 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2791 &_mouse_mode_tearoff->tearoff_window()));
2792 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2793 &_mouse_mode_tearoff->tearoff_window(), 1));
2794 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2795 &_mouse_mode_tearoff->tearoff_window()));
2796 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2797 &_mouse_mode_tearoff->tearoff_window(), 1));
2801 _zoom_box.set_spacing (2);
2802 _zoom_box.set_border_width (2);
2806 zoom_in_button.set_name ("zoom button");
2807 zoom_in_button.set_image (::get_icon ("zoom_in"));
2808 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2809 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2810 zoom_in_button.set_related_action (act);
2812 zoom_out_button.set_name ("zoom button");
2813 zoom_out_button.set_image (::get_icon ("zoom_out"));
2814 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2815 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2816 zoom_out_button.set_related_action (act);
2818 zoom_out_full_button.set_name ("zoom button");
2819 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2820 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2821 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2822 zoom_out_full_button.set_related_action (act);
2824 zoom_focus_selector.set_name ("ZoomFocusSelector");
2825 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2826 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2828 _zoom_box.pack_start (zoom_out_button, false, false);
2829 _zoom_box.pack_start (zoom_in_button, false, false);
2830 _zoom_box.pack_start (zoom_out_full_button, false, false);
2832 _zoom_box.pack_start (zoom_focus_selector, false, false);
2834 /* Track zoom buttons */
2835 tav_expand_button.set_name ("TrackHeightButton");
2836 tav_expand_button.set_size_request (-1, 20);
2837 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2838 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2839 act->connect_proxy (tav_expand_button);
2841 tav_shrink_button.set_name ("TrackHeightButton");
2842 tav_shrink_button.set_size_request (-1, 20);
2843 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2844 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2845 act->connect_proxy (tav_shrink_button);
2847 _zoom_box.pack_start (tav_shrink_button);
2848 _zoom_box.pack_start (tav_expand_button);
2850 _zoom_tearoff = manage (new TearOff (_zoom_box));
2852 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2853 &_zoom_tearoff->tearoff_window()));
2854 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2855 &_zoom_tearoff->tearoff_window(), 0));
2856 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2857 &_zoom_tearoff->tearoff_window()));
2858 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2859 &_zoom_tearoff->tearoff_window(), 0));
2861 snap_box.set_spacing (1);
2862 snap_box.set_border_width (2);
2864 snap_type_selector.set_name ("SnapTypeSelector");
2865 set_popdown_strings (snap_type_selector, snap_type_strings);
2866 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2868 snap_mode_selector.set_name ("SnapModeSelector");
2869 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2870 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2872 edit_point_selector.set_name ("EditPointSelector");
2873 set_popdown_strings (edit_point_selector, edit_point_strings);
2874 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2876 snap_box.pack_start (snap_mode_selector, false, false);
2877 snap_box.pack_start (snap_type_selector, false, false);
2878 snap_box.pack_start (edit_point_selector, false, false);
2882 HBox *nudge_box = manage (new HBox);
2883 nudge_box->set_spacing (2);
2884 nudge_box->set_border_width (2);
2886 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2887 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2889 nudge_box->pack_start (nudge_backward_button, false, false);
2890 nudge_box->pack_start (nudge_forward_button, false, false);
2891 nudge_box->pack_start (*nudge_clock, false, false);
2894 /* Pack everything in... */
2896 HBox* hbox = manage (new HBox);
2897 hbox->set_spacing(10);
2899 _tools_tearoff = manage (new TearOff (*hbox));
2900 _tools_tearoff->set_name ("MouseModeBase");
2901 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2903 if (Profile->get_sae()) {
2904 _tools_tearoff->set_can_be_torn_off (false);
2907 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2908 &_tools_tearoff->tearoff_window()));
2909 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2910 &_tools_tearoff->tearoff_window(), 0));
2911 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2912 &_tools_tearoff->tearoff_window()));
2913 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2914 &_tools_tearoff->tearoff_window(), 0));
2916 toolbar_hbox.set_spacing (10);
2917 toolbar_hbox.set_border_width (1);
2919 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2920 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2921 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2923 hbox->pack_start (snap_box, false, false);
2924 if (!Profile->get_small_screen()) {
2925 hbox->pack_start (*nudge_box, false, false);
2927 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2929 hbox->pack_start (panic_box, false, false);
2933 toolbar_base.set_name ("ToolBarBase");
2934 toolbar_base.add (toolbar_hbox);
2936 _toolbar_viewport.add (toolbar_base);
2937 /* stick to the required height but allow width to vary if there's not enough room */
2938 _toolbar_viewport.set_size_request (1, -1);
2940 toolbar_frame.set_shadow_type (SHADOW_OUT);
2941 toolbar_frame.set_name ("BaseFrame");
2942 toolbar_frame.add (_toolbar_viewport);
2946 Editor::setup_tooltips ()
2948 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2949 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
2950 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
2951 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2952 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2953 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2954 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2955 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
2956 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2957 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2958 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2959 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2960 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2961 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2962 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2963 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2964 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2965 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2966 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2967 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2968 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2969 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2970 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
2974 Editor::convert_drop_to_paths (
2975 vector<string>& paths,
2976 const RefPtr<Gdk::DragContext>& /*context*/,
2979 const SelectionData& data,
2983 if (_session == 0) {
2987 vector<string> uris = data.get_uris();
2991 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
2992 are actually URI lists. So do it by hand.
2995 if (data.get_target() != "text/plain") {
2999 /* Parse the "uri-list" format that Nautilus provides,
3000 where each pathname is delimited by \r\n.
3002 THERE MAY BE NO NULL TERMINATING CHAR!!!
3005 string txt = data.get_text();
3009 p = (const char *) malloc (txt.length() + 1);
3010 txt.copy ((char *) p, txt.length(), 0);
3011 ((char*)p)[txt.length()] = '\0';
3017 while (g_ascii_isspace (*p))
3021 while (*q && (*q != '\n') && (*q != '\r')) {
3028 while (q > p && g_ascii_isspace (*q))
3033 uris.push_back (string (p, q - p + 1));
3037 p = strchr (p, '\n');
3049 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3051 if ((*i).substr (0,7) == "file://") {
3053 string const p = PBD::url_decode (*i);
3055 // scan forward past three slashes
3057 string::size_type slashcnt = 0;
3058 string::size_type n = 0;
3059 string::const_iterator x = p.begin();
3061 while (slashcnt < 3 && x != p.end()) {
3064 } else if (slashcnt == 3) {
3071 if (slashcnt != 3 || x == p.end()) {
3072 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3076 paths.push_back (p.substr (n - 1));
3084 Editor::new_tempo_section ()
3090 Editor::map_transport_state ()
3092 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3094 if (_session && _session->transport_stopped()) {
3095 have_pending_keyboard_selection = false;
3098 update_loop_range_view (true);
3104 Editor::begin_reversible_command (string name)
3107 _session->begin_reversible_command (name);
3112 Editor::begin_reversible_command (GQuark q)
3115 _session->begin_reversible_command (q);
3120 Editor::commit_reversible_command ()
3123 _session->commit_reversible_command ();
3128 Editor::history_changed ()
3132 if (undo_action && _session) {
3133 if (_session->undo_depth() == 0) {
3134 label = S_("Command|Undo");
3136 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3138 undo_action->property_label() = label;
3141 if (redo_action && _session) {
3142 if (_session->redo_depth() == 0) {
3145 label = string_compose(_("Redo (%1)"), _session->next_redo());
3147 redo_action->property_label() = label;
3152 Editor::duplicate_dialog (bool with_dialog)
3156 if (mouse_mode == MouseRange) {
3157 if (selection->time.length() == 0) {
3162 RegionSelection rs = get_regions_from_selection_and_entered ();
3164 if (mouse_mode != MouseRange && rs.empty()) {
3170 ArdourDialog win (_("Duplicate"));
3171 Label label (_("Number of duplications:"));
3172 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3173 SpinButton spinner (adjustment, 0.0, 1);
3176 win.get_vbox()->set_spacing (12);
3177 win.get_vbox()->pack_start (hbox);
3178 hbox.set_border_width (6);
3179 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3181 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3182 place, visually. so do this by hand.
3185 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3186 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3187 spinner.grab_focus();
3193 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3194 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3195 win.set_default_response (RESPONSE_ACCEPT);
3197 win.set_position (WIN_POS_MOUSE);
3199 spinner.grab_focus ();
3201 switch (win.run ()) {
3202 case RESPONSE_ACCEPT:
3208 times = adjustment.get_value();
3211 if (mouse_mode == MouseRange) {
3212 duplicate_selection (times);
3214 duplicate_some_regions (rs, times);
3219 Editor::set_edit_mode (EditMode m)
3221 Config->set_edit_mode (m);
3225 Editor::cycle_edit_mode ()
3227 switch (Config->get_edit_mode()) {
3229 if (Profile->get_sae()) {
3230 Config->set_edit_mode (Lock);
3232 Config->set_edit_mode (Splice);
3236 Config->set_edit_mode (Lock);
3239 Config->set_edit_mode (Slide);
3245 Editor::edit_mode_selection_done ()
3247 string s = edit_mode_selector.get_active_text ();
3250 Config->set_edit_mode (string_to_edit_mode (s));
3255 Editor::snap_type_selection_done ()
3257 string choice = snap_type_selector.get_active_text();
3258 SnapType snaptype = SnapToBeat;
3260 if (choice == _("Beats/2")) {
3261 snaptype = SnapToBeatDiv2;
3262 } else if (choice == _("Beats/3")) {
3263 snaptype = SnapToBeatDiv3;
3264 } else if (choice == _("Beats/4")) {
3265 snaptype = SnapToBeatDiv4;
3266 } else if (choice == _("Beats/5")) {
3267 snaptype = SnapToBeatDiv5;
3268 } else if (choice == _("Beats/6")) {
3269 snaptype = SnapToBeatDiv6;
3270 } else if (choice == _("Beats/7")) {
3271 snaptype = SnapToBeatDiv7;
3272 } else if (choice == _("Beats/8")) {
3273 snaptype = SnapToBeatDiv8;
3274 } else if (choice == _("Beats/10")) {
3275 snaptype = SnapToBeatDiv10;
3276 } else if (choice == _("Beats/12")) {
3277 snaptype = SnapToBeatDiv12;
3278 } else if (choice == _("Beats/14")) {
3279 snaptype = SnapToBeatDiv14;
3280 } else if (choice == _("Beats/16")) {
3281 snaptype = SnapToBeatDiv16;
3282 } else if (choice == _("Beats/20")) {
3283 snaptype = SnapToBeatDiv20;
3284 } else if (choice == _("Beats/24")) {
3285 snaptype = SnapToBeatDiv24;
3286 } else if (choice == _("Beats/28")) {
3287 snaptype = SnapToBeatDiv28;
3288 } else if (choice == _("Beats/32")) {
3289 snaptype = SnapToBeatDiv32;
3290 } else if (choice == _("Beats/64")) {
3291 snaptype = SnapToBeatDiv64;
3292 } else if (choice == _("Beats/128")) {
3293 snaptype = SnapToBeatDiv128;
3294 } else if (choice == _("Beats")) {
3295 snaptype = SnapToBeat;
3296 } else if (choice == _("Bars")) {
3297 snaptype = SnapToBar;
3298 } else if (choice == _("Marks")) {
3299 snaptype = SnapToMark;
3300 } else if (choice == _("Region starts")) {
3301 snaptype = SnapToRegionStart;
3302 } else if (choice == _("Region ends")) {
3303 snaptype = SnapToRegionEnd;
3304 } else if (choice == _("Region bounds")) {
3305 snaptype = SnapToRegionBoundary;
3306 } else if (choice == _("Region syncs")) {
3307 snaptype = SnapToRegionSync;
3308 } else if (choice == _("CD Frames")) {
3309 snaptype = SnapToCDFrame;
3310 } else if (choice == _("Timecode Frames")) {
3311 snaptype = SnapToTimecodeFrame;
3312 } else if (choice == _("Timecode Seconds")) {
3313 snaptype = SnapToTimecodeSeconds;
3314 } else if (choice == _("Timecode Minutes")) {
3315 snaptype = SnapToTimecodeMinutes;
3316 } else if (choice == _("Seconds")) {
3317 snaptype = SnapToSeconds;
3318 } else if (choice == _("Minutes")) {
3319 snaptype = SnapToMinutes;
3322 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3324 ract->set_active ();
3329 Editor::snap_mode_selection_done ()
3331 string choice = snap_mode_selector.get_active_text();
3332 SnapMode mode = SnapNormal;
3334 if (choice == _("No Grid")) {
3336 } else if (choice == _("Grid")) {
3338 } else if (choice == _("Magnetic")) {
3339 mode = SnapMagnetic;
3342 RefPtr<RadioAction> ract = snap_mode_action (mode);
3345 ract->set_active (true);
3350 Editor::cycle_edit_point (bool with_marker)
3352 switch (_edit_point) {
3354 set_edit_point_preference (EditAtPlayhead);
3356 case EditAtPlayhead:
3358 set_edit_point_preference (EditAtSelectedMarker);
3360 set_edit_point_preference (EditAtMouse);
3363 case EditAtSelectedMarker:
3364 set_edit_point_preference (EditAtMouse);
3370 Editor::edit_point_selection_done ()
3372 string choice = edit_point_selector.get_active_text();
3373 EditPoint ep = EditAtSelectedMarker;
3375 if (choice == _("Marker")) {
3376 set_edit_point_preference (EditAtSelectedMarker);
3377 } else if (choice == _("Playhead")) {
3378 set_edit_point_preference (EditAtPlayhead);
3380 set_edit_point_preference (EditAtMouse);
3383 RefPtr<RadioAction> ract = edit_point_action (ep);
3386 ract->set_active (true);
3391 Editor::zoom_focus_selection_done ()
3393 string choice = zoom_focus_selector.get_active_text();
3394 ZoomFocus focus_type = ZoomFocusLeft;
3396 if (choice == _("Left")) {
3397 focus_type = ZoomFocusLeft;
3398 } else if (choice == _("Right")) {
3399 focus_type = ZoomFocusRight;
3400 } else if (choice == _("Center")) {
3401 focus_type = ZoomFocusCenter;
3402 } else if (choice == _("Playhead")) {
3403 focus_type = ZoomFocusPlayhead;
3404 } else if (choice == _("Mouse")) {
3405 focus_type = ZoomFocusMouse;
3406 } else if (choice == _("Edit point")) {
3407 focus_type = ZoomFocusEdit;
3410 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3413 ract->set_active ();
3418 Editor::edit_controls_button_release (GdkEventButton* ev)
3420 if (Keyboard::is_context_menu_event (ev)) {
3421 ARDOUR_UI::instance()->add_route (this);
3422 } else if (ev->button == 1) {
3423 selection->clear_tracks ();
3430 Editor::mouse_select_button_release (GdkEventButton* ev)
3432 /* this handles just right-clicks */
3434 if (ev->button != 3) {
3442 Editor::set_zoom_focus (ZoomFocus f)
3444 string str = zoom_focus_strings[(int)f];
3446 if (str != zoom_focus_selector.get_active_text()) {
3447 zoom_focus_selector.set_active_text (str);
3450 if (zoom_focus != f) {
3457 Editor::ensure_float (Window& win)
3459 win.set_transient_for (*this);
3463 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3465 /* recover or initialize pane positions. do this here rather than earlier because
3466 we don't want the positions to change the child allocations, which they seem to do.
3472 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3481 XMLNode* geometry = find_named_node (*node, "geometry");
3483 if (which == static_cast<Paned*> (&edit_pane)) {
3485 if (done & Horizontal) {
3489 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3490 _notebook_shrunk = string_is_affirmative (prop->value ());
3493 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3494 /* initial allocation is 90% to canvas, 10% to notebook */
3495 pos = (int) floor (alloc.get_width() * 0.90f);
3496 snprintf (buf, sizeof(buf), "%d", pos);
3498 pos = atoi (prop->value());
3501 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3502 edit_pane.set_position (pos);
3505 done = (Pane) (done | Horizontal);
3507 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3509 if (done & Vertical) {
3513 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3514 /* initial allocation is 90% to canvas, 10% to summary */
3515 pos = (int) floor (alloc.get_height() * 0.90f);
3516 snprintf (buf, sizeof(buf), "%d", pos);
3519 pos = atoi (prop->value());
3522 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3523 editor_summary_pane.set_position (pos);
3526 done = (Pane) (done | Vertical);
3531 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3533 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3534 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3535 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3536 top_hbox.remove (toolbar_frame);
3541 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3543 if (toolbar_frame.get_parent() == 0) {
3544 top_hbox.pack_end (toolbar_frame);
3549 Editor::set_show_measures (bool yn)
3551 if (_show_measures != yn) {
3554 if ((_show_measures = yn) == true) {
3556 tempo_lines->show();
3564 Editor::toggle_follow_playhead ()
3566 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3568 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3569 set_follow_playhead (tact->get_active());
3573 /** @param yn true to follow playhead, otherwise false.
3574 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3577 Editor::set_follow_playhead (bool yn, bool catch_up)
3579 if (_follow_playhead != yn) {
3580 if ((_follow_playhead = yn) == true && catch_up) {
3582 reset_x_origin_to_follow_playhead ();
3589 Editor::toggle_stationary_playhead ()
3591 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3593 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3594 set_stationary_playhead (tact->get_active());
3599 Editor::set_stationary_playhead (bool yn)
3601 if (_stationary_playhead != yn) {
3602 if ((_stationary_playhead = yn) == true) {
3604 // FIXME need a 3.0 equivalent of this 2.X call
3605 // update_current_screen ();
3612 Editor::playlist_selector () const
3614 return *_playlist_selector;
3618 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3622 switch (_snap_type) {
3627 case SnapToBeatDiv128:
3630 case SnapToBeatDiv64:
3633 case SnapToBeatDiv32:
3636 case SnapToBeatDiv28:
3639 case SnapToBeatDiv24:
3642 case SnapToBeatDiv20:
3645 case SnapToBeatDiv16:
3648 case SnapToBeatDiv14:
3651 case SnapToBeatDiv12:
3654 case SnapToBeatDiv10:
3657 case SnapToBeatDiv8:
3660 case SnapToBeatDiv7:
3663 case SnapToBeatDiv6:
3666 case SnapToBeatDiv5:
3669 case SnapToBeatDiv4:
3672 case SnapToBeatDiv3:
3675 case SnapToBeatDiv2:
3681 return _session->tempo_map().meter_at (position).divisions_per_bar();
3686 case SnapToTimecodeFrame:
3687 case SnapToTimecodeSeconds:
3688 case SnapToTimecodeMinutes:
3691 case SnapToRegionStart:
3692 case SnapToRegionEnd:
3693 case SnapToRegionSync:
3694 case SnapToRegionBoundary:
3704 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3708 ret = nudge_clock->current_duration (pos);
3709 next = ret + 1; /* XXXX fix me */
3715 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3717 ArdourDialog dialog (_("Playlist Deletion"));
3718 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3719 "If it is kept, its audio files will not be cleaned.\n"
3720 "If it is deleted, audio files used by it alone will be cleaned."),
3723 dialog.set_position (WIN_POS_CENTER);
3724 dialog.get_vbox()->pack_start (label);
3728 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3729 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3730 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3732 switch (dialog.run ()) {
3733 case RESPONSE_ACCEPT:
3734 /* delete the playlist */
3738 case RESPONSE_REJECT:
3739 /* keep the playlist */
3751 Editor::audio_region_selection_covers (framepos_t where)
3753 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3754 if ((*a)->region()->covers (where)) {
3763 Editor::prepare_for_cleanup ()
3765 cut_buffer->clear_regions ();
3766 cut_buffer->clear_playlists ();
3768 selection->clear_regions ();
3769 selection->clear_playlists ();
3771 _regions->suspend_redisplay ();
3775 Editor::finish_cleanup ()
3777 _regions->resume_redisplay ();
3781 Editor::transport_loop_location()
3784 return _session->locations()->auto_loop_location();
3791 Editor::transport_punch_location()
3794 return _session->locations()->auto_punch_location();
3801 Editor::control_layout_scroll (GdkEventScroll* ev)
3803 if (Keyboard::some_magic_widget_has_focus()) {
3807 switch (ev->direction) {
3809 scroll_tracks_up_line ();
3813 case GDK_SCROLL_DOWN:
3814 scroll_tracks_down_line ();
3818 /* no left/right handling yet */
3826 Editor::session_state_saved (string)
3829 _snapshots->redisplay ();
3833 Editor::maximise_editing_space ()
3841 if (!Config->get_keep_tearoffs()) {
3842 /* these calls will leave each tearoff visible *if* it is torn off,
3843 but invisible otherwise.
3845 _mouse_mode_tearoff->set_visible (false);
3846 _tools_tearoff->set_visible (false);
3847 _zoom_tearoff->set_visible (false);
3854 Editor::restore_editing_space ()
3862 if (!Config->get_keep_tearoffs()) {
3863 _mouse_mode_tearoff->set_visible (true);
3864 _tools_tearoff->set_visible (true);
3865 _zoom_tearoff->set_visible (true);
3872 * Make new playlists for a given track and also any others that belong
3873 * to the same active route group with the `edit' property.
3878 Editor::new_playlists (TimeAxisView* v)
3880 begin_reversible_command (_("new playlists"));
3881 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3882 _session->playlists->get (playlists);
3883 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3884 commit_reversible_command ();
3888 * Use a copy of the current playlist for a given track and also any others that belong
3889 * to the same active route group with the `edit' property.
3894 Editor::copy_playlists (TimeAxisView* v)
3896 begin_reversible_command (_("copy playlists"));
3897 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3898 _session->playlists->get (playlists);
3899 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3900 commit_reversible_command ();
3903 /** Clear the current playlist for a given track and also any others that belong
3904 * to the same active route group with the `edit' property.
3909 Editor::clear_playlists (TimeAxisView* v)
3911 begin_reversible_command (_("clear playlists"));
3912 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3913 _session->playlists->get (playlists);
3914 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
3915 commit_reversible_command ();
3919 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3921 atv.use_new_playlist (sz > 1 ? false : true, playlists);
3925 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
3927 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
3931 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
3933 atv.clear_playlist ();
3937 Editor::on_key_press_event (GdkEventKey* ev)
3939 return key_press_focus_accelerator_handler (*this, ev);
3943 Editor::on_key_release_event (GdkEventKey* ev)
3945 return Gtk::Window::on_key_release_event (ev);
3946 // return key_press_focus_accelerator_handler (*this, ev);
3949 /** Queue up a change to the viewport x origin.
3950 * @param frame New x origin.
3953 Editor::reset_x_origin (framepos_t frame)
3955 queue_visual_change (frame);
3959 Editor::reset_y_origin (double y)
3961 queue_visual_change_y (y);
3965 Editor::reset_zoom (double fpu)
3967 queue_visual_change (fpu);
3971 Editor::reposition_and_zoom (framepos_t frame, double fpu)
3973 reset_x_origin (frame);
3976 if (!no_save_visual) {
3977 undo_visual_stack.push_back (current_visual_state(false));
3981 Editor::VisualState::VisualState (bool with_tracks)
3982 : gui_state (with_tracks ? new GUIObjectState : 0)
3986 Editor::VisualState::~VisualState ()
3991 Editor::VisualState*
3992 Editor::current_visual_state (bool with_tracks)
3994 VisualState* vs = new VisualState (with_tracks);
3995 vs->y_position = vertical_adjustment.get_value();
3996 vs->frames_per_unit = frames_per_unit;
3997 vs->leftmost_frame = leftmost_frame;
3998 vs->zoom_focus = zoom_focus;
4001 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4008 Editor::undo_visual_state ()
4010 if (undo_visual_stack.empty()) {
4014 VisualState* vs = undo_visual_stack.back();
4015 undo_visual_stack.pop_back();
4018 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4020 use_visual_state (*vs);
4024 Editor::redo_visual_state ()
4026 if (redo_visual_stack.empty()) {
4030 VisualState* vs = redo_visual_stack.back();
4031 redo_visual_stack.pop_back();
4033 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4035 use_visual_state (*vs);
4039 Editor::swap_visual_state ()
4041 if (undo_visual_stack.empty()) {
4042 redo_visual_state ();
4044 undo_visual_state ();
4049 Editor::use_visual_state (VisualState& vs)
4051 PBD::Unwinder<bool> nsv (no_save_visual, true);
4053 _routes->suspend_redisplay ();
4055 vertical_adjustment.set_value (vs.y_position);
4057 set_zoom_focus (vs.zoom_focus);
4058 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4061 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4063 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4064 (*i)->reset_visual_state ();
4068 _routes->update_visibility ();
4069 _routes->resume_redisplay ();
4073 Editor::set_frames_per_unit (double fpu)
4075 /* this is the core function that controls the zoom level of the canvas. it is called
4076 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4079 if (fpu == frames_per_unit) {
4088 /* don't allow zooms that fit more than the maximum number
4089 of frames into an 800 pixel wide space.
4092 if (max_framepos / fpu < 800.0) {
4097 tempo_lines->tempo_map_changed();
4099 frames_per_unit = fpu;
4104 Editor::post_zoom ()
4106 // convert fpu to frame count
4108 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4110 if (frames_per_unit != zoom_range_clock->current_duration()) {
4111 zoom_range_clock->set (frames);
4114 bool const showing_time_selection =
4115 mouse_mode == MouseRange ||
4116 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4118 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4119 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4120 (*i)->reshow_selection (selection->time);
4124 ZoomChanged (); /* EMIT_SIGNAL */
4126 //reset_scrolling_region ();
4128 if (playhead_cursor) {
4129 playhead_cursor->set_position (playhead_cursor->current_frame);
4132 refresh_location_display();
4133 _summary->set_overlays_dirty ();
4135 update_marker_labels ();
4141 Editor::queue_visual_change (framepos_t where)
4143 pending_visual_change.add (VisualChange::TimeOrigin);
4144 pending_visual_change.time_origin = where;
4145 ensure_visual_change_idle_handler ();
4149 Editor::queue_visual_change (double fpu)
4151 pending_visual_change.add (VisualChange::ZoomLevel);
4152 pending_visual_change.frames_per_unit = fpu;
4154 ensure_visual_change_idle_handler ();
4158 Editor::queue_visual_change_y (double y)
4160 pending_visual_change.add (VisualChange::YOrigin);
4161 pending_visual_change.y_origin = y;
4163 ensure_visual_change_idle_handler ();
4167 Editor::ensure_visual_change_idle_handler ()
4169 if (pending_visual_change.idle_handler_id < 0) {
4170 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4175 Editor::_idle_visual_changer (void* arg)
4177 return static_cast<Editor*>(arg)->idle_visual_changer ();
4181 Editor::idle_visual_changer ()
4183 VisualChange::Type p = pending_visual_change.pending;
4184 pending_visual_change.pending = (VisualChange::Type) 0;
4186 double const last_time_origin = horizontal_position ();
4188 if (p & VisualChange::ZoomLevel) {
4189 set_frames_per_unit (pending_visual_change.frames_per_unit);
4191 compute_fixed_ruler_scale ();
4192 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4193 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4194 update_tempo_based_rulers ();
4196 if (p & VisualChange::TimeOrigin) {
4197 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4199 if (p & VisualChange::YOrigin) {
4200 vertical_adjustment.set_value (pending_visual_change.y_origin);
4203 if (last_time_origin == horizontal_position ()) {
4204 /* changed signal not emitted */
4205 update_fixed_rulers ();
4206 redisplay_tempo (true);
4209 _summary->set_overlays_dirty ();
4211 pending_visual_change.idle_handler_id = -1;
4212 return 0; /* this is always a one-shot call */
4215 struct EditorOrderTimeAxisSorter {
4216 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4217 return a->order () < b->order ();
4222 Editor::sort_track_selection (TrackViewList& sel)
4224 EditorOrderTimeAxisSorter cmp;
4229 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4232 framepos_t where = 0;
4233 EditPoint ep = _edit_point;
4235 if (from_context_menu && (ep == EditAtMouse)) {
4236 return event_frame (&context_click_event, 0, 0);
4239 if (entered_marker) {
4240 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4241 return entered_marker->position();
4244 if (ignore_playhead && ep == EditAtPlayhead) {
4245 ep = EditAtSelectedMarker;
4249 case EditAtPlayhead:
4250 where = _session->audible_frame();
4251 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4254 case EditAtSelectedMarker:
4255 if (!selection->markers.empty()) {
4257 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4260 where = loc->start();
4264 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4272 if (!mouse_frame (where, ignored)) {
4273 /* XXX not right but what can we do ? */
4277 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4285 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4287 if (!_session) return;
4289 begin_reversible_command (cmd);
4293 if ((tll = transport_loop_location()) == 0) {
4294 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4295 XMLNode &before = _session->locations()->get_state();
4296 _session->locations()->add (loc, true);
4297 _session->set_auto_loop_location (loc);
4298 XMLNode &after = _session->locations()->get_state();
4299 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4301 XMLNode &before = tll->get_state();
4302 tll->set_hidden (false, this);
4303 tll->set (start, end);
4304 XMLNode &after = tll->get_state();
4305 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4308 commit_reversible_command ();
4312 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4314 if (!_session) return;
4316 begin_reversible_command (cmd);
4320 if ((tpl = transport_punch_location()) == 0) {
4321 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4322 XMLNode &before = _session->locations()->get_state();
4323 _session->locations()->add (loc, true);
4324 _session->set_auto_loop_location (loc);
4325 XMLNode &after = _session->locations()->get_state();
4326 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4329 XMLNode &before = tpl->get_state();
4330 tpl->set_hidden (false, this);
4331 tpl->set (start, end);
4332 XMLNode &after = tpl->get_state();
4333 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4336 commit_reversible_command ();
4339 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4340 * @param rs List to which found regions are added.
4341 * @param where Time to look at.
4342 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4345 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4347 const TrackViewList* tracks;
4350 tracks = &track_views;
4355 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4357 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4360 boost::shared_ptr<Track> tr;
4361 boost::shared_ptr<Playlist> pl;
4363 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4365 boost::shared_ptr<RegionList> regions = pl->regions_at (
4366 (framepos_t) floor ( (double) where * tr->speed()));
4368 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4369 RegionView* rv = rtv->view()->find_view (*i);
4380 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4382 const TrackViewList* tracks;
4385 tracks = &track_views;
4390 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4391 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4393 boost::shared_ptr<Track> tr;
4394 boost::shared_ptr<Playlist> pl;
4396 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4398 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4399 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4401 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4403 RegionView* rv = rtv->view()->find_view (*i);
4414 /** Start with regions that are selected. Then add equivalent regions
4415 * on tracks in the same active edit-enabled route group as any of
4416 * the regions that we started with.
4420 Editor::get_regions_from_selection ()
4422 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4425 /** Get regions using the following method:
4427 * Make an initial region list using the selected regions, unless
4428 * the edit point is `mouse' and the mouse is over an unselected
4429 * region. In this case, start with just that region.
4431 * Then, make an initial track list of the tracks that these
4432 * regions are on, and if the edit point is not `mouse', add the
4435 * Look at this track list and add any other tracks that are on the
4436 * same active edit-enabled route group as one of the initial tracks.
4438 * Finally take the initial region list and add any regions that are
4439 * under the edit point on one of the tracks on the track list to get
4440 * the returned region list.
4442 * The rationale here is that the mouse edit point is special in that
4443 * its position describes both a time and a track; the other edit
4444 * modes only describe a time. Hence if the edit point is `mouse' we
4445 * ignore selected tracks, as we assume the user means something by
4446 * pointing at a particular track. Also in this case we take note of
4447 * the region directly under the edit point, as there is always just one
4448 * (rather than possibly several with non-mouse edit points).
4452 Editor::get_regions_from_selection_and_edit_point ()
4454 RegionSelection regions;
4456 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4457 regions.add (entered_regionview);
4459 regions = selection->regions;
4462 TrackViewList tracks;
4464 if (_edit_point != EditAtMouse) {
4465 tracks = selection->tracks;
4468 /* Add any other tracks that have regions that are in the same
4469 edit-activated route group as one of our regions.
4471 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4473 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4475 if (g && g->is_active() && g->is_edit()) {
4476 tracks.add (axis_views_from_routes (g->route_list()));
4480 if (!tracks.empty()) {
4481 /* now find regions that are at the edit position on those tracks */
4482 framepos_t const where = get_preferred_edit_position ();
4483 get_regions_at (regions, where, tracks);
4489 /** Start with regions that are selected, or the entered regionview if none are selected.
4490 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4491 * of the regions that we started with.
4495 Editor::get_regions_from_selection_and_entered ()
4497 RegionSelection regions = selection->regions;
4499 if (regions.empty() && entered_regionview) {
4500 regions.add (entered_regionview);
4503 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4507 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4509 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4511 RouteTimeAxisView* tatv;
4513 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4515 boost::shared_ptr<Playlist> pl;
4516 vector<boost::shared_ptr<Region> > results;
4518 boost::shared_ptr<Track> tr;
4520 if ((tr = tatv->track()) == 0) {
4525 if ((pl = (tr->playlist())) != 0) {
4526 pl->get_region_list_equivalent_regions (region, results);
4529 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4530 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4531 regions.push_back (marv);
4540 Editor::show_rhythm_ferret ()
4542 if (rhythm_ferret == 0) {
4543 rhythm_ferret = new RhythmFerret(*this);
4546 rhythm_ferret->set_session (_session);
4547 rhythm_ferret->show ();
4548 rhythm_ferret->present ();
4552 Editor::first_idle ()
4554 MessageDialog* dialog = 0;
4556 if (track_views.size() > 1) {
4557 dialog = new MessageDialog (
4559 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4563 ARDOUR_UI::instance()->flush_pending ();
4566 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4570 // first idle adds route children (automation tracks), so we need to redisplay here
4571 _routes->redisplay ();
4578 Editor::_idle_resize (gpointer arg)
4580 return ((Editor*)arg)->idle_resize ();
4584 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4586 if (resize_idle_id < 0) {
4587 resize_idle_id = g_idle_add (_idle_resize, this);
4588 _pending_resize_amount = 0;
4591 /* make a note of the smallest resulting height, so that we can clamp the
4592 lower limit at TimeAxisView::hSmall */
4594 int32_t min_resulting = INT32_MAX;
4596 _pending_resize_amount += h;
4597 _pending_resize_view = view;
4599 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4601 if (selection->tracks.contains (_pending_resize_view)) {
4602 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4603 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4607 if (min_resulting < 0) {
4612 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4613 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4617 /** Handle pending resizing of tracks */
4619 Editor::idle_resize ()
4621 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4623 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4624 selection->tracks.contains (_pending_resize_view)) {
4626 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4627 if (*i != _pending_resize_view) {
4628 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4633 _pending_resize_amount = 0;
4635 _group_tabs->set_dirty ();
4636 resize_idle_id = -1;
4644 ENSURE_GUI_THREAD (*this, &Editor::located);
4646 playhead_cursor->set_position (_session->audible_frame ());
4647 if (_follow_playhead && !_pending_initial_locate) {
4648 reset_x_origin_to_follow_playhead ();
4651 _pending_locate_request = false;
4652 _pending_initial_locate = false;
4656 Editor::region_view_added (RegionView *)
4658 _summary->set_dirty ();
4662 Editor::region_view_removed ()
4664 _summary->set_dirty ();
4668 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4670 TrackViewList::const_iterator j = track_views.begin ();
4671 while (j != track_views.end()) {
4672 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4673 if (rtv && rtv->route() == r) {
4684 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4688 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4689 TimeAxisView* tv = axis_view_from_route (*i);
4700 Editor::handle_new_route (RouteList& routes)
4702 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4704 RouteTimeAxisView *rtv;
4705 list<RouteTimeAxisView*> new_views;
4707 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4708 boost::shared_ptr<Route> route = (*x);
4710 if (route->is_hidden() || route->is_monitor()) {
4714 DataType dt = route->input()->default_type();
4716 if (dt == ARDOUR::DataType::AUDIO) {
4717 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4718 rtv->set_route (route);
4719 } else if (dt == ARDOUR::DataType::MIDI) {
4720 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4721 rtv->set_route (route);
4723 throw unknown_type();
4726 new_views.push_back (rtv);
4727 track_views.push_back (rtv);
4729 rtv->effective_gain_display ();
4731 if (internal_editing()) {
4732 rtv->enter_internal_edit_mode ();
4734 rtv->leave_internal_edit_mode ();
4737 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4738 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4741 _routes->routes_added (new_views);
4742 _summary->routes_added (new_views);
4744 if (show_editor_mixer_when_tracks_arrive) {
4745 show_editor_mixer (true);
4748 editor_list_button.set_sensitive (true);
4752 Editor::timeaxisview_deleted (TimeAxisView *tv)
4754 if (_session && _session->deletion_in_progress()) {
4755 /* the situation is under control */
4759 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4761 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4763 _routes->route_removed (tv);
4765 if (tv == entered_track) {
4769 TimeAxisView::Children c = tv->get_child_list ();
4770 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4771 if (entered_track == i->get()) {
4776 /* remove it from the list of track views */
4778 TrackViewList::iterator i;
4780 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4781 i = track_views.erase (i);
4784 /* update whatever the current mixer strip is displaying, if revelant */
4786 boost::shared_ptr<Route> route;
4789 route = rtav->route ();
4792 if (current_mixer_strip && current_mixer_strip->route() == route) {
4794 TimeAxisView* next_tv;
4796 if (track_views.empty()) {
4798 } else if (i == track_views.end()) {
4799 next_tv = track_views.front();
4806 set_selected_mixer_strip (*next_tv);
4808 /* make the editor mixer strip go away setting the
4809 * button to inactive (which also unticks the menu option)
4812 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4818 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4820 if (apply_to_selection) {
4821 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4823 TrackSelection::iterator j = i;
4826 hide_track_in_display (*i, false);
4831 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4833 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4834 // this will hide the mixer strip
4835 set_selected_mixer_strip (*tv);
4838 _routes->hide_track_in_display (*tv);
4843 Editor::sync_track_view_list_and_routes ()
4845 track_views = TrackViewList (_routes->views ());
4847 _summary->set_dirty ();
4848 _group_tabs->set_dirty ();
4850 return false; // do not call again (until needed)
4854 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4856 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4861 /** Find a RouteTimeAxisView by the ID of its route */
4863 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4865 RouteTimeAxisView* v;
4867 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4868 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4869 if(v->route()->id() == id) {
4879 Editor::fit_route_group (RouteGroup *g)
4881 TrackViewList ts = axis_views_from_routes (g->route_list ());
4886 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4888 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4891 _session->cancel_audition ();
4895 if (_session->is_auditioning()) {
4896 _session->cancel_audition ();
4897 if (r == last_audition_region) {
4902 _session->audition_region (r);
4903 last_audition_region = r;
4908 Editor::hide_a_region (boost::shared_ptr<Region> r)
4910 r->set_hidden (true);
4914 Editor::show_a_region (boost::shared_ptr<Region> r)
4916 r->set_hidden (false);
4920 Editor::audition_region_from_region_list ()
4922 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
4926 Editor::hide_region_from_region_list ()
4928 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
4932 Editor::show_region_in_region_list ()
4934 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
4938 Editor::step_edit_status_change (bool yn)
4941 start_step_editing ();
4943 stop_step_editing ();
4948 Editor::start_step_editing ()
4950 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
4954 Editor::stop_step_editing ()
4956 step_edit_connection.disconnect ();
4960 Editor::check_step_edit ()
4962 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4963 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
4965 mtv->check_step_edit ();
4969 return true; // do it again, till we stop
4973 Editor::scroll_press (Direction dir)
4975 ++_scroll_callbacks;
4977 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
4978 /* delay the first auto-repeat */
4984 scroll_backward (1);
4992 scroll_tracks_up_line ();
4996 scroll_tracks_down_line ();
5000 /* do hacky auto-repeat */
5001 if (!_scroll_connection.connected ()) {
5003 _scroll_connection = Glib::signal_timeout().connect (
5004 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5007 _scroll_callbacks = 0;
5014 Editor::scroll_release ()
5016 _scroll_connection.disconnect ();
5019 /** Queue a change for the Editor viewport x origin to follow the playhead */
5021 Editor::reset_x_origin_to_follow_playhead ()
5023 framepos_t const frame = playhead_cursor->current_frame;
5025 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5027 if (_session->transport_speed() < 0) {
5029 if (frame > (current_page_frames() / 2)) {
5030 center_screen (frame-(current_page_frames()/2));
5032 center_screen (current_page_frames()/2);
5039 if (frame < leftmost_frame) {
5041 if (_session->transport_rolling()) {
5042 /* rolling; end up with the playhead at the right of the page */
5043 l = frame - current_page_frames ();
5045 /* not rolling: end up with the playhead 1/4 of the way along the page */
5046 l = frame - current_page_frames() / 4;
5050 if (_session->transport_rolling()) {
5051 /* rolling: end up with the playhead on the left of the page */
5054 /* not rolling: end up with the playhead 3/4 of the way along the page */
5055 l = frame - 3 * current_page_frames() / 4;
5063 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5069 Editor::super_rapid_screen_update ()
5071 if (!_session || !_session->engine().running()) {
5075 /* METERING / MIXER STRIPS */
5077 /* update track meters, if required */
5078 if (is_mapped() && meters_running) {
5079 RouteTimeAxisView* rtv;
5080 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5081 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5082 rtv->fast_update ();
5087 /* and any current mixer strip */
5088 if (current_mixer_strip) {
5089 current_mixer_strip->fast_update ();
5092 /* PLAYHEAD AND VIEWPORT */
5094 framepos_t const frame = _session->audible_frame();
5096 /* There are a few reasons why we might not update the playhead / viewport stuff:
5098 * 1. we don't update things when there's a pending locate request, otherwise
5099 * when the editor requests a locate there is a chance that this method
5100 * will move the playhead before the locate request is processed, causing
5102 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5103 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5106 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5108 last_update_frame = frame;
5110 if (!_dragging_playhead) {
5111 playhead_cursor->set_position (frame);
5114 if (!_stationary_playhead) {
5116 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5117 reset_x_origin_to_follow_playhead ();
5122 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5126 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5127 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5128 if (target <= 0.0) {
5131 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5132 target = (target * 0.15) + (current * 0.85);
5138 set_horizontal_position (current);
5147 Editor::session_going_away ()
5149 _have_idled = false;
5151 _session_connections.drop_connections ();
5153 super_rapid_screen_update_connection.disconnect ();
5155 selection->clear ();
5156 cut_buffer->clear ();
5158 clicked_regionview = 0;
5159 clicked_axisview = 0;
5160 clicked_routeview = 0;
5161 entered_regionview = 0;
5163 last_update_frame = 0;
5166 playhead_cursor->canvas_item.hide ();
5168 /* rip everything out of the list displays */
5172 _route_groups->clear ();
5174 /* do this first so that deleting a track doesn't reset cms to null
5175 and thus cause a leak.
5178 if (current_mixer_strip) {
5179 if (current_mixer_strip->get_parent() != 0) {
5180 global_hpacker.remove (*current_mixer_strip);
5182 delete current_mixer_strip;
5183 current_mixer_strip = 0;
5186 /* delete all trackviews */
5188 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5191 track_views.clear ();
5193 zoom_range_clock->set_session (0);
5194 nudge_clock->set_session (0);
5196 editor_list_button.set_active(false);
5197 editor_list_button.set_sensitive(false);
5199 /* clear tempo/meter rulers */
5200 remove_metric_marks ();
5202 clear_marker_display ();
5204 current_bbt_points_begin = current_bbt_points_end;
5206 /* get rid of any existing editor mixer strip */
5208 WindowTitle title(Glib::get_application_name());
5209 title += _("Editor");
5211 set_title (title.get_string());
5213 SessionHandlePtr::session_going_away ();
5218 Editor::show_editor_list (bool yn)
5221 _the_notebook.show ();
5223 _the_notebook.hide ();
5228 Editor::change_region_layering_order (bool from_context_menu)
5230 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5232 if (!clicked_routeview) {
5233 if (layering_order_editor) {
5234 layering_order_editor->hide ();
5239 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5245 boost::shared_ptr<Playlist> pl = track->playlist();
5251 if (layering_order_editor == 0) {
5252 layering_order_editor = new RegionLayeringOrderEditor (*this);
5253 layering_order_editor->set_position (WIN_POS_MOUSE);
5256 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5257 layering_order_editor->maybe_present ();
5261 Editor::update_region_layering_order_editor ()
5263 if (layering_order_editor && layering_order_editor->is_visible ()) {
5264 change_region_layering_order (true);
5269 Editor::setup_fade_images ()
5271 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5272 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5273 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5274 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5275 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5277 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5278 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5279 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5280 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5281 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5284 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5286 Editor::action_menu_item (std::string const & name)
5288 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5291 return *manage (a->create_menu_item ());
5295 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5297 EventBox* b = manage (new EventBox);
5298 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5299 Label* l = manage (new Label (name));
5303 _the_notebook.append_page (widget, *b);
5307 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5309 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5310 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5313 if (ev->type == GDK_2BUTTON_PRESS) {
5315 /* double-click on a notebook tab shrinks or expands the notebook */
5317 if (_notebook_shrunk) {
5318 if (pre_notebook_shrink_pane_width) {
5319 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5321 _notebook_shrunk = false;
5323 pre_notebook_shrink_pane_width = edit_pane.get_position();
5325 /* this expands the LHS of the edit pane to cover the notebook
5326 PAGE but leaves the tabs visible.
5328 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5329 _notebook_shrunk = true;
5337 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5339 using namespace Menu_Helpers;
5341 MenuList& items = _control_point_context_menu.items ();
5344 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5345 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5346 if (!can_remove_control_point (item)) {
5347 items.back().set_sensitive (false);
5350 _control_point_context_menu.popup (event->button.button, event->button.time);