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"
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/grouped_buttons.h"
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/tearoff.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/window_title.h"
58 #include "gtkmm2ext/choice.h"
59 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
61 #include "ardour/audio_track.h"
62 #include "ardour/audioplaylist.h"
63 #include "ardour/audioregion.h"
64 #include "ardour/location.h"
65 #include "ardour/midi_region.h"
66 #include "ardour/plugin_manager.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_directory.h"
70 #include "ardour/session_route.h"
71 #include "ardour/session_state_utils.h"
72 #include "ardour/tempo.h"
73 #include "ardour/utils.h"
74 #include "ardour/session_playlists.h"
75 #include "ardour/audioengine.h"
77 #include "control_protocol/control_protocol.h"
81 #include "analysis_window.h"
82 #include "audio_clock.h"
83 #include "audio_region_view.h"
84 #include "audio_streamview.h"
85 #include "audio_time_axis.h"
86 #include "automation_time_axis.h"
87 #include "bundle_manager.h"
88 #include "canvas-noevent-text.h"
89 #include "canvas_impl.h"
90 #include "crossfade_edit.h"
91 #include "crossfade_view.h"
95 #include "editor_cursors.h"
96 #include "editor_drag.h"
97 #include "editor_group_tabs.h"
98 #include "editor_locations.h"
99 #include "editor_regions.h"
100 #include "editor_route_groups.h"
101 #include "editor_routes.h"
102 #include "editor_snapshots.h"
103 #include "editor_summary.h"
104 #include "global_port_matrix.h"
105 #include "gui_object.h"
106 #include "gui_thread.h"
107 #include "keyboard.h"
109 #include "midi_time_axis.h"
110 #include "mixer_strip.h"
111 #include "mixer_ui.h"
112 #include "mouse_cursors.h"
113 #include "playlist_selector.h"
114 #include "public_editor.h"
115 #include "region_layering_order_editor.h"
116 #include "rgb_macros.h"
117 #include "rhythm_ferret.h"
118 #include "selection.h"
120 #include "simpleline.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
128 #include "imageframe_socket_handler.h"
132 using namespace ARDOUR;
135 using namespace Glib;
136 using namespace Gtkmm2ext;
137 using namespace Editing;
139 using PBD::internationalize;
141 using Gtkmm2ext::Keyboard;
143 const double Editor::timebar_height = 15.0;
145 static const gchar *_snap_type_strings[] = {
147 N_("Timecode Frames"),
148 N_("Timecode Seconds"),
149 N_("Timecode Minutes"),
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_zoom_focus_strings[] = {
201 #ifdef USE_RUBBERBAND
202 static const gchar *_rb_opt_strings[] = {
205 N_("Balanced multitimbral mixture"),
206 N_("Unpitched percussion with stable notes"),
207 N_("Crisp monophonic instrumental"),
208 N_("Unpitched solo percussion"),
209 N_("Resample without preserving pitch"),
215 show_me_the_size (Requisition* r, const char* what)
217 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
222 pane_size_watcher (Paned* pane)
224 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
225 it is no longer accessible. so stop that. this doesn't happen on X11,
226 just the quartz backend.
231 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
233 gint pos = pane->get_position ();
235 if (pos > max_width_of_lhs) {
236 pane->set_position (max_width_of_lhs);
242 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
244 /* time display buttons */
245 , minsec_label (_("Mins:Secs"))
246 , bbt_label (_("Bars:Beats"))
247 , timecode_label (_("Timecode"))
248 , samples_label (_("Samples"))
249 , tempo_label (_("Tempo"))
250 , meter_label (_("Meter"))
251 , mark_label (_("Location Markers"))
252 , range_mark_label (_("Range Markers"))
253 , transport_mark_label (_("Loop/Punch Ranges"))
254 , cd_mark_label (_("CD Markers"))
255 , edit_packer (4, 4, true)
257 /* the values here don't matter: layout widgets
258 reset them as needed.
261 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
263 /* tool bar related */
265 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
267 , toolbar_selection_clock_table (2,3)
269 , automation_mode_button (_("mode"))
271 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
274 , image_socket_listener(0)
279 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
280 , meters_running(false)
281 , _pending_locate_request (false)
282 , _pending_initial_locate (false)
283 , _last_cut_copy_source_track (0)
285 , _region_selection_change_updates_region_list (true)
286 , _following_mixer_selection (false)
290 /* we are a singleton */
292 PublicEditor::_instance = this;
296 selection = new Selection (this);
297 cut_buffer = new Selection (this);
299 clicked_regionview = 0;
300 clicked_axisview = 0;
301 clicked_routeview = 0;
302 clicked_crossfadeview = 0;
303 clicked_control_point = 0;
304 last_update_frame = 0;
305 pre_press_cursor = 0;
306 _drags = new DragManager (this);
307 current_mixer_strip = 0;
310 snap_type_strings = I18N (_snap_type_strings);
311 snap_mode_strings = I18N (_snap_mode_strings);
312 zoom_focus_strings = I18N (_zoom_focus_strings);
313 edit_point_strings = I18N (_edit_point_strings);
314 #ifdef USE_RUBBERBAND
315 rb_opt_strings = I18N (_rb_opt_strings);
319 snap_threshold = 5.0;
320 bbt_beat_subdivision = 4;
323 last_autoscroll_x = 0;
324 last_autoscroll_y = 0;
325 autoscroll_active = false;
326 autoscroll_timeout_tag = -1;
331 current_interthread_info = 0;
332 _show_measures = true;
333 show_gain_after_trim = false;
335 have_pending_keyboard_selection = false;
336 _follow_playhead = true;
337 _stationary_playhead = false;
338 _xfade_visibility = true;
339 editor_ruler_menu = 0;
340 no_ruler_shown_update = false;
342 range_marker_menu = 0;
343 marker_menu_item = 0;
344 tempo_or_meter_marker_menu = 0;
345 transport_marker_menu = 0;
346 new_transport_marker_menu = 0;
347 editor_mixer_strip_width = Wide;
348 show_editor_mixer_when_tracks_arrive = false;
349 region_edit_menu_split_multichannel_item = 0;
350 region_edit_menu_split_item = 0;
353 current_stepping_trackview = 0;
355 entered_regionview = 0;
357 clear_entered_track = false;
360 button_release_can_deselect = true;
361 _dragging_playhead = false;
362 _dragging_edit_point = false;
363 select_new_marker = false;
365 layering_order_editor = 0;
366 no_save_visual = false;
369 scrubbing_direction = 0;
373 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
374 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
375 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
376 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
377 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
379 _edit_point = EditAtMouse;
380 _internal_editing = false;
381 current_canvas_cursor = 0;
383 frames_per_unit = 2048; /* too early to use reset_zoom () */
385 _scroll_callbacks = 0;
387 zoom_focus = ZoomFocusLeft;
388 set_zoom_focus (ZoomFocusLeft);
389 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
391 bbt_label.set_name ("EditorTimeButton");
392 bbt_label.set_size_request (-1, (int)timebar_height);
393 bbt_label.set_alignment (1.0, 0.5);
394 bbt_label.set_padding (5,0);
396 bbt_label.set_no_show_all();
397 minsec_label.set_name ("EditorTimeButton");
398 minsec_label.set_size_request (-1, (int)timebar_height);
399 minsec_label.set_alignment (1.0, 0.5);
400 minsec_label.set_padding (5,0);
401 minsec_label.hide ();
402 minsec_label.set_no_show_all();
403 timecode_label.set_name ("EditorTimeButton");
404 timecode_label.set_size_request (-1, (int)timebar_height);
405 timecode_label.set_alignment (1.0, 0.5);
406 timecode_label.set_padding (5,0);
407 timecode_label.hide ();
408 timecode_label.set_no_show_all();
409 samples_label.set_name ("EditorTimeButton");
410 samples_label.set_size_request (-1, (int)timebar_height);
411 samples_label.set_alignment (1.0, 0.5);
412 samples_label.set_padding (5,0);
413 samples_label.hide ();
414 samples_label.set_no_show_all();
416 tempo_label.set_name ("EditorTimeButton");
417 tempo_label.set_size_request (-1, (int)timebar_height);
418 tempo_label.set_alignment (1.0, 0.5);
419 tempo_label.set_padding (5,0);
421 tempo_label.set_no_show_all();
423 meter_label.set_name ("EditorTimeButton");
424 meter_label.set_size_request (-1, (int)timebar_height);
425 meter_label.set_alignment (1.0, 0.5);
426 meter_label.set_padding (5,0);
428 meter_label.set_no_show_all();
430 mark_label.set_name ("EditorTimeButton");
431 mark_label.set_size_request (-1, (int)timebar_height);
432 mark_label.set_alignment (1.0, 0.5);
433 mark_label.set_padding (5,0);
435 mark_label.set_no_show_all();
437 cd_mark_label.set_name ("EditorTimeButton");
438 cd_mark_label.set_size_request (-1, (int)timebar_height);
439 cd_mark_label.set_alignment (1.0, 0.5);
440 cd_mark_label.set_padding (5,0);
441 cd_mark_label.hide();
442 cd_mark_label.set_no_show_all();
444 range_mark_label.set_name ("EditorTimeButton");
445 range_mark_label.set_size_request (-1, (int)timebar_height);
446 range_mark_label.set_alignment (1.0, 0.5);
447 range_mark_label.set_padding (5,0);
448 range_mark_label.hide();
449 range_mark_label.set_no_show_all();
451 transport_mark_label.set_name ("EditorTimeButton");
452 transport_mark_label.set_size_request (-1, (int)timebar_height);
453 transport_mark_label.set_alignment (1.0, 0.5);
454 transport_mark_label.set_padding (5,0);
455 transport_mark_label.hide();
456 transport_mark_label.set_no_show_all();
458 initialize_rulers ();
459 initialize_canvas ();
461 _summary = new EditorSummary (this);
463 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
464 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
466 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
468 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
469 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
471 edit_controls_vbox.set_spacing (0);
472 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
473 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
475 HBox* h = manage (new HBox);
476 _group_tabs = new EditorGroupTabs (this);
477 h->pack_start (*_group_tabs, PACK_SHRINK);
478 h->pack_start (edit_controls_vbox);
479 controls_layout.add (*h);
481 controls_layout.set_name ("EditControlsBase");
482 controls_layout.add_events (Gdk::SCROLL_MASK);
483 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
485 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
486 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
488 _cursors = new MouseCursors;
490 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
491 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
492 0.0, 1.0, 100.0, 1.0));
494 pad_line_1->property_color_rgba() = 0xFF0000FF;
499 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
500 time_canvas_vbox.set_size_request (-1, -1);
502 ruler_label_event_box.add (ruler_label_vbox);
503 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
504 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
506 time_button_event_box.add (time_button_vbox);
507 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
508 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
510 /* these enable us to have a dedicated window (for cursor setting, etc.)
511 for the canvas areas.
514 track_canvas_event_box.add (*track_canvas);
516 time_canvas_event_box.add (time_canvas_vbox);
517 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
519 edit_packer.set_col_spacings (0);
520 edit_packer.set_row_spacings (0);
521 edit_packer.set_homogeneous (false);
522 edit_packer.set_border_width (0);
523 edit_packer.set_name ("EditorWindow");
525 /* labels for the rulers */
526 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
527 /* labels for the marker "tracks" */
528 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
530 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
532 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
534 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
536 bottom_hbox.set_border_width (2);
537 bottom_hbox.set_spacing (3);
539 _route_groups = new EditorRouteGroups (this);
540 _routes = new EditorRoutes (this);
541 _regions = new EditorRegions (this);
542 _snapshots = new EditorSnapshots (this);
543 _locations = new EditorLocations (this);
545 add_notebook_page (_("Regions"), _regions->widget ());
546 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
547 add_notebook_page (_("Snapshots"), _snapshots->widget ());
548 add_notebook_page (_("Route Groups"), _route_groups->widget ());
549 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
551 _the_notebook.set_show_tabs (true);
552 _the_notebook.set_scrollable (true);
553 _the_notebook.popup_disable ();
554 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
555 _the_notebook.show_all ();
557 post_maximal_editor_width = 0;
558 post_maximal_horizontal_pane_position = 0;
559 post_maximal_editor_height = 0;
560 post_maximal_vertical_pane_position = 0;
561 _notebook_shrunk = false;
563 editor_summary_pane.pack1(edit_packer);
565 Button* summary_arrows_left_left = manage (new Button);
566 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
567 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
568 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
570 Button* summary_arrows_left_right = manage (new Button);
571 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
572 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
573 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
575 VBox* summary_arrows_left = manage (new VBox);
576 summary_arrows_left->pack_start (*summary_arrows_left_left);
577 summary_arrows_left->pack_start (*summary_arrows_left_right);
579 Button* summary_arrows_right_up = manage (new Button);
580 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
581 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
582 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
584 Button* summary_arrows_right_down = manage (new Button);
585 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
586 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
587 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
589 VBox* summary_arrows_right = manage (new VBox);
590 summary_arrows_right->pack_start (*summary_arrows_right_up);
591 summary_arrows_right->pack_start (*summary_arrows_right_down);
593 Frame* summary_frame = manage (new Frame);
594 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
596 summary_frame->add (*_summary);
597 summary_frame->show ();
599 _summary_hbox.pack_start (*summary_arrows_left, false, false);
600 _summary_hbox.pack_start (*summary_frame, true, true);
601 _summary_hbox.pack_start (*summary_arrows_right, false, false);
603 editor_summary_pane.pack2 (_summary_hbox);
605 edit_pane.pack1 (editor_summary_pane, true, true);
606 edit_pane.pack2 (_the_notebook, false, true);
608 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
610 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
612 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
614 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
615 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
617 top_hbox.pack_start (toolbar_frame);
619 HBox *hbox = manage (new HBox);
620 hbox->pack_start (edit_pane, true, true);
622 global_vpacker.pack_start (top_hbox, false, false);
623 global_vpacker.pack_start (*hbox, true, true);
625 global_hpacker.pack_start (global_vpacker, true, true);
627 set_name ("EditorWindow");
628 add_accel_group (ActionManager::ui_manager->get_accel_group());
630 status_bar_hpacker.show ();
632 vpacker.pack_end (status_bar_hpacker, false, false);
633 vpacker.pack_end (global_hpacker, true, true);
635 /* register actions now so that set_state() can find them and set toggles/checks etc */
638 /* when we start using our own keybinding system for the editor, this
639 * will be uncommented
645 _snap_type = SnapToBeat;
646 set_snap_to (_snap_type);
647 _snap_mode = SnapOff;
648 set_snap_mode (_snap_mode);
649 set_mouse_mode (MouseObject, true);
650 pre_internal_mouse_mode = MouseObject;
651 set_edit_point_preference (EditAtMouse, true);
653 _playlist_selector = new PlaylistSelector();
654 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
656 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
660 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
661 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
663 nudge_forward_button.set_name ("TransportButton");
664 nudge_backward_button.set_name ("TransportButton");
666 fade_context_menu.set_name ("ArdourContextMenu");
668 /* icons, titles, WM stuff */
670 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
671 Glib::RefPtr<Gdk::Pixbuf> icon;
673 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
683 window_icons.push_back (icon);
685 if (!window_icons.empty()) {
686 // set_icon_list (window_icons);
687 set_default_icon_list (window_icons);
690 WindowTitle title(Glib::get_application_name());
691 title += _("Editor");
692 set_title (title.get_string());
693 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
696 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
698 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
699 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
701 /* allow external control surfaces/protocols to do various things */
703 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
704 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
705 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
706 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
707 ControlProtocol::SelectByRID.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1), gui_context());
708 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
710 /* problematic: has to return a value and thus cannot be x-thread */
712 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
714 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
716 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
718 _ignore_region_action = false;
719 _last_region_menu_was_main = false;
720 _popup_region_menu_item = 0;
722 _show_marker_lines = false;
723 _over_region_trim_target = false;
725 /* Button bindings */
727 button_bindings = new Bindings;
729 XMLNode* node = button_settings();
731 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
732 button_bindings->load (**i);
739 setup_fade_images ();
745 if(image_socket_listener) {
746 if(image_socket_listener->is_connected())
748 image_socket_listener->close_connection() ;
751 delete image_socket_listener ;
752 image_socket_listener = 0 ;
756 delete button_bindings;
758 delete _route_groups;
764 Editor::button_settings () const
766 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
767 XMLNode* node = find_named_node (*settings, X_("Buttons"));
770 cerr << "new empty Button node\n";
771 node = new XMLNode (X_("Buttons"));
778 Editor::add_toplevel_controls (Container& cont)
780 vpacker.pack_start (cont, false, false);
785 Editor::catch_vanishing_regionview (RegionView *rv)
787 /* note: the selection will take care of the vanishing
788 audioregionview by itself.
791 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
795 if (clicked_regionview == rv) {
796 clicked_regionview = 0;
799 if (entered_regionview == rv) {
800 set_entered_regionview (0);
803 if (!_all_region_actions_sensitized) {
804 sensitize_all_region_actions (true);
807 _over_region_trim_target = false;
811 Editor::set_entered_regionview (RegionView* rv)
813 if (rv == entered_regionview) {
817 if (entered_regionview) {
818 entered_regionview->exited ();
821 if ((entered_regionview = rv) != 0) {
822 entered_regionview->entered (internal_editing ());
825 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
826 /* This RegionView entry might have changed what region actions
827 are allowed, so sensitize them all in case a key is pressed.
829 sensitize_all_region_actions (true);
834 Editor::set_entered_track (TimeAxisView* tav)
837 entered_track->exited ();
840 if ((entered_track = tav) != 0) {
841 entered_track->entered ();
846 Editor::show_window ()
848 if (!is_visible ()) {
851 /* XXX: this is a bit unfortunate; it would probably
852 be nicer if we could just call show () above rather
853 than needing the show_all ()
856 /* re-hide stuff if necessary */
857 editor_list_button_toggled ();
858 parameter_changed ("show-summary");
859 parameter_changed ("show-group-tabs");
860 parameter_changed ("show-zoom-tools");
862 /* now reset all audio_time_axis heights, because widgets might need
868 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
869 tv = (static_cast<TimeAxisView*>(*i));
873 if (current_mixer_strip) {
874 current_mixer_strip->hide_things ();
875 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
883 Editor::instant_save ()
885 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
890 _session->add_instant_xml(get_state());
892 Config->add_instant_xml(get_state());
897 Editor::zoom_adjustment_changed ()
903 double fpu = zoom_range_clock->current_duration() / _canvas_width;
907 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
908 } else if (fpu > _session->current_end_frame() / _canvas_width) {
909 fpu = _session->current_end_frame() / _canvas_width;
910 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
917 Editor::control_select (uint32_t rid)
919 /* handles the (static) signal from the ControlProtocol class that
920 * requests setting the selected track to a given RID
927 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
933 TimeAxisView* tav = axis_view_from_route (r);
936 selection->set (tav);
938 selection->clear_tracks ();
943 Editor::control_scroll (float fraction)
945 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
951 double step = fraction * current_page_frames();
954 _control_scroll_target is an optional<T>
956 it acts like a pointer to an framepos_t, with
957 a operator conversion to boolean to check
958 that it has a value could possibly use
959 playhead_cursor->current_frame to store the
960 value and a boolean in the class to know
961 when it's out of date
964 if (!_control_scroll_target) {
965 _control_scroll_target = _session->transport_frame();
966 _dragging_playhead = true;
969 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
970 *_control_scroll_target = 0;
971 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
972 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
974 *_control_scroll_target += (framepos_t) floor (step);
977 /* move visuals, we'll catch up with it later */
979 playhead_cursor->set_position (*_control_scroll_target);
980 UpdateAllTransportClocks (*_control_scroll_target);
982 if (*_control_scroll_target > (current_page_frames() / 2)) {
983 /* try to center PH in window */
984 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
990 Now we do a timeout to actually bring the session to the right place
991 according to the playhead. This is to avoid reading disk buffers on every
992 call to control_scroll, which is driven by ScrollTimeline and therefore
993 probably by a control surface wheel which can generate lots of events.
995 /* cancel the existing timeout */
997 control_scroll_connection.disconnect ();
999 /* add the next timeout */
1001 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1005 Editor::deferred_control_scroll (framepos_t /*target*/)
1007 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1008 // reset for next stream
1009 _control_scroll_target = boost::none;
1010 _dragging_playhead = false;
1015 Editor::access_action (std::string action_group, std::string action_item)
1021 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1024 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1032 Editor::on_realize ()
1034 Window::on_realize ();
1039 Editor::map_position_change (framepos_t frame)
1041 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1043 if (_session == 0) {
1047 if (_follow_playhead) {
1048 center_screen (frame);
1051 playhead_cursor->set_position (frame);
1055 Editor::center_screen (framepos_t frame)
1057 double page = _canvas_width * frames_per_unit;
1059 /* if we're off the page, then scroll.
1062 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1063 center_screen_internal (frame, page);
1068 Editor::center_screen_internal (framepos_t frame, float page)
1073 frame -= (framepos_t) page;
1078 reset_x_origin (frame);
1083 Editor::update_title ()
1085 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1088 bool dirty = _session->dirty();
1090 string session_name;
1092 if (_session->snap_name() != _session->name()) {
1093 session_name = _session->snap_name();
1095 session_name = _session->name();
1099 session_name = "*" + session_name;
1102 WindowTitle title(session_name);
1103 title += Glib::get_application_name();
1104 set_title (title.get_string());
1109 Editor::set_session (Session *t)
1111 SessionHandlePtr::set_session (t);
1117 zoom_range_clock->set_session (_session);
1118 _playlist_selector->set_session (_session);
1119 nudge_clock->set_session (_session);
1120 _summary->set_session (_session);
1121 _group_tabs->set_session (_session);
1122 _route_groups->set_session (_session);
1123 _regions->set_session (_session);
1124 _snapshots->set_session (_session);
1125 _routes->set_session (_session);
1126 _locations->set_session (_session);
1128 if (rhythm_ferret) {
1129 rhythm_ferret->set_session (_session);
1132 if (analysis_window) {
1133 analysis_window->set_session (_session);
1137 sfbrowser->set_session (_session);
1140 compute_fixed_ruler_scale ();
1142 /* Make sure we have auto loop and auto punch ranges */
1144 Location* loc = _session->locations()->auto_loop_location();
1146 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1148 if (loc->start() == loc->end()) {
1149 loc->set_end (loc->start() + 1);
1152 _session->locations()->add (loc, false);
1153 _session->set_auto_loop_location (loc);
1156 loc->set_name (_("Loop"));
1159 loc = _session->locations()->auto_punch_location();
1162 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1164 if (loc->start() == loc->end()) {
1165 loc->set_end (loc->start() + 1);
1168 _session->locations()->add (loc, false);
1169 _session->set_auto_punch_location (loc);
1172 loc->set_name (_("Punch"));
1175 refresh_location_display ();
1177 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1178 the selected Marker; this needs the LocationMarker list to be available.
1180 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1181 set_state (*node, Stateful::loading_state_version);
1183 /* catch up with the playhead */
1185 _session->request_locate (playhead_cursor->current_frame);
1186 _pending_initial_locate = true;
1190 /* These signals can all be emitted by a non-GUI thread. Therefore the
1191 handlers for them must not attempt to directly interact with the GUI,
1192 but use Gtkmm2ext::UI::instance()->call_slot();
1195 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1196 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1197 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1198 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1199 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1200 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1201 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1202 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1203 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1204 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1205 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1206 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1207 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display, this), gui_context());
1208 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1210 if (Profile->get_sae()) {
1211 Timecode::BBT_Time bbt;
1215 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1216 nudge_clock->set_mode(AudioClock::BBT);
1217 nudge_clock->set (pos, true);
1220 nudge_clock->set_mode (AudioClock::Timecode);
1221 nudge_clock->set (_session->frame_rate() * 5, true);
1224 playhead_cursor->canvas_item.show ();
1226 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1227 Config->map_parameters (pc);
1228 _session->config.map_parameters (pc);
1230 restore_ruler_visibility ();
1231 //tempo_map_changed (PropertyChange (0));
1232 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1234 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1235 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1238 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1239 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1242 switch (_snap_type) {
1243 case SnapToRegionStart:
1244 case SnapToRegionEnd:
1245 case SnapToRegionSync:
1246 case SnapToRegionBoundary:
1247 build_region_boundary_cache ();
1254 /* register for undo history */
1255 _session->register_with_memento_command_factory(id(), this);
1257 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1259 start_updating_meters ();
1263 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1265 if (a->get_name() == "RegionMenu") {
1266 /* When the main menu's region menu is opened, we setup the actions so that they look right
1267 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1268 so we resensitize all region actions when the entered regionview or the region selection
1269 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1270 happens after the region context menu is opened. So we set a flag here, too.
1274 sensitize_the_right_region_actions ();
1275 _last_region_menu_was_main = true;
1279 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1281 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1283 using namespace Menu_Helpers;
1284 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1287 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1291 MenuList& items (fade_context_menu.items());
1295 switch (item_type) {
1297 case FadeInHandleItem:
1298 if (arv->audio_region()->fade_in_active()) {
1299 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1301 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1304 items.push_back (SeparatorElem());
1306 if (Profile->get_sae()) {
1308 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1309 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1316 *_fade_in_images[FadeLinear],
1317 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1321 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1326 *_fade_in_images[FadeFast],
1327 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1330 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1335 *_fade_in_images[FadeLogB],
1336 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1339 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1344 *_fade_in_images[FadeLogA],
1345 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1348 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1353 *_fade_in_images[FadeSlow],
1354 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1357 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1363 case FadeOutHandleItem:
1364 if (arv->audio_region()->fade_out_active()) {
1365 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1367 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1370 items.push_back (SeparatorElem());
1372 if (Profile->get_sae()) {
1373 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1374 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1380 *_fade_out_images[FadeLinear],
1381 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1390 *_fade_out_images[FadeFast],
1391 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1394 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 *_fade_out_images[FadeLogB],
1400 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1403 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1408 *_fade_out_images[FadeLogA],
1409 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1412 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1417 *_fade_out_images[FadeSlow],
1418 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1421 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1427 fatal << _("programming error: ")
1428 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1433 fade_context_menu.popup (button, time);
1437 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1439 using namespace Menu_Helpers;
1440 Menu* (Editor::*build_menu_function)();
1443 switch (item_type) {
1445 case RegionViewName:
1446 case RegionViewNameHighlight:
1447 case LeftFrameHandle:
1448 case RightFrameHandle:
1449 if (with_selection) {
1450 build_menu_function = &Editor::build_track_selection_context_menu;
1452 build_menu_function = &Editor::build_track_region_context_menu;
1457 if (with_selection) {
1458 build_menu_function = &Editor::build_track_selection_context_menu;
1460 build_menu_function = &Editor::build_track_context_menu;
1464 case CrossfadeViewItem:
1465 build_menu_function = &Editor::build_track_crossfade_context_menu;
1469 if (clicked_routeview->track()) {
1470 build_menu_function = &Editor::build_track_context_menu;
1472 build_menu_function = &Editor::build_track_bus_context_menu;
1477 /* probably shouldn't happen but if it does, we don't care */
1481 menu = (this->*build_menu_function)();
1482 menu->set_name ("ArdourContextMenu");
1484 /* now handle specific situations */
1486 switch (item_type) {
1488 case RegionViewName:
1489 case RegionViewNameHighlight:
1490 case LeftFrameHandle:
1491 case RightFrameHandle:
1492 if (!with_selection) {
1493 if (region_edit_menu_split_item) {
1494 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1495 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1497 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1500 if (region_edit_menu_split_multichannel_item) {
1501 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1502 region_edit_menu_split_multichannel_item->set_sensitive (true);
1504 region_edit_menu_split_multichannel_item->set_sensitive (false);
1513 case CrossfadeViewItem:
1520 /* probably shouldn't happen but if it does, we don't care */
1524 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1526 /* Bounce to disk */
1528 using namespace Menu_Helpers;
1529 MenuList& edit_items = menu->items();
1531 edit_items.push_back (SeparatorElem());
1533 switch (clicked_routeview->audio_track()->freeze_state()) {
1534 case AudioTrack::NoFreeze:
1535 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1538 case AudioTrack::Frozen:
1539 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1542 case AudioTrack::UnFrozen:
1543 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1549 if (item_type == StreamItem && clicked_routeview) {
1550 clicked_routeview->build_underlay_menu(menu);
1553 /* When the region menu is opened, we setup the actions so that they look right
1556 sensitize_the_right_region_actions ();
1557 _last_region_menu_was_main = false;
1559 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1560 menu->popup (button, time);
1564 Editor::build_track_context_menu ()
1566 using namespace Menu_Helpers;
1568 MenuList& edit_items = track_context_menu.items();
1571 add_dstream_context_items (edit_items);
1572 return &track_context_menu;
1576 Editor::build_track_bus_context_menu ()
1578 using namespace Menu_Helpers;
1580 MenuList& edit_items = track_context_menu.items();
1583 add_bus_context_items (edit_items);
1584 return &track_context_menu;
1588 Editor::build_track_region_context_menu ()
1590 using namespace Menu_Helpers;
1591 MenuList& edit_items = track_region_context_menu.items();
1594 /* we've just cleared the track region context menu, so the menu that these
1595 two items were on will have disappeared; stop them dangling.
1597 region_edit_menu_split_item = 0;
1598 region_edit_menu_split_multichannel_item = 0;
1600 /* we might try to use items that are currently attached to a crossfade menu,
1603 track_crossfade_context_menu.items().clear ();
1605 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1608 boost::shared_ptr<Track> tr;
1609 boost::shared_ptr<Playlist> pl;
1611 if ((tr = rtv->track())) {
1612 add_region_context_items (edit_items, tr);
1616 add_dstream_context_items (edit_items);
1618 return &track_region_context_menu;
1622 Editor::build_track_crossfade_context_menu ()
1624 using namespace Menu_Helpers;
1625 MenuList& edit_items = track_crossfade_context_menu.items();
1626 edit_items.clear ();
1628 /* we might try to use items that are currently attached to a crossfade menu,
1631 track_region_context_menu.items().clear ();
1633 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1636 boost::shared_ptr<Track> tr;
1637 boost::shared_ptr<Playlist> pl;
1638 boost::shared_ptr<AudioPlaylist> apl;
1640 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1642 AudioPlaylist::Crossfades xfades;
1646 /* The xfade menu is a bit of a special case, as we always use the mouse position
1647 to decide whether or not to display it (rather than the edit point). No particularly
1648 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1651 mouse_frame (where, ignored);
1652 apl->crossfades_at (where, xfades);
1654 bool const many = xfades.size() > 1;
1656 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1657 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1660 add_region_context_items (edit_items, tr);
1664 add_dstream_context_items (edit_items);
1666 return &track_crossfade_context_menu;
1670 Editor::analyze_region_selection ()
1672 if (analysis_window == 0) {
1673 analysis_window = new AnalysisWindow();
1676 analysis_window->set_session(_session);
1678 analysis_window->show_all();
1681 analysis_window->set_regionmode();
1682 analysis_window->analyze();
1684 analysis_window->present();
1688 Editor::analyze_range_selection()
1690 if (analysis_window == 0) {
1691 analysis_window = new AnalysisWindow();
1694 analysis_window->set_session(_session);
1696 analysis_window->show_all();
1699 analysis_window->set_rangemode();
1700 analysis_window->analyze();
1702 analysis_window->present();
1706 Editor::build_track_selection_context_menu ()
1708 using namespace Menu_Helpers;
1709 MenuList& edit_items = track_selection_context_menu.items();
1710 edit_items.clear ();
1712 add_selection_context_items (edit_items);
1713 // edit_items.push_back (SeparatorElem());
1714 // add_dstream_context_items (edit_items);
1716 return &track_selection_context_menu;
1719 /** Add context menu items relevant to crossfades.
1720 * @param edit_items List to add the items to.
1723 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1725 using namespace Menu_Helpers;
1726 Menu *xfade_menu = manage (new Menu);
1727 MenuList& items = xfade_menu->items();
1728 xfade_menu->set_name ("ArdourContextMenu");
1731 if (xfade->active()) {
1737 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1738 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1740 if (xfade->can_follow_overlap()) {
1742 if (xfade->following_overlap()) {
1743 str = _("Convert to Short");
1745 str = _("Convert to Full");
1748 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1752 str = xfade->out()->name();
1754 str += xfade->in()->name();
1756 str = _("Crossfade");
1759 edit_items.push_back (MenuElem (str, *xfade_menu));
1760 edit_items.push_back (SeparatorElem());
1764 Editor::xfade_edit_left_region ()
1766 if (clicked_crossfadeview) {
1767 clicked_crossfadeview->left_view.show_region_editor ();
1772 Editor::xfade_edit_right_region ()
1774 if (clicked_crossfadeview) {
1775 clicked_crossfadeview->right_view.show_region_editor ();
1780 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1782 using namespace Menu_Helpers;
1784 /* OK, stick the region submenu at the top of the list, and then add
1788 RegionSelection rs = get_regions_from_selection_and_entered ();
1790 string::size_type pos = 0;
1791 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1793 /* we have to hack up the region name because "_" has a special
1794 meaning for menu titles.
1797 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1798 menu_item_name.replace (pos, 1, "__");
1802 if (_popup_region_menu_item == 0) {
1803 _popup_region_menu_item = new MenuItem (menu_item_name);
1804 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1805 _popup_region_menu_item->show ();
1807 _popup_region_menu_item->set_label (menu_item_name);
1810 const framepos_t position = get_preferred_edit_position (false, true);
1812 edit_items.push_back (*_popup_region_menu_item);
1813 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1814 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1816 edit_items.push_back (SeparatorElem());
1819 /** Add context menu items relevant to selection ranges.
1820 * @param edit_items List to add the items to.
1823 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1825 using namespace Menu_Helpers;
1827 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1828 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1830 edit_items.push_back (SeparatorElem());
1831 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1833 edit_items.push_back (SeparatorElem());
1835 edit_items.push_back (
1837 _("Move Range Start to Previous Region Boundary"),
1838 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1842 edit_items.push_back (
1844 _("Move Range Start to Next Region Boundary"),
1845 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1849 edit_items.push_back (
1851 _("Move Range End to Previous Region Boundary"),
1852 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1856 edit_items.push_back (
1858 _("Move Range End to Next Region Boundary"),
1859 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1863 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1865 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1867 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1870 edit_items.push_back (SeparatorElem());
1871 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1872 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1874 edit_items.push_back (SeparatorElem());
1875 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1877 edit_items.push_back (SeparatorElem());
1878 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1879 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1880 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1882 edit_items.push_back (SeparatorElem());
1883 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1884 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1885 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1886 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1887 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1892 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1894 using namespace Menu_Helpers;
1898 Menu *play_menu = manage (new Menu);
1899 MenuList& play_items = play_menu->items();
1900 play_menu->set_name ("ArdourContextMenu");
1902 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1903 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1904 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1905 play_items.push_back (SeparatorElem());
1906 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1908 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1912 Menu *select_menu = manage (new Menu);
1913 MenuList& select_items = select_menu->items();
1914 select_menu->set_name ("ArdourContextMenu");
1916 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1917 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1918 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1919 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1920 select_items.push_back (SeparatorElem());
1921 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1922 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1923 select_items.push_back (SeparatorElem());
1924 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1925 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1926 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1927 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1928 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1929 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1930 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1932 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1936 Menu *cutnpaste_menu = manage (new Menu);
1937 MenuList& cutnpaste_items = cutnpaste_menu->items();
1938 cutnpaste_menu->set_name ("ArdourContextMenu");
1940 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1941 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1942 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1944 cutnpaste_items.push_back (SeparatorElem());
1946 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1947 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1949 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1951 /* Adding new material */
1953 edit_items.push_back (SeparatorElem());
1954 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1955 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1959 Menu *nudge_menu = manage (new Menu());
1960 MenuList& nudge_items = nudge_menu->items();
1961 nudge_menu->set_name ("ArdourContextMenu");
1963 edit_items.push_back (SeparatorElem());
1964 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1965 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1966 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1967 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1969 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1973 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1975 using namespace Menu_Helpers;
1979 Menu *play_menu = manage (new Menu);
1980 MenuList& play_items = play_menu->items();
1981 play_menu->set_name ("ArdourContextMenu");
1983 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1984 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1985 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1989 Menu *select_menu = manage (new Menu);
1990 MenuList& select_items = select_menu->items();
1991 select_menu->set_name ("ArdourContextMenu");
1993 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1994 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1995 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1996 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1997 select_items.push_back (SeparatorElem());
1998 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1999 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2000 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2001 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2003 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2007 Menu *cutnpaste_menu = manage (new Menu);
2008 MenuList& cutnpaste_items = cutnpaste_menu->items();
2009 cutnpaste_menu->set_name ("ArdourContextMenu");
2011 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2012 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2013 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2015 Menu *nudge_menu = manage (new Menu());
2016 MenuList& nudge_items = nudge_menu->items();
2017 nudge_menu->set_name ("ArdourContextMenu");
2019 edit_items.push_back (SeparatorElem());
2020 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2021 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2022 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2023 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2025 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2029 Editor::snap_type() const
2035 Editor::snap_mode() const
2041 Editor::set_snap_to (SnapType st)
2043 unsigned int snap_ind = (unsigned int)st;
2047 if (snap_ind > snap_type_strings.size() - 1) {
2049 _snap_type = (SnapType)snap_ind;
2052 string str = snap_type_strings[snap_ind];
2054 if (str != snap_type_selector.get_active_text()) {
2055 snap_type_selector.set_active_text (str);
2060 switch (_snap_type) {
2061 case SnapToBeatDiv32:
2062 case SnapToBeatDiv28:
2063 case SnapToBeatDiv24:
2064 case SnapToBeatDiv20:
2065 case SnapToBeatDiv16:
2066 case SnapToBeatDiv14:
2067 case SnapToBeatDiv12:
2068 case SnapToBeatDiv10:
2069 case SnapToBeatDiv8:
2070 case SnapToBeatDiv7:
2071 case SnapToBeatDiv6:
2072 case SnapToBeatDiv5:
2073 case SnapToBeatDiv4:
2074 case SnapToBeatDiv3:
2075 case SnapToBeatDiv2:
2076 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2077 update_tempo_based_rulers ();
2080 case SnapToRegionStart:
2081 case SnapToRegionEnd:
2082 case SnapToRegionSync:
2083 case SnapToRegionBoundary:
2084 build_region_boundary_cache ();
2092 SnapChanged (); /* EMIT SIGNAL */
2096 Editor::set_snap_mode (SnapMode mode)
2099 string str = snap_mode_strings[(int)mode];
2101 if (str != snap_mode_selector.get_active_text ()) {
2102 snap_mode_selector.set_active_text (str);
2108 Editor::set_edit_point_preference (EditPoint ep, bool force)
2110 bool changed = (_edit_point != ep);
2113 string str = edit_point_strings[(int)ep];
2115 if (str != edit_point_selector.get_active_text ()) {
2116 edit_point_selector.set_active_text (str);
2119 set_canvas_cursor ();
2121 if (!force && !changed) {
2125 const char* action=NULL;
2127 switch (_edit_point) {
2128 case EditAtPlayhead:
2129 action = "edit-at-playhead";
2131 case EditAtSelectedMarker:
2132 action = "edit-at-marker";
2135 action = "edit-at-mouse";
2139 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2141 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2145 bool in_track_canvas;
2147 if (!mouse_frame (foo, in_track_canvas)) {
2148 in_track_canvas = false;
2151 reset_canvas_action_sensitivity (in_track_canvas);
2157 Editor::set_state (const XMLNode& node, int /*version*/)
2159 const XMLProperty* prop;
2166 g.base_width = default_width;
2167 g.base_height = default_height;
2171 if ((geometry = find_named_node (node, "geometry")) != 0) {
2175 if ((prop = geometry->property("x_size")) == 0) {
2176 prop = geometry->property ("x-size");
2179 g.base_width = atoi(prop->value());
2181 if ((prop = geometry->property("y_size")) == 0) {
2182 prop = geometry->property ("y-size");
2185 g.base_height = atoi(prop->value());
2188 if ((prop = geometry->property ("x_pos")) == 0) {
2189 prop = geometry->property ("x-pos");
2192 x = atoi (prop->value());
2195 if ((prop = geometry->property ("y_pos")) == 0) {
2196 prop = geometry->property ("y-pos");
2199 y = atoi (prop->value());
2203 set_default_size (g.base_width, g.base_height);
2206 if (_session && (prop = node.property ("playhead"))) {
2208 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2209 playhead_cursor->set_position (pos);
2211 playhead_cursor->set_position (0);
2214 if ((prop = node.property ("mixer-width"))) {
2215 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2218 if ((prop = node.property ("zoom-focus"))) {
2219 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2222 if ((prop = node.property ("zoom"))) {
2223 reset_zoom (PBD::atof (prop->value()));
2225 reset_zoom (frames_per_unit);
2228 if ((prop = node.property ("snap-to"))) {
2229 set_snap_to ((SnapType) atoi (prop->value()));
2232 if ((prop = node.property ("snap-mode"))) {
2233 set_snap_mode ((SnapMode) atoi (prop->value()));
2236 if ((prop = node.property ("mouse-mode"))) {
2237 MouseMode m = str2mousemode(prop->value());
2238 set_mouse_mode (m, true);
2240 set_mouse_mode (MouseObject, true);
2243 if ((prop = node.property ("left-frame")) != 0) {
2245 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2246 reset_x_origin (pos);
2250 if ((prop = node.property ("y-origin")) != 0) {
2251 reset_y_origin (atof (prop->value ()));
2254 if ((prop = node.property ("internal-edit"))) {
2255 bool yn = string_is_affirmative (prop->value());
2256 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2258 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2259 tact->set_active (!yn);
2260 tact->set_active (yn);
2264 if ((prop = node.property ("join-object-range"))) {
2265 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2268 if ((prop = node.property ("edit-point"))) {
2269 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2272 if ((prop = node.property ("show-measures"))) {
2273 bool yn = string_is_affirmative (prop->value());
2274 _show_measures = yn;
2275 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2277 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2278 /* do it twice to force the change */
2279 tact->set_active (!yn);
2280 tact->set_active (yn);
2284 if ((prop = node.property ("follow-playhead"))) {
2285 bool yn = string_is_affirmative (prop->value());
2286 set_follow_playhead (yn);
2287 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2289 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2290 if (tact->get_active() != yn) {
2291 tact->set_active (yn);
2296 if ((prop = node.property ("stationary-playhead"))) {
2297 bool yn = string_is_affirmative (prop->value());
2298 set_stationary_playhead (yn);
2299 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2301 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2302 if (tact->get_active() != yn) {
2303 tact->set_active (yn);
2308 if ((prop = node.property ("region-list-sort-type"))) {
2309 RegionListSortType st;
2310 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2313 if ((prop = node.property ("xfades-visible"))) {
2314 bool yn = string_is_affirmative (prop->value());
2315 _xfade_visibility = !yn;
2316 // set_xfade_visibility (yn);
2319 if ((prop = node.property ("show-editor-mixer"))) {
2321 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2324 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2325 bool yn = string_is_affirmative (prop->value());
2327 /* do it twice to force the change */
2329 tact->set_active (!yn);
2330 tact->set_active (yn);
2333 if ((prop = node.property ("show-editor-list"))) {
2335 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2338 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2339 bool yn = string_is_affirmative (prop->value());
2341 /* do it twice to force the change */
2343 tact->set_active (!yn);
2344 tact->set_active (yn);
2347 if ((prop = node.property (X_("editor-list-page")))) {
2348 _the_notebook.set_current_page (atoi (prop->value ()));
2351 if ((prop = node.property (X_("show-marker-lines")))) {
2352 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2354 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2355 bool yn = string_is_affirmative (prop->value ());
2357 tact->set_active (!yn);
2358 tact->set_active (yn);
2361 XMLNodeList children = node.children ();
2362 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2363 selection->set_state (**i, Stateful::current_state_version);
2364 _regions->set_state (**i);
2371 Editor::get_state ()
2373 XMLNode* node = new XMLNode ("Editor");
2376 id().print (buf, sizeof (buf));
2377 node->add_property ("id", buf);
2379 if (is_realized()) {
2380 Glib::RefPtr<Gdk::Window> win = get_window();
2382 int x, y, width, height;
2383 win->get_root_origin(x, y);
2384 win->get_size(width, height);
2386 XMLNode* geometry = new XMLNode ("geometry");
2388 snprintf(buf, sizeof(buf), "%d", width);
2389 geometry->add_property("x-size", string(buf));
2390 snprintf(buf, sizeof(buf), "%d", height);
2391 geometry->add_property("y-size", string(buf));
2392 snprintf(buf, sizeof(buf), "%d", x);
2393 geometry->add_property("x-pos", string(buf));
2394 snprintf(buf, sizeof(buf), "%d", y);
2395 geometry->add_property("y-pos", string(buf));
2396 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2397 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2398 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2399 snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position);
2400 geometry->add_property("pre-maximal-horizontal-pane-position", string(buf));
2401 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2402 geometry->add_property("edit-vertical-pane-pos", string(buf));
2404 node->add_child_nocopy (*geometry);
2407 maybe_add_mixer_strip_width (*node);
2409 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2410 node->add_property ("zoom-focus", buf);
2411 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2412 node->add_property ("zoom", buf);
2413 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2414 node->add_property ("snap-to", buf);
2415 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2416 node->add_property ("snap-mode", buf);
2418 node->add_property ("edit-point", enum_2_string (_edit_point));
2420 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2421 node->add_property ("playhead", buf);
2422 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2423 node->add_property ("left-frame", buf);
2424 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2425 node->add_property ("y-origin", buf);
2427 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2428 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2429 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2430 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2431 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2432 node->add_property ("mouse-mode", enum2str(mouse_mode));
2433 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2434 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2436 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2438 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2439 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2442 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2444 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2445 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2448 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2449 node->add_property (X_("editor-list-page"), buf);
2451 if (button_bindings) {
2452 XMLNode* bb = new XMLNode (X_("Buttons"));
2453 button_bindings->save (*bb);
2454 node->add_child_nocopy (*bb);
2457 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2459 node->add_child_nocopy (selection->get_state ());
2460 node->add_child_nocopy (_regions->get_state ());
2467 /** @param y y offset from the top of all trackviews.
2468 * @return pair: TimeAxisView that y is over, layer index.
2469 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2470 * in stacked or expanded region display mode, otherwise 0.
2472 std::pair<TimeAxisView *, double>
2473 Editor::trackview_by_y_position (double y)
2475 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2477 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2483 return std::make_pair ( (TimeAxisView *) 0, 0);
2486 /** Snap a position to the grid, if appropriate, taking into account current
2487 * grid settings and also the state of any snap modifier keys that may be pressed.
2488 * @param start Position to snap.
2489 * @param event Event to get current key modifier information from, or 0.
2492 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2494 if (!_session || !event) {
2498 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2499 if (_snap_mode == SnapOff) {
2500 snap_to_internal (start, direction, for_mark);
2503 if (_snap_mode != SnapOff) {
2504 snap_to_internal (start, direction, for_mark);
2510 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2512 if (!_session || _snap_mode == SnapOff) {
2516 snap_to_internal (start, direction, for_mark);
2520 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2522 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2523 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2525 switch (_snap_type) {
2526 case SnapToTimecodeFrame:
2527 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2528 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2530 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2534 case SnapToTimecodeSeconds:
2535 if (_session->config.get_timecode_offset_negative()) {
2536 start += _session->config.get_timecode_offset ();
2538 start -= _session->config.get_timecode_offset ();
2540 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2541 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2543 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2546 if (_session->config.get_timecode_offset_negative()) {
2547 start -= _session->config.get_timecode_offset ();
2549 start += _session->config.get_timecode_offset ();
2553 case SnapToTimecodeMinutes:
2554 if (_session->config.get_timecode_offset_negative()) {
2555 start += _session->config.get_timecode_offset ();
2557 start -= _session->config.get_timecode_offset ();
2559 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2560 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2562 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2564 if (_session->config.get_timecode_offset_negative()) {
2565 start -= _session->config.get_timecode_offset ();
2567 start += _session->config.get_timecode_offset ();
2571 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2577 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2579 const framepos_t one_second = _session->frame_rate();
2580 const framepos_t one_minute = _session->frame_rate() * 60;
2581 framepos_t presnap = start;
2585 switch (_snap_type) {
2586 case SnapToTimecodeFrame:
2587 case SnapToTimecodeSeconds:
2588 case SnapToTimecodeMinutes:
2589 return timecode_snap_to_internal (start, direction, for_mark);
2592 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2593 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2595 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2600 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2601 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2603 start = (framepos_t) floor ((double) start / one_second) * one_second;
2608 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2609 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2611 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2616 start = _session->tempo_map().round_to_bar (start, direction);
2620 start = _session->tempo_map().round_to_beat (start, direction);
2623 case SnapToBeatDiv32:
2624 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2626 case SnapToBeatDiv28:
2627 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2629 case SnapToBeatDiv24:
2630 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2632 case SnapToBeatDiv20:
2633 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2635 case SnapToBeatDiv16:
2636 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2638 case SnapToBeatDiv14:
2639 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2641 case SnapToBeatDiv12:
2642 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2644 case SnapToBeatDiv10:
2645 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2647 case SnapToBeatDiv8:
2648 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2650 case SnapToBeatDiv7:
2651 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2653 case SnapToBeatDiv6:
2654 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2656 case SnapToBeatDiv5:
2657 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2659 case SnapToBeatDiv4:
2660 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2662 case SnapToBeatDiv3:
2663 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2665 case SnapToBeatDiv2:
2666 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2674 _session->locations()->marks_either_side (start, before, after);
2676 if (before == max_framepos) {
2678 } else if (after == max_framepos) {
2680 } else if (before != max_framepos && after != max_framepos) {
2681 /* have before and after */
2682 if ((start - before) < (after - start)) {
2691 case SnapToRegionStart:
2692 case SnapToRegionEnd:
2693 case SnapToRegionSync:
2694 case SnapToRegionBoundary:
2695 if (!region_boundary_cache.empty()) {
2697 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2698 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2700 if (direction > 0) {
2701 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2703 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2706 if (next != region_boundary_cache.begin ()) {
2711 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2712 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2714 if (start > (p + n) / 2) {
2723 switch (_snap_mode) {
2729 if (presnap > start) {
2730 if (presnap > (start + unit_to_frame(snap_threshold))) {
2734 } else if (presnap < start) {
2735 if (presnap < (start - unit_to_frame(snap_threshold))) {
2741 /* handled at entry */
2749 Editor::setup_toolbar ()
2751 HBox* mode_box = manage(new HBox);
2752 mode_box->set_border_width (2);
2753 mode_box->set_spacing(4);
2755 /* table containing mode buttons */
2757 HBox* mouse_mode_button_box = manage (new HBox ());
2758 mouse_mode_button_box->set_spacing (2);
2760 if (Profile->get_sae()) {
2761 mouse_mode_button_box->pack_start (mouse_move_button);
2763 mouse_mode_button_box->pack_start (mouse_move_button);
2764 mouse_mode_button_box->pack_start (join_object_range_button);
2765 mouse_mode_button_box->pack_start (mouse_select_button);
2768 mouse_mode_button_box->pack_start (mouse_zoom_button);
2770 if (!Profile->get_sae()) {
2771 mouse_mode_button_box->pack_start (mouse_gain_button);
2774 mouse_mode_button_box->pack_start (mouse_timefx_button);
2775 mouse_mode_button_box->pack_start (mouse_audition_button);
2776 mouse_mode_button_box->pack_start (mouse_draw_button);
2777 mouse_mode_button_box->pack_start (internal_edit_button);
2779 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2780 if (!Profile->get_sae()) {
2781 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2783 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2785 edit_mode_selector.set_name ("EditModeSelector");
2786 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2787 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2789 mode_box->pack_start (edit_mode_selector, false, false);
2790 mode_box->pack_start (*mouse_mode_button_box, false, false);
2792 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2793 _mouse_mode_tearoff->set_name ("MouseModeBase");
2794 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2796 if (Profile->get_sae()) {
2797 _mouse_mode_tearoff->set_can_be_torn_off (false);
2800 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2801 &_mouse_mode_tearoff->tearoff_window()));
2802 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2803 &_mouse_mode_tearoff->tearoff_window(), 1));
2804 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2805 &_mouse_mode_tearoff->tearoff_window()));
2806 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2807 &_mouse_mode_tearoff->tearoff_window(), 1));
2811 _zoom_box.set_spacing (2);
2812 _zoom_box.set_border_width (2);
2816 zoom_in_button.set_name ("zoom button");
2817 zoom_in_button.set_image (::get_icon ("zoom_in"));
2818 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2819 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2820 zoom_in_button.set_related_action (act);
2822 zoom_out_button.set_name ("zoom button");
2823 zoom_out_button.set_image (::get_icon ("zoom_out"));
2824 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2825 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2826 zoom_out_button.set_related_action (act);
2828 zoom_out_full_button.set_name ("zoom button");
2829 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2830 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2831 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2832 zoom_out_full_button.set_related_action (act);
2834 zoom_focus_selector.set_name ("ZoomFocusSelector");
2835 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2836 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2838 _zoom_box.pack_start (zoom_out_button, false, false);
2839 _zoom_box.pack_start (zoom_in_button, false, false);
2840 _zoom_box.pack_start (zoom_out_full_button, false, false);
2842 _zoom_box.pack_start (zoom_focus_selector, false, false);
2844 /* Track zoom buttons */
2845 tav_expand_button.set_name ("TrackHeightButton");
2846 tav_expand_button.set_size_request (-1, 20);
2847 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2848 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2849 act->connect_proxy (tav_expand_button);
2851 tav_shrink_button.set_name ("TrackHeightButton");
2852 tav_shrink_button.set_size_request (-1, 20);
2853 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2854 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2855 act->connect_proxy (tav_shrink_button);
2857 _zoom_box.pack_start (tav_shrink_button);
2858 _zoom_box.pack_start (tav_expand_button);
2860 _zoom_tearoff = manage (new TearOff (_zoom_box));
2862 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2863 &_zoom_tearoff->tearoff_window()));
2864 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2865 &_zoom_tearoff->tearoff_window(), 0));
2866 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2867 &_zoom_tearoff->tearoff_window()));
2868 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2869 &_zoom_tearoff->tearoff_window(), 0));
2871 snap_box.set_spacing (1);
2872 snap_box.set_border_width (2);
2874 snap_type_selector.set_name ("SnapTypeSelector");
2875 set_popdown_strings (snap_type_selector, snap_type_strings);
2876 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2878 snap_mode_selector.set_name ("SnapModeSelector");
2879 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2880 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2882 edit_point_selector.set_name ("EditPointSelector");
2883 set_popdown_strings (edit_point_selector, edit_point_strings);
2884 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2886 snap_box.pack_start (snap_mode_selector, false, false);
2887 snap_box.pack_start (snap_type_selector, false, false);
2888 snap_box.pack_start (edit_point_selector, false, false);
2892 HBox *nudge_box = manage (new HBox);
2893 nudge_box->set_spacing (2);
2894 nudge_box->set_border_width (2);
2896 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2897 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2899 nudge_box->pack_start (nudge_backward_button, false, false);
2900 nudge_box->pack_start (nudge_forward_button, false, false);
2901 nudge_box->pack_start (*nudge_clock, false, false);
2904 /* Pack everything in... */
2906 HBox* hbox = manage (new HBox);
2907 hbox->set_spacing(10);
2909 _tools_tearoff = manage (new TearOff (*hbox));
2910 _tools_tearoff->set_name ("MouseModeBase");
2911 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2913 if (Profile->get_sae()) {
2914 _tools_tearoff->set_can_be_torn_off (false);
2917 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2918 &_tools_tearoff->tearoff_window()));
2919 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2920 &_tools_tearoff->tearoff_window(), 0));
2921 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2922 &_tools_tearoff->tearoff_window()));
2923 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2924 &_tools_tearoff->tearoff_window(), 0));
2926 toolbar_hbox.set_spacing (10);
2927 toolbar_hbox.set_border_width (1);
2929 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2930 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2931 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2933 hbox->pack_start (snap_box, false, false);
2934 if (!Profile->get_small_screen()) {
2935 hbox->pack_start (*nudge_box, false, false);
2937 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2939 hbox->pack_start (panic_box, false, false);
2943 toolbar_base.set_name ("ToolBarBase");
2944 toolbar_base.add (toolbar_hbox);
2946 _toolbar_viewport.add (toolbar_base);
2947 /* stick to the required height but allow width to vary if there's not enough room */
2948 _toolbar_viewport.set_size_request (1, -1);
2950 toolbar_frame.set_shadow_type (SHADOW_OUT);
2951 toolbar_frame.set_name ("BaseFrame");
2952 toolbar_frame.add (_toolbar_viewport);
2956 Editor::setup_tooltips ()
2958 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2959 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
2960 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
2961 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2962 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2963 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2964 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2965 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2966 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2967 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2968 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2969 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2970 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2971 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2972 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2973 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2974 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2975 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2976 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2977 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2978 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2979 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2983 Editor::convert_drop_to_paths (
2984 vector<string>& paths,
2985 const RefPtr<Gdk::DragContext>& /*context*/,
2988 const SelectionData& data,
2992 if (_session == 0) {
2996 vector<string> uris = data.get_uris();
3000 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3001 are actually URI lists. So do it by hand.
3004 if (data.get_target() != "text/plain") {
3008 /* Parse the "uri-list" format that Nautilus provides,
3009 where each pathname is delimited by \r\n.
3011 THERE MAY BE NO NULL TERMINATING CHAR!!!
3014 string txt = data.get_text();
3018 p = (const char *) malloc (txt.length() + 1);
3019 txt.copy ((char *) p, txt.length(), 0);
3020 ((char*)p)[txt.length()] = '\0';
3026 while (g_ascii_isspace (*p))
3030 while (*q && (*q != '\n') && (*q != '\r')) {
3037 while (q > p && g_ascii_isspace (*q))
3042 uris.push_back (string (p, q - p + 1));
3046 p = strchr (p, '\n');
3058 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3060 if ((*i).substr (0,7) == "file://") {
3063 PBD::url_decode (p);
3065 // scan forward past three slashes
3067 string::size_type slashcnt = 0;
3068 string::size_type n = 0;
3069 string::iterator x = p.begin();
3071 while (slashcnt < 3 && x != p.end()) {
3074 } else if (slashcnt == 3) {
3081 if (slashcnt != 3 || x == p.end()) {
3082 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3086 paths.push_back (p.substr (n - 1));
3094 Editor::new_tempo_section ()
3100 Editor::map_transport_state ()
3102 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3104 if (_session && _session->transport_stopped()) {
3105 have_pending_keyboard_selection = false;
3108 update_loop_range_view (true);
3113 Editor::State::State (PublicEditor const * e)
3115 selection = new Selection (e);
3118 Editor::State::~State ()
3124 Editor::begin_reversible_command (string name)
3127 _session->begin_reversible_command (name);
3132 Editor::begin_reversible_command (GQuark q)
3135 _session->begin_reversible_command (q);
3140 Editor::commit_reversible_command ()
3143 _session->commit_reversible_command ();
3148 Editor::history_changed ()
3152 if (undo_action && _session) {
3153 if (_session->undo_depth() == 0) {
3154 label = S_("Command|Undo");
3156 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3158 undo_action->property_label() = label;
3161 if (redo_action && _session) {
3162 if (_session->redo_depth() == 0) {
3165 label = string_compose(_("Redo (%1)"), _session->next_redo());
3167 redo_action->property_label() = label;
3172 Editor::duplicate_dialog (bool with_dialog)
3176 if (mouse_mode == MouseRange) {
3177 if (selection->time.length() == 0) {
3182 RegionSelection rs = get_regions_from_selection_and_entered ();
3184 if (mouse_mode != MouseRange && rs.empty()) {
3190 ArdourDialog win (_("Duplicate"));
3191 Label label (_("Number of duplications:"));
3192 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3193 SpinButton spinner (adjustment, 0.0, 1);
3196 win.get_vbox()->set_spacing (12);
3197 win.get_vbox()->pack_start (hbox);
3198 hbox.set_border_width (6);
3199 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3201 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3202 place, visually. so do this by hand.
3205 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3206 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3207 spinner.grab_focus();
3213 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3214 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3215 win.set_default_response (RESPONSE_ACCEPT);
3217 win.set_position (WIN_POS_MOUSE);
3219 spinner.grab_focus ();
3221 switch (win.run ()) {
3222 case RESPONSE_ACCEPT:
3228 times = adjustment.get_value();
3231 if (mouse_mode == MouseRange) {
3232 duplicate_selection (times);
3234 duplicate_some_regions (rs, times);
3239 Editor::set_edit_mode (EditMode m)
3241 Config->set_edit_mode (m);
3245 Editor::cycle_edit_mode ()
3247 switch (Config->get_edit_mode()) {
3249 if (Profile->get_sae()) {
3250 Config->set_edit_mode (Lock);
3252 Config->set_edit_mode (Splice);
3256 Config->set_edit_mode (Lock);
3259 Config->set_edit_mode (Slide);
3265 Editor::edit_mode_selection_done ()
3267 string s = edit_mode_selector.get_active_text ();
3270 Config->set_edit_mode (string_to_edit_mode (s));
3275 Editor::snap_type_selection_done ()
3277 string choice = snap_type_selector.get_active_text();
3278 SnapType snaptype = SnapToBeat;
3280 if (choice == _("Beats/2")) {
3281 snaptype = SnapToBeatDiv2;
3282 } else if (choice == _("Beats/3")) {
3283 snaptype = SnapToBeatDiv3;
3284 } else if (choice == _("Beats/4")) {
3285 snaptype = SnapToBeatDiv4;
3286 } else if (choice == _("Beats/5")) {
3287 snaptype = SnapToBeatDiv5;
3288 } else if (choice == _("Beats/6")) {
3289 snaptype = SnapToBeatDiv6;
3290 } else if (choice == _("Beats/7")) {
3291 snaptype = SnapToBeatDiv7;
3292 } else if (choice == _("Beats/8")) {
3293 snaptype = SnapToBeatDiv8;
3294 } else if (choice == _("Beats/10")) {
3295 snaptype = SnapToBeatDiv10;
3296 } else if (choice == _("Beats/12")) {
3297 snaptype = SnapToBeatDiv12;
3298 } else if (choice == _("Beats/14")) {
3299 snaptype = SnapToBeatDiv14;
3300 } else if (choice == _("Beats/16")) {
3301 snaptype = SnapToBeatDiv16;
3302 } else if (choice == _("Beats/20")) {
3303 snaptype = SnapToBeatDiv20;
3304 } else if (choice == _("Beats/24")) {
3305 snaptype = SnapToBeatDiv24;
3306 } else if (choice == _("Beats/28")) {
3307 snaptype = SnapToBeatDiv28;
3308 } else if (choice == _("Beats/32")) {
3309 snaptype = SnapToBeatDiv32;
3310 } else if (choice == _("Beats")) {
3311 snaptype = SnapToBeat;
3312 } else if (choice == _("Bars")) {
3313 snaptype = SnapToBar;
3314 } else if (choice == _("Marks")) {
3315 snaptype = SnapToMark;
3316 } else if (choice == _("Region starts")) {
3317 snaptype = SnapToRegionStart;
3318 } else if (choice == _("Region ends")) {
3319 snaptype = SnapToRegionEnd;
3320 } else if (choice == _("Region bounds")) {
3321 snaptype = SnapToRegionBoundary;
3322 } else if (choice == _("Region syncs")) {
3323 snaptype = SnapToRegionSync;
3324 } else if (choice == _("CD Frames")) {
3325 snaptype = SnapToCDFrame;
3326 } else if (choice == _("Timecode Frames")) {
3327 snaptype = SnapToTimecodeFrame;
3328 } else if (choice == _("Timecode Seconds")) {
3329 snaptype = SnapToTimecodeSeconds;
3330 } else if (choice == _("Timecode Minutes")) {
3331 snaptype = SnapToTimecodeMinutes;
3332 } else if (choice == _("Seconds")) {
3333 snaptype = SnapToSeconds;
3334 } else if (choice == _("Minutes")) {
3335 snaptype = SnapToMinutes;
3338 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3340 ract->set_active ();
3345 Editor::snap_mode_selection_done ()
3347 string choice = snap_mode_selector.get_active_text();
3348 SnapMode mode = SnapNormal;
3350 if (choice == _("No Grid")) {
3352 } else if (choice == _("Grid")) {
3354 } else if (choice == _("Magnetic")) {
3355 mode = SnapMagnetic;
3358 RefPtr<RadioAction> ract = snap_mode_action (mode);
3361 ract->set_active (true);
3366 Editor::cycle_edit_point (bool with_marker)
3368 switch (_edit_point) {
3370 set_edit_point_preference (EditAtPlayhead);
3372 case EditAtPlayhead:
3374 set_edit_point_preference (EditAtSelectedMarker);
3376 set_edit_point_preference (EditAtMouse);
3379 case EditAtSelectedMarker:
3380 set_edit_point_preference (EditAtMouse);
3386 Editor::edit_point_selection_done ()
3388 string choice = edit_point_selector.get_active_text();
3389 EditPoint ep = EditAtSelectedMarker;
3391 if (choice == _("Marker")) {
3392 set_edit_point_preference (EditAtSelectedMarker);
3393 } else if (choice == _("Playhead")) {
3394 set_edit_point_preference (EditAtPlayhead);
3396 set_edit_point_preference (EditAtMouse);
3399 RefPtr<RadioAction> ract = edit_point_action (ep);
3402 ract->set_active (true);
3407 Editor::zoom_focus_selection_done ()
3409 string choice = zoom_focus_selector.get_active_text();
3410 ZoomFocus focus_type = ZoomFocusLeft;
3412 if (choice == _("Left")) {
3413 focus_type = ZoomFocusLeft;
3414 } else if (choice == _("Right")) {
3415 focus_type = ZoomFocusRight;
3416 } else if (choice == _("Center")) {
3417 focus_type = ZoomFocusCenter;
3418 } else if (choice == _("Playhead")) {
3419 focus_type = ZoomFocusPlayhead;
3420 } else if (choice == _("Mouse")) {
3421 focus_type = ZoomFocusMouse;
3422 } else if (choice == _("Edit point")) {
3423 focus_type = ZoomFocusEdit;
3426 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3429 ract->set_active ();
3434 Editor::edit_controls_button_release (GdkEventButton* ev)
3436 if (Keyboard::is_context_menu_event (ev)) {
3437 ARDOUR_UI::instance()->add_route (this);
3438 } else if (ev->button == 1) {
3439 selection->clear_tracks ();
3446 Editor::mouse_select_button_release (GdkEventButton* ev)
3448 /* this handles just right-clicks */
3450 if (ev->button != 3) {
3458 Editor::set_zoom_focus (ZoomFocus f)
3460 string str = zoom_focus_strings[(int)f];
3462 if (str != zoom_focus_selector.get_active_text()) {
3463 zoom_focus_selector.set_active_text (str);
3466 if (zoom_focus != f) {
3473 Editor::ensure_float (Window& win)
3475 win.set_transient_for (*this);
3479 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3481 /* recover or initialize pane positions. do this here rather than earlier because
3482 we don't want the positions to change the child allocations, which they seem to do.
3488 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3497 XMLNode* geometry = find_named_node (*node, "geometry");
3499 if (which == static_cast<Paned*> (&edit_pane)) {
3501 if (done & Horizontal) {
3505 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3506 _notebook_shrunk = string_is_affirmative (prop->value ());
3509 if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) {
3510 pre_maximal_horizontal_pane_position = atoi (prop->value ());
3513 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3514 /* initial allocation is 90% to canvas, 10% to notebook */
3515 pos = (int) floor (alloc.get_width() * 0.90f);
3516 snprintf (buf, sizeof(buf), "%d", pos);
3518 pos = atoi (prop->value());
3521 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3522 edit_pane.set_position (pos);
3523 if (pre_maximal_horizontal_pane_position == 0) {
3524 pre_maximal_horizontal_pane_position = pos;
3528 done = (Pane) (done | Horizontal);
3530 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3532 if (done & Vertical) {
3536 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3537 /* initial allocation is 90% to canvas, 10% to summary */
3538 pos = (int) floor (alloc.get_height() * 0.90f);
3539 snprintf (buf, sizeof(buf), "%d", pos);
3541 pos = atoi (prop->value());
3544 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3545 editor_summary_pane.set_position (pos);
3546 pre_maximal_vertical_pane_position = pos;
3549 done = (Pane) (done | Vertical);
3554 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3556 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3557 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3558 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3559 top_hbox.remove (toolbar_frame);
3564 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3566 if (toolbar_frame.get_parent() == 0) {
3567 top_hbox.pack_end (toolbar_frame);
3572 Editor::set_show_measures (bool yn)
3574 if (_show_measures != yn) {
3577 if ((_show_measures = yn) == true) {
3579 tempo_lines->show();
3587 Editor::toggle_follow_playhead ()
3589 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3591 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3592 set_follow_playhead (tact->get_active());
3596 /** @param yn true to follow playhead, otherwise false.
3597 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3600 Editor::set_follow_playhead (bool yn, bool catch_up)
3602 if (_follow_playhead != yn) {
3603 if ((_follow_playhead = yn) == true && catch_up) {
3605 reset_x_origin_to_follow_playhead ();
3612 Editor::toggle_stationary_playhead ()
3614 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3616 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3617 set_stationary_playhead (tact->get_active());
3622 Editor::set_stationary_playhead (bool yn)
3624 if (_stationary_playhead != yn) {
3625 if ((_stationary_playhead = yn) == true) {
3627 // FIXME need a 3.0 equivalent of this 2.X call
3628 // update_current_screen ();
3635 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3637 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3639 xfade->set_active (!xfade->active());
3644 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3646 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3648 xfade->set_follow_overlap (!xfade->following_overlap());
3653 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3655 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3661 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3665 switch (cew.run ()) {
3666 case RESPONSE_ACCEPT:
3673 PropertyChange all_crossfade_properties;
3674 all_crossfade_properties.add (ARDOUR::Properties::active);
3675 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3676 xfade->PropertyChanged (all_crossfade_properties);
3680 Editor::playlist_selector () const
3682 return *_playlist_selector;
3686 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3690 switch (_snap_type) {
3695 case SnapToBeatDiv32:
3698 case SnapToBeatDiv28:
3701 case SnapToBeatDiv24:
3704 case SnapToBeatDiv20:
3707 case SnapToBeatDiv16:
3710 case SnapToBeatDiv14:
3713 case SnapToBeatDiv12:
3716 case SnapToBeatDiv10:
3719 case SnapToBeatDiv8:
3722 case SnapToBeatDiv7:
3725 case SnapToBeatDiv6:
3728 case SnapToBeatDiv5:
3731 case SnapToBeatDiv4:
3734 case SnapToBeatDiv3:
3737 case SnapToBeatDiv2:
3743 return _session->tempo_map().meter_at (position).divisions_per_bar();
3748 case SnapToTimecodeFrame:
3749 case SnapToTimecodeSeconds:
3750 case SnapToTimecodeMinutes:
3753 case SnapToRegionStart:
3754 case SnapToRegionEnd:
3755 case SnapToRegionSync:
3756 case SnapToRegionBoundary:
3766 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3770 ret = nudge_clock->current_duration (pos);
3771 next = ret + 1; /* XXXX fix me */
3777 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3779 ArdourDialog dialog (_("Playlist Deletion"));
3780 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3781 "If it is kept, its audio files will not be cleaned.\n"
3782 "If it is deleted, audio files used by it alone will be cleaned."),
3785 dialog.set_position (WIN_POS_CENTER);
3786 dialog.get_vbox()->pack_start (label);
3790 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3791 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3792 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3794 switch (dialog.run ()) {
3795 case RESPONSE_ACCEPT:
3796 /* delete the playlist */
3800 case RESPONSE_REJECT:
3801 /* keep the playlist */
3813 Editor::audio_region_selection_covers (framepos_t where)
3815 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3816 if ((*a)->region()->covers (where)) {
3825 Editor::prepare_for_cleanup ()
3827 cut_buffer->clear_regions ();
3828 cut_buffer->clear_playlists ();
3830 selection->clear_regions ();
3831 selection->clear_playlists ();
3833 _regions->suspend_redisplay ();
3837 Editor::finish_cleanup ()
3839 _regions->resume_redisplay ();
3843 Editor::transport_loop_location()
3846 return _session->locations()->auto_loop_location();
3853 Editor::transport_punch_location()
3856 return _session->locations()->auto_punch_location();
3863 Editor::control_layout_scroll (GdkEventScroll* ev)
3865 if (Keyboard::some_magic_widget_has_focus()) {
3869 switch (ev->direction) {
3871 scroll_tracks_up_line ();
3875 case GDK_SCROLL_DOWN:
3876 scroll_tracks_down_line ();
3880 /* no left/right handling yet */
3888 Editor::session_state_saved (string)
3891 _snapshots->redisplay ();
3895 Editor::maximise_editing_space ()
3897 /* these calls will leave each tearoff visible *if* it is torn off
3900 _mouse_mode_tearoff->set_visible (false);
3901 _tools_tearoff->set_visible (false);
3902 _zoom_tearoff->set_visible (false);
3904 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
3905 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
3906 pre_maximal_editor_width = this->get_width ();
3907 pre_maximal_editor_height = this->get_height ();
3909 if (post_maximal_horizontal_pane_position == 0) {
3910 post_maximal_horizontal_pane_position = edit_pane.get_width();
3913 if (post_maximal_vertical_pane_position == 0) {
3914 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
3919 if (post_maximal_editor_width) {
3920 edit_pane.set_position (post_maximal_horizontal_pane_position -
3921 abs(post_maximal_editor_width - pre_maximal_editor_width));
3923 edit_pane.set_position (post_maximal_horizontal_pane_position);
3926 /* Hack: we must do this in an idle handler for it to work; see comment in
3927 restore_editing_space()
3930 Glib::signal_idle().connect (
3932 sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position),
3933 post_maximal_vertical_pane_position
3937 if (Config->get_keep_tearoffs()) {
3938 _mouse_mode_tearoff->set_visible (true);
3939 _tools_tearoff->set_visible (true);
3940 if (Config->get_show_zoom_tools ()) {
3941 _zoom_tearoff->set_visible (true);
3948 Editor::idle_reset_vertical_pane_position (int p)
3950 editor_summary_pane.set_position (p);
3955 Editor::restore_editing_space ()
3957 // user changed width/height of panes during fullscreen
3959 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
3960 post_maximal_horizontal_pane_position = edit_pane.get_position();
3963 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
3964 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
3969 _mouse_mode_tearoff->set_visible (true);
3970 _tools_tearoff->set_visible (true);
3971 if (Config->get_show_zoom_tools ()) {
3972 _zoom_tearoff->set_visible (true);
3974 post_maximal_editor_width = this->get_width();
3975 post_maximal_editor_height = this->get_height();
3977 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
3979 /* This is a bit of a hack, but it seems that if you set the vertical pane position
3980 here it gets reset to some wrong value after this method has finished. Doing
3981 the setup in an idle callback seems to work.
3983 Glib::signal_idle().connect (
3985 sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position),
3986 pre_maximal_vertical_pane_position
3992 * Make new playlists for a given track and also any others that belong
3993 * to the same active route group with the `edit' property.
3998 Editor::new_playlists (TimeAxisView* v)
4000 begin_reversible_command (_("new playlists"));
4001 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4002 _session->playlists->get (playlists);
4003 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4004 commit_reversible_command ();
4008 * Use a copy of the current playlist for a given track and also any others that belong
4009 * to the same active route group with the `edit' property.
4014 Editor::copy_playlists (TimeAxisView* v)
4016 begin_reversible_command (_("copy playlists"));
4017 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4018 _session->playlists->get (playlists);
4019 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4020 commit_reversible_command ();
4023 /** Clear the current playlist for a given track and also any others that belong
4024 * to the same active route group with the `edit' property.
4029 Editor::clear_playlists (TimeAxisView* v)
4031 begin_reversible_command (_("clear playlists"));
4032 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4033 _session->playlists->get (playlists);
4034 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4035 commit_reversible_command ();
4039 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4041 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4045 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4047 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4051 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4053 atv.clear_playlist ();
4057 Editor::on_key_press_event (GdkEventKey* ev)
4059 return key_press_focus_accelerator_handler (*this, ev);
4063 Editor::on_key_release_event (GdkEventKey* ev)
4065 return Gtk::Window::on_key_release_event (ev);
4066 // return key_press_focus_accelerator_handler (*this, ev);
4069 /** Queue up a change to the viewport x origin.
4070 * @param frame New x origin.
4073 Editor::reset_x_origin (framepos_t frame)
4075 queue_visual_change (frame);
4079 Editor::reset_y_origin (double y)
4081 queue_visual_change_y (y);
4085 Editor::reset_zoom (double fpu)
4087 queue_visual_change (fpu);
4091 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4093 reset_x_origin (frame);
4096 if (!no_save_visual) {
4097 undo_visual_stack.push_back (current_visual_state(false));
4101 Editor::VisualState::VisualState ()
4102 : gui_state (new GUIObjectState)
4106 Editor::VisualState::~VisualState ()
4111 Editor::VisualState*
4112 Editor::current_visual_state (bool with_tracks)
4114 VisualState* vs = new VisualState;
4115 vs->y_position = vertical_adjustment.get_value();
4116 vs->frames_per_unit = frames_per_unit;
4117 vs->leftmost_frame = leftmost_frame;
4118 vs->zoom_focus = zoom_focus;
4121 *(vs->gui_state) = *ARDOUR_UI::instance()->gui_object_state;
4128 Editor::undo_visual_state ()
4130 if (undo_visual_stack.empty()) {
4134 redo_visual_stack.push_back (current_visual_state());
4136 VisualState* vs = undo_visual_stack.back();
4137 undo_visual_stack.pop_back();
4138 use_visual_state (*vs);
4142 Editor::redo_visual_state ()
4144 if (redo_visual_stack.empty()) {
4148 undo_visual_stack.push_back (current_visual_state());
4150 VisualState* vs = redo_visual_stack.back();
4151 redo_visual_stack.pop_back();
4152 use_visual_state (*vs);
4156 Editor::swap_visual_state ()
4158 if (undo_visual_stack.empty()) {
4159 redo_visual_state ();
4161 undo_visual_state ();
4166 Editor::use_visual_state (VisualState& vs)
4168 no_save_visual = true;
4170 _routes->suspend_redisplay ();
4172 vertical_adjustment.set_value (vs.y_position);
4174 set_zoom_focus (vs.zoom_focus);
4175 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4177 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4179 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4180 (*i)->reset_visual_state ();
4183 _routes->update_visibility ();
4184 _routes->resume_redisplay ();
4186 no_save_visual = false;
4190 Editor::set_frames_per_unit (double fpu)
4192 /* this is the core function that controls the zoom level of the canvas. it is called
4193 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4196 if (fpu == frames_per_unit) {
4205 /* don't allow zooms that fit more than the maximum number
4206 of frames into an 800 pixel wide space.
4209 if (max_framepos / fpu < 800.0) {
4214 tempo_lines->tempo_map_changed();
4216 frames_per_unit = fpu;
4221 Editor::post_zoom ()
4223 // convert fpu to frame count
4225 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4227 if (frames_per_unit != zoom_range_clock->current_duration()) {
4228 zoom_range_clock->set (frames);
4231 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4232 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4233 (*i)->reshow_selection (selection->time);
4237 ZoomChanged (); /* EMIT_SIGNAL */
4239 //reset_scrolling_region ();
4241 if (playhead_cursor) {
4242 playhead_cursor->set_position (playhead_cursor->current_frame);
4245 refresh_location_display();
4246 _summary->set_overlays_dirty ();
4248 update_marker_labels ();
4254 Editor::queue_visual_change (framepos_t where)
4256 pending_visual_change.add (VisualChange::TimeOrigin);
4257 pending_visual_change.time_origin = where;
4258 ensure_visual_change_idle_handler ();
4262 Editor::queue_visual_change (double fpu)
4264 pending_visual_change.add (VisualChange::ZoomLevel);
4265 pending_visual_change.frames_per_unit = fpu;
4267 ensure_visual_change_idle_handler ();
4271 Editor::queue_visual_change_y (double y)
4273 pending_visual_change.add (VisualChange::YOrigin);
4274 pending_visual_change.y_origin = y;
4276 ensure_visual_change_idle_handler ();
4280 Editor::ensure_visual_change_idle_handler ()
4282 if (pending_visual_change.idle_handler_id < 0) {
4283 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4288 Editor::_idle_visual_changer (void* arg)
4290 return static_cast<Editor*>(arg)->idle_visual_changer ();
4294 Editor::idle_visual_changer ()
4296 VisualChange::Type p = pending_visual_change.pending;
4297 pending_visual_change.pending = (VisualChange::Type) 0;
4299 double const last_time_origin = horizontal_position ();
4301 if (p & VisualChange::TimeOrigin) {
4302 /* This is a bit of a hack, but set_frames_per_unit
4303 below will (if called) end up with the
4304 CrossfadeViews looking at Editor::leftmost_frame,
4305 and if we're changing origin and zoom in the same
4306 operation it will be the wrong value unless we
4310 leftmost_frame = pending_visual_change.time_origin;
4313 if (p & VisualChange::ZoomLevel) {
4314 set_frames_per_unit (pending_visual_change.frames_per_unit);
4316 compute_fixed_ruler_scale ();
4317 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4318 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4319 update_tempo_based_rulers ();
4321 if (p & VisualChange::TimeOrigin) {
4322 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4324 if (p & VisualChange::YOrigin) {
4325 vertical_adjustment.set_value (pending_visual_change.y_origin);
4328 if (last_time_origin == horizontal_position ()) {
4329 /* changed signal not emitted */
4330 update_fixed_rulers ();
4331 redisplay_tempo (true);
4334 _summary->set_overlays_dirty ();
4336 pending_visual_change.idle_handler_id = -1;
4337 return 0; /* this is always a one-shot call */
4340 struct EditorOrderTimeAxisSorter {
4341 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4342 return a->order () < b->order ();
4347 Editor::sort_track_selection (TrackViewList& sel)
4349 EditorOrderTimeAxisSorter cmp;
4354 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4357 framepos_t where = 0;
4358 EditPoint ep = _edit_point;
4360 if (from_context_menu && (ep == EditAtMouse)) {
4361 return event_frame (&context_click_event, 0, 0);
4364 if (entered_marker) {
4365 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4366 return entered_marker->position();
4369 if (ignore_playhead && ep == EditAtPlayhead) {
4370 ep = EditAtSelectedMarker;
4374 case EditAtPlayhead:
4375 where = _session->audible_frame();
4376 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4379 case EditAtSelectedMarker:
4380 if (!selection->markers.empty()) {
4382 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4385 where = loc->start();
4389 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4397 if (!mouse_frame (where, ignored)) {
4398 /* XXX not right but what can we do ? */
4402 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4410 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4412 if (!_session) return;
4414 begin_reversible_command (cmd);
4418 if ((tll = transport_loop_location()) == 0) {
4419 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4420 XMLNode &before = _session->locations()->get_state();
4421 _session->locations()->add (loc, true);
4422 _session->set_auto_loop_location (loc);
4423 XMLNode &after = _session->locations()->get_state();
4424 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4426 XMLNode &before = tll->get_state();
4427 tll->set_hidden (false, this);
4428 tll->set (start, end);
4429 XMLNode &after = tll->get_state();
4430 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4433 commit_reversible_command ();
4437 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4439 if (!_session) return;
4441 begin_reversible_command (cmd);
4445 if ((tpl = transport_punch_location()) == 0) {
4446 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4447 XMLNode &before = _session->locations()->get_state();
4448 _session->locations()->add (loc, true);
4449 _session->set_auto_loop_location (loc);
4450 XMLNode &after = _session->locations()->get_state();
4451 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4454 XMLNode &before = tpl->get_state();
4455 tpl->set_hidden (false, this);
4456 tpl->set (start, end);
4457 XMLNode &after = tpl->get_state();
4458 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4461 commit_reversible_command ();
4464 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4465 * @param rs List to which found regions are added.
4466 * @param where Time to look at.
4467 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4470 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4472 const TrackViewList* tracks;
4475 tracks = &track_views;
4480 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4482 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4485 boost::shared_ptr<Track> tr;
4486 boost::shared_ptr<Playlist> pl;
4488 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4490 boost::shared_ptr<Playlist::RegionList> regions = pl->regions_at (
4491 (framepos_t) floor ( (double) where * tr->speed()));
4493 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4494 RegionView* rv = rtv->view()->find_view (*i);
4505 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4507 const TrackViewList* tracks;
4510 tracks = &track_views;
4515 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4516 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4518 boost::shared_ptr<Track> tr;
4519 boost::shared_ptr<Playlist> pl;
4521 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4523 boost::shared_ptr<Playlist::RegionList> regions = pl->regions_touched (
4524 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4526 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4528 RegionView* rv = rtv->view()->find_view (*i);
4539 /** Start with regions that are selected. Then add equivalent regions
4540 * on tracks in the same active edit-enabled route group as any of
4541 * the regions that we started with.
4545 Editor::get_regions_from_selection ()
4547 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4550 /** Get regions using the following method:
4552 * Make an initial region list using the selected regions, unless
4553 * the edit point is `mouse' and the mouse is over an unselected
4554 * region. In this case, start with just that region.
4556 * Then, make an initial track list of the tracks that these
4557 * regions are on, and if the edit point is not `mouse', add the
4560 * Look at this track list and add any other tracks that are on the
4561 * same active edit-enabled route group as one of the initial tracks.
4563 * Finally take the initial region list and add any regions that are
4564 * under the edit point on one of the tracks on the track list to get
4565 * the returned region list.
4567 * The rationale here is that the mouse edit point is special in that
4568 * its position describes both a time and a track; the other edit
4569 * modes only describe a time. Hence if the edit point is `mouse' we
4570 * ignore selected tracks, as we assume the user means something by
4571 * pointing at a particular track. Also in this case we take note of
4572 * the region directly under the edit point, as there is always just one
4573 * (rather than possibly several with non-mouse edit points).
4577 Editor::get_regions_from_selection_and_edit_point ()
4579 RegionSelection regions;
4581 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4582 regions.add (entered_regionview);
4584 regions = selection->regions;
4587 TrackViewList tracks;
4589 if (_edit_point != EditAtMouse) {
4590 tracks = selection->tracks;
4593 /* Add any other tracks that have regions that are in the same
4594 edit-activated route group as one of our regions.
4596 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4598 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4600 if (g && g->is_active() && g->is_edit()) {
4601 tracks.add (axis_views_from_routes (g->route_list()));
4605 if (!tracks.empty()) {
4606 /* now find regions that are at the edit position on those tracks */
4607 framepos_t const where = get_preferred_edit_position ();
4608 get_regions_at (regions, where, tracks);
4614 /** Start with regions that are selected, or the entered regionview if none are selected.
4615 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4616 * of the regions that we started with.
4620 Editor::get_regions_from_selection_and_entered ()
4622 RegionSelection regions = selection->regions;
4624 if (regions.empty() && entered_regionview) {
4625 regions.add (entered_regionview);
4628 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4632 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4634 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4636 RouteTimeAxisView* tatv;
4638 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4640 boost::shared_ptr<Playlist> pl;
4641 vector<boost::shared_ptr<Region> > results;
4643 boost::shared_ptr<Track> tr;
4645 if ((tr = tatv->track()) == 0) {
4650 if ((pl = (tr->playlist())) != 0) {
4651 pl->get_region_list_equivalent_regions (region, results);
4654 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4655 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4656 regions.push_back (marv);
4665 Editor::show_rhythm_ferret ()
4667 if (rhythm_ferret == 0) {
4668 rhythm_ferret = new RhythmFerret(*this);
4671 rhythm_ferret->set_session (_session);
4672 rhythm_ferret->show ();
4673 rhythm_ferret->present ();
4677 Editor::first_idle ()
4679 MessageDialog* dialog = 0;
4681 if (track_views.size() > 1) {
4682 dialog = new MessageDialog (
4684 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4688 ARDOUR_UI::instance()->flush_pending ();
4691 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4695 // first idle adds route children (automation tracks), so we need to redisplay here
4696 _routes->redisplay ();
4703 Editor::_idle_resize (gpointer arg)
4705 return ((Editor*)arg)->idle_resize ();
4709 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4711 if (resize_idle_id < 0) {
4712 resize_idle_id = g_idle_add (_idle_resize, this);
4713 _pending_resize_amount = 0;
4716 /* make a note of the smallest resulting height, so that we can clamp the
4717 lower limit at TimeAxisView::hSmall */
4719 int32_t min_resulting = INT32_MAX;
4721 _pending_resize_amount += h;
4722 _pending_resize_view = view;
4724 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4726 if (selection->tracks.contains (_pending_resize_view)) {
4727 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4728 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4732 if (min_resulting < 0) {
4737 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4738 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4742 /** Handle pending resizing of tracks */
4744 Editor::idle_resize ()
4746 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4748 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4749 selection->tracks.contains (_pending_resize_view)) {
4751 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4752 if (*i != _pending_resize_view) {
4753 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4758 _pending_resize_amount = 0;
4760 _group_tabs->set_dirty ();
4761 resize_idle_id = -1;
4769 ENSURE_GUI_THREAD (*this, &Editor::located);
4771 playhead_cursor->set_position (_session->audible_frame ());
4772 if (_follow_playhead && !_pending_initial_locate) {
4773 reset_x_origin_to_follow_playhead ();
4776 _pending_locate_request = false;
4777 _pending_initial_locate = false;
4781 Editor::region_view_added (RegionView *)
4783 _summary->set_dirty ();
4787 Editor::region_view_removed ()
4789 _summary->set_dirty ();
4793 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4795 TrackViewList::const_iterator j = track_views.begin ();
4796 while (j != track_views.end()) {
4797 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4798 if (rtv && rtv->route() == r) {
4809 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4813 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4814 TimeAxisView* tv = axis_view_from_route (*i);
4825 Editor::handle_new_route (RouteList& routes)
4827 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4829 RouteTimeAxisView *rtv;
4830 list<RouteTimeAxisView*> new_views;
4832 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4833 boost::shared_ptr<Route> route = (*x);
4835 if (route->is_hidden() || route->is_monitor()) {
4839 DataType dt = route->input()->default_type();
4841 if (dt == ARDOUR::DataType::AUDIO) {
4842 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4843 rtv->set_route (route);
4844 } else if (dt == ARDOUR::DataType::MIDI) {
4845 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4846 rtv->set_route (route);
4848 throw unknown_type();
4851 new_views.push_back (rtv);
4852 track_views.push_back (rtv);
4854 rtv->effective_gain_display ();
4856 if (internal_editing()) {
4857 rtv->enter_internal_edit_mode ();
4859 rtv->leave_internal_edit_mode ();
4862 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4863 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4866 _routes->routes_added (new_views);
4867 _summary->routes_added (new_views);
4869 if (show_editor_mixer_when_tracks_arrive) {
4870 show_editor_mixer (true);
4873 editor_list_button.set_sensitive (true);
4877 Editor::timeaxisview_deleted (TimeAxisView *tv)
4879 if (_session && _session->deletion_in_progress()) {
4880 /* the situation is under control */
4884 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4886 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4888 _routes->route_removed (tv);
4890 if (tv == entered_track) {
4894 TimeAxisView::Children c = tv->get_child_list ();
4895 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4896 if (entered_track == i->get()) {
4901 /* remove it from the list of track views */
4903 TrackViewList::iterator i;
4905 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4906 i = track_views.erase (i);
4909 /* update whatever the current mixer strip is displaying, if revelant */
4911 boost::shared_ptr<Route> route;
4914 route = rtav->route ();
4917 if (current_mixer_strip && current_mixer_strip->route() == route) {
4919 TimeAxisView* next_tv;
4921 if (track_views.empty()) {
4923 } else if (i == track_views.end()) {
4924 next_tv = track_views.front();
4931 set_selected_mixer_strip (*next_tv);
4933 /* make the editor mixer strip go away setting the
4934 * button to inactive (which also unticks the menu option)
4937 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4943 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4945 if (apply_to_selection) {
4946 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4948 TrackSelection::iterator j = i;
4951 hide_track_in_display (*i, false);
4956 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4958 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4959 // this will hide the mixer strip
4960 set_selected_mixer_strip (*tv);
4963 _routes->hide_track_in_display (*tv);
4968 Editor::sync_track_view_list_and_routes ()
4970 track_views = TrackViewList (_routes->views ());
4972 _summary->set_dirty ();
4973 _group_tabs->set_dirty ();
4975 return false; // do not call again (until needed)
4979 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4981 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4986 /** Find a RouteTimeAxisView by the ID of its route */
4988 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4990 RouteTimeAxisView* v;
4992 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4993 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4994 if(v->route()->id() == id) {
5004 Editor::fit_route_group (RouteGroup *g)
5006 TrackViewList ts = axis_views_from_routes (g->route_list ());
5011 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5013 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5016 _session->cancel_audition ();
5020 if (_session->is_auditioning()) {
5021 _session->cancel_audition ();
5022 if (r == last_audition_region) {
5027 _session->audition_region (r);
5028 last_audition_region = r;
5033 Editor::hide_a_region (boost::shared_ptr<Region> r)
5035 r->set_hidden (true);
5039 Editor::show_a_region (boost::shared_ptr<Region> r)
5041 r->set_hidden (false);
5045 Editor::audition_region_from_region_list ()
5047 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5051 Editor::hide_region_from_region_list ()
5053 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5057 Editor::show_region_in_region_list ()
5059 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5063 Editor::step_edit_status_change (bool yn)
5066 start_step_editing ();
5068 stop_step_editing ();
5073 Editor::start_step_editing ()
5075 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5079 Editor::stop_step_editing ()
5081 step_edit_connection.disconnect ();
5085 Editor::check_step_edit ()
5087 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5088 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5090 mtv->check_step_edit ();
5094 return true; // do it again, till we stop
5098 Editor::scroll_press (Direction dir)
5100 ++_scroll_callbacks;
5102 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5103 /* delay the first auto-repeat */
5109 scroll_backward (1);
5117 scroll_tracks_up_line ();
5121 scroll_tracks_down_line ();
5125 /* do hacky auto-repeat */
5126 if (!_scroll_connection.connected ()) {
5128 _scroll_connection = Glib::signal_timeout().connect (
5129 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5132 _scroll_callbacks = 0;
5139 Editor::scroll_release ()
5141 _scroll_connection.disconnect ();
5144 /** Queue a change for the Editor viewport x origin to follow the playhead */
5146 Editor::reset_x_origin_to_follow_playhead ()
5148 framepos_t const frame = playhead_cursor->current_frame;
5150 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5152 if (_session->transport_speed() < 0) {
5154 if (frame > (current_page_frames() / 2)) {
5155 center_screen (frame-(current_page_frames()/2));
5157 center_screen (current_page_frames()/2);
5162 if (frame < leftmost_frame) {
5165 if (_session->transport_rolling()) {
5166 /* rolling; end up with the playhead at the right of the page */
5167 l = frame - current_page_frames ();
5169 /* not rolling: end up with the playhead 3/4 of the way along the page */
5170 l = frame - (3 * current_page_frames() / 4);
5177 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5180 if (_session->transport_rolling()) {
5181 /* rolling: end up with the playhead on the left of the page */
5182 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5184 /* not rolling: end up with the playhead 1/4 of the way along the page */
5185 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5193 Editor::super_rapid_screen_update ()
5195 if (!_session || !_session->engine().running()) {
5199 /* METERING / MIXER STRIPS */
5201 /* update track meters, if required */
5202 if (is_mapped() && meters_running) {
5203 RouteTimeAxisView* rtv;
5204 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5205 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5206 rtv->fast_update ();
5211 /* and any current mixer strip */
5212 if (current_mixer_strip) {
5213 current_mixer_strip->fast_update ();
5216 /* PLAYHEAD AND VIEWPORT */
5218 framepos_t const frame = _session->audible_frame();
5220 /* There are a few reasons why we might not update the playhead / viewport stuff:
5222 * 1. we don't update things when there's a pending locate request, otherwise
5223 * when the editor requests a locate there is a chance that this method
5224 * will move the playhead before the locate request is processed, causing
5226 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5227 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5230 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5232 last_update_frame = frame;
5234 if (!_dragging_playhead) {
5235 playhead_cursor->set_position (frame);
5238 if (!_stationary_playhead) {
5240 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5241 reset_x_origin_to_follow_playhead ();
5246 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5250 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5251 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5252 if (target <= 0.0) {
5255 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5256 target = (target * 0.15) + (current * 0.85);
5262 set_horizontal_position (current);
5271 Editor::session_going_away ()
5273 _have_idled = false;
5275 _session_connections.drop_connections ();
5277 super_rapid_screen_update_connection.disconnect ();
5279 selection->clear ();
5280 cut_buffer->clear ();
5282 clicked_regionview = 0;
5283 clicked_axisview = 0;
5284 clicked_routeview = 0;
5285 clicked_crossfadeview = 0;
5286 entered_regionview = 0;
5288 last_update_frame = 0;
5291 playhead_cursor->canvas_item.hide ();
5293 /* rip everything out of the list displays */
5297 _route_groups->clear ();
5299 /* do this first so that deleting a track doesn't reset cms to null
5300 and thus cause a leak.
5303 if (current_mixer_strip) {
5304 if (current_mixer_strip->get_parent() != 0) {
5305 global_hpacker.remove (*current_mixer_strip);
5307 delete current_mixer_strip;
5308 current_mixer_strip = 0;
5311 /* delete all trackviews */
5313 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5316 track_views.clear ();
5318 zoom_range_clock->set_session (0);
5319 nudge_clock->set_session (0);
5321 editor_list_button.set_active(false);
5322 editor_list_button.set_sensitive(false);
5324 /* clear tempo/meter rulers */
5325 remove_metric_marks ();
5327 clear_marker_display ();
5329 current_bbt_points_begin = current_bbt_points_end;
5331 /* get rid of any existing editor mixer strip */
5333 WindowTitle title(Glib::get_application_name());
5334 title += _("Editor");
5336 set_title (title.get_string());
5338 SessionHandlePtr::session_going_away ();
5343 Editor::show_editor_list (bool yn)
5346 _the_notebook.show ();
5348 _the_notebook.hide ();
5353 Editor::change_region_layering_order (bool from_context_menu)
5355 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5357 if (!clicked_routeview) {
5358 if (layering_order_editor) {
5359 layering_order_editor->hide ();
5364 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5370 boost::shared_ptr<Playlist> pl = track->playlist();
5376 if (layering_order_editor == 0) {
5377 layering_order_editor = new RegionLayeringOrderEditor (*this);
5378 layering_order_editor->set_position (WIN_POS_MOUSE);
5381 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5382 layering_order_editor->maybe_present ();
5386 Editor::update_region_layering_order_editor ()
5388 if (layering_order_editor && layering_order_editor->is_visible ()) {
5389 change_region_layering_order (true);
5394 Editor::setup_fade_images ()
5396 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5397 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5398 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5399 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5400 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5402 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5403 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5404 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5405 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5406 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5410 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5412 Editor::action_menu_item (std::string const & name)
5414 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5417 return *manage (a->create_menu_item ());
5421 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5423 EventBox* b = manage (new EventBox);
5424 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5425 Label* l = manage (new Label (name));
5429 _the_notebook.append_page (widget, *b);
5433 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5435 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5436 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5439 if (ev->type == GDK_2BUTTON_PRESS) {
5441 /* double-click on a notebook tab shrinks or expands the notebook */
5443 if (_notebook_shrunk) {
5444 edit_pane.set_position (pre_maximal_horizontal_pane_position);
5445 _notebook_shrunk = false;
5447 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
5448 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5449 _notebook_shrunk = true;
5457 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5459 using namespace Menu_Helpers;
5461 MenuList& items = _control_point_context_menu.items ();
5464 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5465 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5466 if (!can_remove_control_point (item)) {
5467 items.back().set_sensitive (false);
5470 _control_point_context_menu.popup (event->button.button, event->button.time);