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) {
2249 reset_x_origin (pos);
2253 if ((prop = node.property ("y-origin")) != 0) {
2254 reset_y_origin (atof (prop->value ()));
2257 if ((prop = node.property ("internal-edit"))) {
2258 bool yn = string_is_affirmative (prop->value());
2259 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2261 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2262 tact->set_active (!yn);
2263 tact->set_active (yn);
2267 if ((prop = node.property ("join-object-range"))) {
2268 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2271 if ((prop = node.property ("edit-point"))) {
2272 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2275 if ((prop = node.property ("show-measures"))) {
2276 bool yn = string_is_affirmative (prop->value());
2277 _show_measures = yn;
2278 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2280 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2281 /* do it twice to force the change */
2282 tact->set_active (!yn);
2283 tact->set_active (yn);
2287 if ((prop = node.property ("follow-playhead"))) {
2288 bool yn = string_is_affirmative (prop->value());
2289 set_follow_playhead (yn);
2290 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2292 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2293 if (tact->get_active() != yn) {
2294 tact->set_active (yn);
2299 if ((prop = node.property ("stationary-playhead"))) {
2300 bool yn = string_is_affirmative (prop->value());
2301 set_stationary_playhead (yn);
2302 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2304 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2305 if (tact->get_active() != yn) {
2306 tact->set_active (yn);
2311 if ((prop = node.property ("region-list-sort-type"))) {
2312 RegionListSortType st;
2313 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2316 if ((prop = node.property ("xfades-visible"))) {
2317 bool yn = string_is_affirmative (prop->value());
2318 _xfade_visibility = !yn;
2319 // set_xfade_visibility (yn);
2322 if ((prop = node.property ("show-editor-mixer"))) {
2324 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2327 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2328 bool yn = string_is_affirmative (prop->value());
2330 /* do it twice to force the change */
2332 tact->set_active (!yn);
2333 tact->set_active (yn);
2336 if ((prop = node.property ("show-editor-list"))) {
2338 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2341 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2342 bool yn = string_is_affirmative (prop->value());
2344 /* do it twice to force the change */
2346 tact->set_active (!yn);
2347 tact->set_active (yn);
2350 if ((prop = node.property (X_("editor-list-page")))) {
2351 _the_notebook.set_current_page (atoi (prop->value ()));
2354 if ((prop = node.property (X_("show-marker-lines")))) {
2355 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2357 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2358 bool yn = string_is_affirmative (prop->value ());
2360 tact->set_active (!yn);
2361 tact->set_active (yn);
2364 XMLNodeList children = node.children ();
2365 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2366 selection->set_state (**i, Stateful::current_state_version);
2367 _regions->set_state (**i);
2374 Editor::get_state ()
2376 XMLNode* node = new XMLNode ("Editor");
2379 id().print (buf, sizeof (buf));
2380 node->add_property ("id", buf);
2382 if (is_realized()) {
2383 Glib::RefPtr<Gdk::Window> win = get_window();
2385 int x, y, width, height;
2386 win->get_root_origin(x, y);
2387 win->get_size(width, height);
2389 XMLNode* geometry = new XMLNode ("geometry");
2391 snprintf(buf, sizeof(buf), "%d", width);
2392 geometry->add_property("x-size", string(buf));
2393 snprintf(buf, sizeof(buf), "%d", height);
2394 geometry->add_property("y-size", string(buf));
2395 snprintf(buf, sizeof(buf), "%d", x);
2396 geometry->add_property("x-pos", string(buf));
2397 snprintf(buf, sizeof(buf), "%d", y);
2398 geometry->add_property("y-pos", string(buf));
2399 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2400 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2401 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2402 snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position);
2403 geometry->add_property("pre-maximal-horizontal-pane-position", string(buf));
2404 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2405 geometry->add_property("edit-vertical-pane-pos", string(buf));
2407 node->add_child_nocopy (*geometry);
2410 maybe_add_mixer_strip_width (*node);
2412 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2413 node->add_property ("zoom-focus", buf);
2414 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2415 node->add_property ("zoom", buf);
2416 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2417 node->add_property ("snap-to", buf);
2418 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2419 node->add_property ("snap-mode", buf);
2421 node->add_property ("edit-point", enum_2_string (_edit_point));
2423 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2424 node->add_property ("playhead", buf);
2425 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2426 node->add_property ("left-frame", buf);
2427 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2428 node->add_property ("y-origin", buf);
2430 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2431 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2432 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2433 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2434 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2435 node->add_property ("mouse-mode", enum2str(mouse_mode));
2436 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2437 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2439 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2441 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2442 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2445 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2447 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2448 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2451 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2452 node->add_property (X_("editor-list-page"), buf);
2454 if (button_bindings) {
2455 XMLNode* bb = new XMLNode (X_("Buttons"));
2456 button_bindings->save (*bb);
2457 node->add_child_nocopy (*bb);
2460 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2462 node->add_child_nocopy (selection->get_state ());
2463 node->add_child_nocopy (_regions->get_state ());
2470 /** @param y y offset from the top of all trackviews.
2471 * @return pair: TimeAxisView that y is over, layer index.
2472 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2473 * in stacked or expanded region display mode, otherwise 0.
2475 std::pair<TimeAxisView *, double>
2476 Editor::trackview_by_y_position (double y)
2478 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2480 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2486 return std::make_pair ( (TimeAxisView *) 0, 0);
2489 /** Snap a position to the grid, if appropriate, taking into account current
2490 * grid settings and also the state of any snap modifier keys that may be pressed.
2491 * @param start Position to snap.
2492 * @param event Event to get current key modifier information from, or 0.
2495 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2497 if (!_session || !event) {
2501 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2502 if (_snap_mode == SnapOff) {
2503 snap_to_internal (start, direction, for_mark);
2506 if (_snap_mode != SnapOff) {
2507 snap_to_internal (start, direction, for_mark);
2513 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2515 if (!_session || _snap_mode == SnapOff) {
2519 snap_to_internal (start, direction, for_mark);
2523 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2525 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2526 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2528 switch (_snap_type) {
2529 case SnapToTimecodeFrame:
2530 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2531 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2533 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2537 case SnapToTimecodeSeconds:
2538 if (_session->config.get_timecode_offset_negative()) {
2539 start += _session->config.get_timecode_offset ();
2541 start -= _session->config.get_timecode_offset ();
2543 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2544 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2546 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2549 if (_session->config.get_timecode_offset_negative()) {
2550 start -= _session->config.get_timecode_offset ();
2552 start += _session->config.get_timecode_offset ();
2556 case SnapToTimecodeMinutes:
2557 if (_session->config.get_timecode_offset_negative()) {
2558 start += _session->config.get_timecode_offset ();
2560 start -= _session->config.get_timecode_offset ();
2562 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2563 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2565 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2567 if (_session->config.get_timecode_offset_negative()) {
2568 start -= _session->config.get_timecode_offset ();
2570 start += _session->config.get_timecode_offset ();
2574 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2580 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2582 const framepos_t one_second = _session->frame_rate();
2583 const framepos_t one_minute = _session->frame_rate() * 60;
2584 framepos_t presnap = start;
2588 switch (_snap_type) {
2589 case SnapToTimecodeFrame:
2590 case SnapToTimecodeSeconds:
2591 case SnapToTimecodeMinutes:
2592 return timecode_snap_to_internal (start, direction, for_mark);
2595 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2596 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2598 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2603 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2604 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2606 start = (framepos_t) floor ((double) start / one_second) * one_second;
2611 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2612 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2614 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2619 start = _session->tempo_map().round_to_bar (start, direction);
2623 start = _session->tempo_map().round_to_beat (start, direction);
2626 case SnapToBeatDiv32:
2627 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2629 case SnapToBeatDiv28:
2630 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2632 case SnapToBeatDiv24:
2633 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2635 case SnapToBeatDiv20:
2636 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2638 case SnapToBeatDiv16:
2639 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2641 case SnapToBeatDiv14:
2642 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2644 case SnapToBeatDiv12:
2645 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2647 case SnapToBeatDiv10:
2648 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2650 case SnapToBeatDiv8:
2651 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2653 case SnapToBeatDiv7:
2654 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2656 case SnapToBeatDiv6:
2657 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2659 case SnapToBeatDiv5:
2660 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2662 case SnapToBeatDiv4:
2663 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2665 case SnapToBeatDiv3:
2666 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2668 case SnapToBeatDiv2:
2669 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2677 _session->locations()->marks_either_side (start, before, after);
2679 if (before == max_framepos) {
2681 } else if (after == max_framepos) {
2683 } else if (before != max_framepos && after != max_framepos) {
2684 /* have before and after */
2685 if ((start - before) < (after - start)) {
2694 case SnapToRegionStart:
2695 case SnapToRegionEnd:
2696 case SnapToRegionSync:
2697 case SnapToRegionBoundary:
2698 if (!region_boundary_cache.empty()) {
2700 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2701 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2703 if (direction > 0) {
2704 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2706 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2709 if (next != region_boundary_cache.begin ()) {
2714 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2715 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2717 if (start > (p + n) / 2) {
2726 switch (_snap_mode) {
2732 if (presnap > start) {
2733 if (presnap > (start + unit_to_frame(snap_threshold))) {
2737 } else if (presnap < start) {
2738 if (presnap < (start - unit_to_frame(snap_threshold))) {
2744 /* handled at entry */
2752 Editor::setup_toolbar ()
2754 HBox* mode_box = manage(new HBox);
2755 mode_box->set_border_width (2);
2756 mode_box->set_spacing(4);
2758 /* table containing mode buttons */
2760 HBox* mouse_mode_button_box = manage (new HBox ());
2761 mouse_mode_button_box->set_spacing (2);
2763 if (Profile->get_sae()) {
2764 mouse_mode_button_box->pack_start (mouse_move_button);
2766 mouse_mode_button_box->pack_start (mouse_move_button);
2767 mouse_mode_button_box->pack_start (join_object_range_button);
2768 mouse_mode_button_box->pack_start (mouse_select_button);
2771 mouse_mode_button_box->pack_start (mouse_zoom_button);
2773 if (!Profile->get_sae()) {
2774 mouse_mode_button_box->pack_start (mouse_gain_button);
2777 mouse_mode_button_box->pack_start (mouse_timefx_button);
2778 mouse_mode_button_box->pack_start (mouse_audition_button);
2779 mouse_mode_button_box->pack_start (mouse_draw_button);
2780 mouse_mode_button_box->pack_start (internal_edit_button);
2782 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2783 if (!Profile->get_sae()) {
2784 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2786 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2788 edit_mode_selector.set_name ("EditModeSelector");
2789 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2790 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2792 mode_box->pack_start (edit_mode_selector, false, false);
2793 mode_box->pack_start (*mouse_mode_button_box, false, false);
2795 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2796 _mouse_mode_tearoff->set_name ("MouseModeBase");
2797 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2799 if (Profile->get_sae()) {
2800 _mouse_mode_tearoff->set_can_be_torn_off (false);
2803 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2804 &_mouse_mode_tearoff->tearoff_window()));
2805 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2806 &_mouse_mode_tearoff->tearoff_window(), 1));
2807 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2808 &_mouse_mode_tearoff->tearoff_window()));
2809 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2810 &_mouse_mode_tearoff->tearoff_window(), 1));
2814 _zoom_box.set_spacing (2);
2815 _zoom_box.set_border_width (2);
2819 zoom_in_button.set_name ("zoom button");
2820 zoom_in_button.set_image (::get_icon ("zoom_in"));
2821 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2822 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2823 zoom_in_button.set_related_action (act);
2825 zoom_out_button.set_name ("zoom button");
2826 zoom_out_button.set_image (::get_icon ("zoom_out"));
2827 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2828 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2829 zoom_out_button.set_related_action (act);
2831 zoom_out_full_button.set_name ("zoom button");
2832 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2833 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2834 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2835 zoom_out_full_button.set_related_action (act);
2837 zoom_focus_selector.set_name ("ZoomFocusSelector");
2838 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2839 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2841 _zoom_box.pack_start (zoom_out_button, false, false);
2842 _zoom_box.pack_start (zoom_in_button, false, false);
2843 _zoom_box.pack_start (zoom_out_full_button, false, false);
2845 _zoom_box.pack_start (zoom_focus_selector, false, false);
2847 /* Track zoom buttons */
2848 tav_expand_button.set_name ("TrackHeightButton");
2849 tav_expand_button.set_size_request (-1, 20);
2850 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2851 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2852 act->connect_proxy (tav_expand_button);
2854 tav_shrink_button.set_name ("TrackHeightButton");
2855 tav_shrink_button.set_size_request (-1, 20);
2856 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2857 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2858 act->connect_proxy (tav_shrink_button);
2860 _zoom_box.pack_start (tav_shrink_button);
2861 _zoom_box.pack_start (tav_expand_button);
2863 _zoom_tearoff = manage (new TearOff (_zoom_box));
2865 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2866 &_zoom_tearoff->tearoff_window()));
2867 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2868 &_zoom_tearoff->tearoff_window(), 0));
2869 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2870 &_zoom_tearoff->tearoff_window()));
2871 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2872 &_zoom_tearoff->tearoff_window(), 0));
2874 snap_box.set_spacing (1);
2875 snap_box.set_border_width (2);
2877 snap_type_selector.set_name ("SnapTypeSelector");
2878 set_popdown_strings (snap_type_selector, snap_type_strings);
2879 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2881 snap_mode_selector.set_name ("SnapModeSelector");
2882 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2883 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2885 edit_point_selector.set_name ("EditPointSelector");
2886 set_popdown_strings (edit_point_selector, edit_point_strings);
2887 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2889 snap_box.pack_start (snap_mode_selector, false, false);
2890 snap_box.pack_start (snap_type_selector, false, false);
2891 snap_box.pack_start (edit_point_selector, false, false);
2895 HBox *nudge_box = manage (new HBox);
2896 nudge_box->set_spacing (2);
2897 nudge_box->set_border_width (2);
2899 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2900 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2902 nudge_box->pack_start (nudge_backward_button, false, false);
2903 nudge_box->pack_start (nudge_forward_button, false, false);
2904 nudge_box->pack_start (*nudge_clock, false, false);
2907 /* Pack everything in... */
2909 HBox* hbox = manage (new HBox);
2910 hbox->set_spacing(10);
2912 _tools_tearoff = manage (new TearOff (*hbox));
2913 _tools_tearoff->set_name ("MouseModeBase");
2914 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2916 if (Profile->get_sae()) {
2917 _tools_tearoff->set_can_be_torn_off (false);
2920 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2921 &_tools_tearoff->tearoff_window()));
2922 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2923 &_tools_tearoff->tearoff_window(), 0));
2924 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2925 &_tools_tearoff->tearoff_window()));
2926 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2927 &_tools_tearoff->tearoff_window(), 0));
2929 toolbar_hbox.set_spacing (10);
2930 toolbar_hbox.set_border_width (1);
2932 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2933 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2934 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2936 hbox->pack_start (snap_box, false, false);
2937 if (!Profile->get_small_screen()) {
2938 hbox->pack_start (*nudge_box, false, false);
2940 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2942 hbox->pack_start (panic_box, false, false);
2946 toolbar_base.set_name ("ToolBarBase");
2947 toolbar_base.add (toolbar_hbox);
2949 _toolbar_viewport.add (toolbar_base);
2950 /* stick to the required height but allow width to vary if there's not enough room */
2951 _toolbar_viewport.set_size_request (1, -1);
2953 toolbar_frame.set_shadow_type (SHADOW_OUT);
2954 toolbar_frame.set_name ("BaseFrame");
2955 toolbar_frame.add (_toolbar_viewport);
2959 Editor::setup_tooltips ()
2961 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2962 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
2963 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
2964 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2965 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2966 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2967 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2968 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2969 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2970 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2971 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2972 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2973 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2974 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2975 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2976 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2977 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2978 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2979 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2980 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2981 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2982 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2986 Editor::convert_drop_to_paths (
2987 vector<string>& paths,
2988 const RefPtr<Gdk::DragContext>& /*context*/,
2991 const SelectionData& data,
2995 if (_session == 0) {
2999 vector<string> uris = data.get_uris();
3003 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3004 are actually URI lists. So do it by hand.
3007 if (data.get_target() != "text/plain") {
3011 /* Parse the "uri-list" format that Nautilus provides,
3012 where each pathname is delimited by \r\n.
3014 THERE MAY BE NO NULL TERMINATING CHAR!!!
3017 string txt = data.get_text();
3021 p = (const char *) malloc (txt.length() + 1);
3022 txt.copy ((char *) p, txt.length(), 0);
3023 ((char*)p)[txt.length()] = '\0';
3029 while (g_ascii_isspace (*p))
3033 while (*q && (*q != '\n') && (*q != '\r')) {
3040 while (q > p && g_ascii_isspace (*q))
3045 uris.push_back (string (p, q - p + 1));
3049 p = strchr (p, '\n');
3061 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3063 if ((*i).substr (0,7) == "file://") {
3066 PBD::url_decode (p);
3068 // scan forward past three slashes
3070 string::size_type slashcnt = 0;
3071 string::size_type n = 0;
3072 string::iterator x = p.begin();
3074 while (slashcnt < 3 && x != p.end()) {
3077 } else if (slashcnt == 3) {
3084 if (slashcnt != 3 || x == p.end()) {
3085 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3089 paths.push_back (p.substr (n - 1));
3097 Editor::new_tempo_section ()
3103 Editor::map_transport_state ()
3105 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3107 if (_session && _session->transport_stopped()) {
3108 have_pending_keyboard_selection = false;
3111 update_loop_range_view (true);
3116 Editor::State::State (PublicEditor const * e)
3118 selection = new Selection (e);
3121 Editor::State::~State ()
3127 Editor::begin_reversible_command (string name)
3130 _session->begin_reversible_command (name);
3135 Editor::begin_reversible_command (GQuark q)
3138 _session->begin_reversible_command (q);
3143 Editor::commit_reversible_command ()
3146 _session->commit_reversible_command ();
3151 Editor::history_changed ()
3155 if (undo_action && _session) {
3156 if (_session->undo_depth() == 0) {
3157 label = S_("Command|Undo");
3159 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3161 undo_action->property_label() = label;
3164 if (redo_action && _session) {
3165 if (_session->redo_depth() == 0) {
3168 label = string_compose(_("Redo (%1)"), _session->next_redo());
3170 redo_action->property_label() = label;
3175 Editor::duplicate_dialog (bool with_dialog)
3179 if (mouse_mode == MouseRange) {
3180 if (selection->time.length() == 0) {
3185 RegionSelection rs = get_regions_from_selection_and_entered ();
3187 if (mouse_mode != MouseRange && rs.empty()) {
3193 ArdourDialog win (_("Duplicate"));
3194 Label label (_("Number of duplications:"));
3195 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3196 SpinButton spinner (adjustment, 0.0, 1);
3199 win.get_vbox()->set_spacing (12);
3200 win.get_vbox()->pack_start (hbox);
3201 hbox.set_border_width (6);
3202 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3204 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3205 place, visually. so do this by hand.
3208 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3209 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3210 spinner.grab_focus();
3216 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3217 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3218 win.set_default_response (RESPONSE_ACCEPT);
3220 win.set_position (WIN_POS_MOUSE);
3222 spinner.grab_focus ();
3224 switch (win.run ()) {
3225 case RESPONSE_ACCEPT:
3231 times = adjustment.get_value();
3234 if (mouse_mode == MouseRange) {
3235 duplicate_selection (times);
3237 duplicate_some_regions (rs, times);
3242 Editor::set_edit_mode (EditMode m)
3244 Config->set_edit_mode (m);
3248 Editor::cycle_edit_mode ()
3250 switch (Config->get_edit_mode()) {
3252 if (Profile->get_sae()) {
3253 Config->set_edit_mode (Lock);
3255 Config->set_edit_mode (Splice);
3259 Config->set_edit_mode (Lock);
3262 Config->set_edit_mode (Slide);
3268 Editor::edit_mode_selection_done ()
3270 string s = edit_mode_selector.get_active_text ();
3273 Config->set_edit_mode (string_to_edit_mode (s));
3278 Editor::snap_type_selection_done ()
3280 string choice = snap_type_selector.get_active_text();
3281 SnapType snaptype = SnapToBeat;
3283 if (choice == _("Beats/2")) {
3284 snaptype = SnapToBeatDiv2;
3285 } else if (choice == _("Beats/3")) {
3286 snaptype = SnapToBeatDiv3;
3287 } else if (choice == _("Beats/4")) {
3288 snaptype = SnapToBeatDiv4;
3289 } else if (choice == _("Beats/5")) {
3290 snaptype = SnapToBeatDiv5;
3291 } else if (choice == _("Beats/6")) {
3292 snaptype = SnapToBeatDiv6;
3293 } else if (choice == _("Beats/7")) {
3294 snaptype = SnapToBeatDiv7;
3295 } else if (choice == _("Beats/8")) {
3296 snaptype = SnapToBeatDiv8;
3297 } else if (choice == _("Beats/10")) {
3298 snaptype = SnapToBeatDiv10;
3299 } else if (choice == _("Beats/12")) {
3300 snaptype = SnapToBeatDiv12;
3301 } else if (choice == _("Beats/14")) {
3302 snaptype = SnapToBeatDiv14;
3303 } else if (choice == _("Beats/16")) {
3304 snaptype = SnapToBeatDiv16;
3305 } else if (choice == _("Beats/20")) {
3306 snaptype = SnapToBeatDiv20;
3307 } else if (choice == _("Beats/24")) {
3308 snaptype = SnapToBeatDiv24;
3309 } else if (choice == _("Beats/28")) {
3310 snaptype = SnapToBeatDiv28;
3311 } else if (choice == _("Beats/32")) {
3312 snaptype = SnapToBeatDiv32;
3313 } else if (choice == _("Beats")) {
3314 snaptype = SnapToBeat;
3315 } else if (choice == _("Bars")) {
3316 snaptype = SnapToBar;
3317 } else if (choice == _("Marks")) {
3318 snaptype = SnapToMark;
3319 } else if (choice == _("Region starts")) {
3320 snaptype = SnapToRegionStart;
3321 } else if (choice == _("Region ends")) {
3322 snaptype = SnapToRegionEnd;
3323 } else if (choice == _("Region bounds")) {
3324 snaptype = SnapToRegionBoundary;
3325 } else if (choice == _("Region syncs")) {
3326 snaptype = SnapToRegionSync;
3327 } else if (choice == _("CD Frames")) {
3328 snaptype = SnapToCDFrame;
3329 } else if (choice == _("Timecode Frames")) {
3330 snaptype = SnapToTimecodeFrame;
3331 } else if (choice == _("Timecode Seconds")) {
3332 snaptype = SnapToTimecodeSeconds;
3333 } else if (choice == _("Timecode Minutes")) {
3334 snaptype = SnapToTimecodeMinutes;
3335 } else if (choice == _("Seconds")) {
3336 snaptype = SnapToSeconds;
3337 } else if (choice == _("Minutes")) {
3338 snaptype = SnapToMinutes;
3341 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3343 ract->set_active ();
3348 Editor::snap_mode_selection_done ()
3350 string choice = snap_mode_selector.get_active_text();
3351 SnapMode mode = SnapNormal;
3353 if (choice == _("No Grid")) {
3355 } else if (choice == _("Grid")) {
3357 } else if (choice == _("Magnetic")) {
3358 mode = SnapMagnetic;
3361 RefPtr<RadioAction> ract = snap_mode_action (mode);
3364 ract->set_active (true);
3369 Editor::cycle_edit_point (bool with_marker)
3371 switch (_edit_point) {
3373 set_edit_point_preference (EditAtPlayhead);
3375 case EditAtPlayhead:
3377 set_edit_point_preference (EditAtSelectedMarker);
3379 set_edit_point_preference (EditAtMouse);
3382 case EditAtSelectedMarker:
3383 set_edit_point_preference (EditAtMouse);
3389 Editor::edit_point_selection_done ()
3391 string choice = edit_point_selector.get_active_text();
3392 EditPoint ep = EditAtSelectedMarker;
3394 if (choice == _("Marker")) {
3395 set_edit_point_preference (EditAtSelectedMarker);
3396 } else if (choice == _("Playhead")) {
3397 set_edit_point_preference (EditAtPlayhead);
3399 set_edit_point_preference (EditAtMouse);
3402 RefPtr<RadioAction> ract = edit_point_action (ep);
3405 ract->set_active (true);
3410 Editor::zoom_focus_selection_done ()
3412 string choice = zoom_focus_selector.get_active_text();
3413 ZoomFocus focus_type = ZoomFocusLeft;
3415 if (choice == _("Left")) {
3416 focus_type = ZoomFocusLeft;
3417 } else if (choice == _("Right")) {
3418 focus_type = ZoomFocusRight;
3419 } else if (choice == _("Center")) {
3420 focus_type = ZoomFocusCenter;
3421 } else if (choice == _("Playhead")) {
3422 focus_type = ZoomFocusPlayhead;
3423 } else if (choice == _("Mouse")) {
3424 focus_type = ZoomFocusMouse;
3425 } else if (choice == _("Edit point")) {
3426 focus_type = ZoomFocusEdit;
3429 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3432 ract->set_active ();
3437 Editor::edit_controls_button_release (GdkEventButton* ev)
3439 if (Keyboard::is_context_menu_event (ev)) {
3440 ARDOUR_UI::instance()->add_route (this);
3441 } else if (ev->button == 1) {
3442 selection->clear_tracks ();
3449 Editor::mouse_select_button_release (GdkEventButton* ev)
3451 /* this handles just right-clicks */
3453 if (ev->button != 3) {
3461 Editor::set_zoom_focus (ZoomFocus f)
3463 string str = zoom_focus_strings[(int)f];
3465 if (str != zoom_focus_selector.get_active_text()) {
3466 zoom_focus_selector.set_active_text (str);
3469 if (zoom_focus != f) {
3476 Editor::ensure_float (Window& win)
3478 win.set_transient_for (*this);
3482 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3484 /* recover or initialize pane positions. do this here rather than earlier because
3485 we don't want the positions to change the child allocations, which they seem to do.
3491 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3500 XMLNode* geometry = find_named_node (*node, "geometry");
3502 if (which == static_cast<Paned*> (&edit_pane)) {
3504 if (done & Horizontal) {
3508 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3509 _notebook_shrunk = string_is_affirmative (prop->value ());
3512 if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) {
3513 pre_maximal_horizontal_pane_position = atoi (prop->value ());
3516 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3517 /* initial allocation is 90% to canvas, 10% to notebook */
3518 pos = (int) floor (alloc.get_width() * 0.90f);
3519 snprintf (buf, sizeof(buf), "%d", pos);
3521 pos = atoi (prop->value());
3524 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3525 edit_pane.set_position (pos);
3526 if (pre_maximal_horizontal_pane_position == 0) {
3527 pre_maximal_horizontal_pane_position = pos;
3531 done = (Pane) (done | Horizontal);
3533 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3535 if (done & Vertical) {
3539 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3540 /* initial allocation is 90% to canvas, 10% to summary */
3541 pos = (int) floor (alloc.get_height() * 0.90f);
3542 snprintf (buf, sizeof(buf), "%d", pos);
3544 pos = atoi (prop->value());
3547 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3548 editor_summary_pane.set_position (pos);
3549 pre_maximal_vertical_pane_position = pos;
3552 done = (Pane) (done | Vertical);
3557 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3559 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3560 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3561 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3562 top_hbox.remove (toolbar_frame);
3567 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3569 if (toolbar_frame.get_parent() == 0) {
3570 top_hbox.pack_end (toolbar_frame);
3575 Editor::set_show_measures (bool yn)
3577 if (_show_measures != yn) {
3580 if ((_show_measures = yn) == true) {
3582 tempo_lines->show();
3590 Editor::toggle_follow_playhead ()
3592 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3594 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3595 set_follow_playhead (tact->get_active());
3599 /** @param yn true to follow playhead, otherwise false.
3600 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3603 Editor::set_follow_playhead (bool yn, bool catch_up)
3605 if (_follow_playhead != yn) {
3606 if ((_follow_playhead = yn) == true && catch_up) {
3608 reset_x_origin_to_follow_playhead ();
3615 Editor::toggle_stationary_playhead ()
3617 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3619 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3620 set_stationary_playhead (tact->get_active());
3625 Editor::set_stationary_playhead (bool yn)
3627 if (_stationary_playhead != yn) {
3628 if ((_stationary_playhead = yn) == true) {
3630 // FIXME need a 3.0 equivalent of this 2.X call
3631 // update_current_screen ();
3638 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3640 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3642 xfade->set_active (!xfade->active());
3647 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3649 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3651 xfade->set_follow_overlap (!xfade->following_overlap());
3656 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3658 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3664 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3668 switch (cew.run ()) {
3669 case RESPONSE_ACCEPT:
3676 PropertyChange all_crossfade_properties;
3677 all_crossfade_properties.add (ARDOUR::Properties::active);
3678 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3679 xfade->PropertyChanged (all_crossfade_properties);
3683 Editor::playlist_selector () const
3685 return *_playlist_selector;
3689 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3693 switch (_snap_type) {
3698 case SnapToBeatDiv32:
3701 case SnapToBeatDiv28:
3704 case SnapToBeatDiv24:
3707 case SnapToBeatDiv20:
3710 case SnapToBeatDiv16:
3713 case SnapToBeatDiv14:
3716 case SnapToBeatDiv12:
3719 case SnapToBeatDiv10:
3722 case SnapToBeatDiv8:
3725 case SnapToBeatDiv7:
3728 case SnapToBeatDiv6:
3731 case SnapToBeatDiv5:
3734 case SnapToBeatDiv4:
3737 case SnapToBeatDiv3:
3740 case SnapToBeatDiv2:
3746 return _session->tempo_map().meter_at (position).divisions_per_bar();
3751 case SnapToTimecodeFrame:
3752 case SnapToTimecodeSeconds:
3753 case SnapToTimecodeMinutes:
3756 case SnapToRegionStart:
3757 case SnapToRegionEnd:
3758 case SnapToRegionSync:
3759 case SnapToRegionBoundary:
3769 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3773 ret = nudge_clock->current_duration (pos);
3774 next = ret + 1; /* XXXX fix me */
3780 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3782 ArdourDialog dialog (_("Playlist Deletion"));
3783 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3784 "If it is kept, its audio files will not be cleaned.\n"
3785 "If it is deleted, audio files used by it alone will be cleaned."),
3788 dialog.set_position (WIN_POS_CENTER);
3789 dialog.get_vbox()->pack_start (label);
3793 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3794 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3795 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3797 switch (dialog.run ()) {
3798 case RESPONSE_ACCEPT:
3799 /* delete the playlist */
3803 case RESPONSE_REJECT:
3804 /* keep the playlist */
3816 Editor::audio_region_selection_covers (framepos_t where)
3818 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3819 if ((*a)->region()->covers (where)) {
3828 Editor::prepare_for_cleanup ()
3830 cut_buffer->clear_regions ();
3831 cut_buffer->clear_playlists ();
3833 selection->clear_regions ();
3834 selection->clear_playlists ();
3836 _regions->suspend_redisplay ();
3840 Editor::finish_cleanup ()
3842 _regions->resume_redisplay ();
3846 Editor::transport_loop_location()
3849 return _session->locations()->auto_loop_location();
3856 Editor::transport_punch_location()
3859 return _session->locations()->auto_punch_location();
3866 Editor::control_layout_scroll (GdkEventScroll* ev)
3868 if (Keyboard::some_magic_widget_has_focus()) {
3872 switch (ev->direction) {
3874 scroll_tracks_up_line ();
3878 case GDK_SCROLL_DOWN:
3879 scroll_tracks_down_line ();
3883 /* no left/right handling yet */
3891 Editor::session_state_saved (string)
3894 _snapshots->redisplay ();
3898 Editor::maximise_editing_space ()
3900 /* these calls will leave each tearoff visible *if* it is torn off
3903 _mouse_mode_tearoff->set_visible (false);
3904 _tools_tearoff->set_visible (false);
3905 _zoom_tearoff->set_visible (false);
3907 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
3908 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
3909 pre_maximal_editor_width = this->get_width ();
3910 pre_maximal_editor_height = this->get_height ();
3912 if (post_maximal_horizontal_pane_position == 0) {
3913 post_maximal_horizontal_pane_position = edit_pane.get_width();
3916 if (post_maximal_vertical_pane_position == 0) {
3917 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
3922 if (post_maximal_editor_width) {
3923 edit_pane.set_position (post_maximal_horizontal_pane_position -
3924 abs(post_maximal_editor_width - pre_maximal_editor_width));
3926 edit_pane.set_position (post_maximal_horizontal_pane_position);
3929 /* Hack: we must do this in an idle handler for it to work; see comment in
3930 restore_editing_space()
3933 Glib::signal_idle().connect (
3935 sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position),
3936 post_maximal_vertical_pane_position
3940 if (Config->get_keep_tearoffs()) {
3941 _mouse_mode_tearoff->set_visible (true);
3942 _tools_tearoff->set_visible (true);
3943 if (Config->get_show_zoom_tools ()) {
3944 _zoom_tearoff->set_visible (true);
3951 Editor::idle_reset_vertical_pane_position (int p)
3953 editor_summary_pane.set_position (p);
3958 Editor::restore_editing_space ()
3960 // user changed width/height of panes during fullscreen
3962 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
3963 post_maximal_horizontal_pane_position = edit_pane.get_position();
3966 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
3967 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
3972 _mouse_mode_tearoff->set_visible (true);
3973 _tools_tearoff->set_visible (true);
3974 if (Config->get_show_zoom_tools ()) {
3975 _zoom_tearoff->set_visible (true);
3977 post_maximal_editor_width = this->get_width();
3978 post_maximal_editor_height = this->get_height();
3980 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
3982 /* This is a bit of a hack, but it seems that if you set the vertical pane position
3983 here it gets reset to some wrong value after this method has finished. Doing
3984 the setup in an idle callback seems to work.
3986 Glib::signal_idle().connect (
3988 sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position),
3989 pre_maximal_vertical_pane_position
3995 * Make new playlists for a given track and also any others that belong
3996 * to the same active route group with the `edit' property.
4001 Editor::new_playlists (TimeAxisView* v)
4003 begin_reversible_command (_("new playlists"));
4004 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4005 _session->playlists->get (playlists);
4006 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4007 commit_reversible_command ();
4011 * Use a copy of the current playlist for a given track and also any others that belong
4012 * to the same active route group with the `edit' property.
4017 Editor::copy_playlists (TimeAxisView* v)
4019 begin_reversible_command (_("copy playlists"));
4020 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4021 _session->playlists->get (playlists);
4022 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4023 commit_reversible_command ();
4026 /** Clear the current playlist for a given track and also any others that belong
4027 * to the same active route group with the `edit' property.
4032 Editor::clear_playlists (TimeAxisView* v)
4034 begin_reversible_command (_("clear playlists"));
4035 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4036 _session->playlists->get (playlists);
4037 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4038 commit_reversible_command ();
4042 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4044 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4048 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4050 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4054 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4056 atv.clear_playlist ();
4060 Editor::on_key_press_event (GdkEventKey* ev)
4062 return key_press_focus_accelerator_handler (*this, ev);
4066 Editor::on_key_release_event (GdkEventKey* ev)
4068 return Gtk::Window::on_key_release_event (ev);
4069 // return key_press_focus_accelerator_handler (*this, ev);
4072 /** Queue up a change to the viewport x origin.
4073 * @param frame New x origin.
4076 Editor::reset_x_origin (framepos_t frame)
4078 queue_visual_change (frame);
4082 Editor::reset_y_origin (double y)
4084 queue_visual_change_y (y);
4088 Editor::reset_zoom (double fpu)
4090 queue_visual_change (fpu);
4094 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4096 reset_x_origin (frame);
4099 if (!no_save_visual) {
4100 undo_visual_stack.push_back (current_visual_state(false));
4104 Editor::VisualState::VisualState ()
4105 : gui_state (new GUIObjectState)
4109 Editor::VisualState::~VisualState ()
4114 Editor::VisualState*
4115 Editor::current_visual_state (bool with_tracks)
4117 VisualState* vs = new VisualState;
4118 vs->y_position = vertical_adjustment.get_value();
4119 vs->frames_per_unit = frames_per_unit;
4120 vs->leftmost_frame = leftmost_frame;
4121 vs->zoom_focus = zoom_focus;
4124 *(vs->gui_state) = *ARDOUR_UI::instance()->gui_object_state;
4131 Editor::undo_visual_state ()
4133 if (undo_visual_stack.empty()) {
4137 redo_visual_stack.push_back (current_visual_state());
4139 VisualState* vs = undo_visual_stack.back();
4140 undo_visual_stack.pop_back();
4141 use_visual_state (*vs);
4145 Editor::redo_visual_state ()
4147 if (redo_visual_stack.empty()) {
4151 undo_visual_stack.push_back (current_visual_state());
4153 VisualState* vs = redo_visual_stack.back();
4154 redo_visual_stack.pop_back();
4155 use_visual_state (*vs);
4159 Editor::swap_visual_state ()
4161 if (undo_visual_stack.empty()) {
4162 redo_visual_state ();
4164 undo_visual_state ();
4169 Editor::use_visual_state (VisualState& vs)
4171 no_save_visual = true;
4173 _routes->suspend_redisplay ();
4175 vertical_adjustment.set_value (vs.y_position);
4177 set_zoom_focus (vs.zoom_focus);
4178 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4180 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4182 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4183 (*i)->reset_visual_state ();
4186 _routes->update_visibility ();
4187 _routes->resume_redisplay ();
4189 no_save_visual = false;
4193 Editor::set_frames_per_unit (double fpu)
4195 /* this is the core function that controls the zoom level of the canvas. it is called
4196 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4199 if (fpu == frames_per_unit) {
4208 /* don't allow zooms that fit more than the maximum number
4209 of frames into an 800 pixel wide space.
4212 if (max_framepos / fpu < 800.0) {
4217 tempo_lines->tempo_map_changed();
4219 frames_per_unit = fpu;
4224 Editor::post_zoom ()
4226 // convert fpu to frame count
4228 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4230 if (frames_per_unit != zoom_range_clock->current_duration()) {
4231 zoom_range_clock->set (frames);
4234 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4235 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4236 (*i)->reshow_selection (selection->time);
4240 ZoomChanged (); /* EMIT_SIGNAL */
4242 //reset_scrolling_region ();
4244 if (playhead_cursor) {
4245 playhead_cursor->set_position (playhead_cursor->current_frame);
4248 refresh_location_display();
4249 _summary->set_overlays_dirty ();
4251 update_marker_labels ();
4257 Editor::queue_visual_change (framepos_t where)
4259 pending_visual_change.add (VisualChange::TimeOrigin);
4260 pending_visual_change.time_origin = where;
4261 ensure_visual_change_idle_handler ();
4265 Editor::queue_visual_change (double fpu)
4267 pending_visual_change.add (VisualChange::ZoomLevel);
4268 pending_visual_change.frames_per_unit = fpu;
4270 ensure_visual_change_idle_handler ();
4274 Editor::queue_visual_change_y (double y)
4276 pending_visual_change.add (VisualChange::YOrigin);
4277 pending_visual_change.y_origin = y;
4279 ensure_visual_change_idle_handler ();
4283 Editor::ensure_visual_change_idle_handler ()
4285 if (pending_visual_change.idle_handler_id < 0) {
4286 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4291 Editor::_idle_visual_changer (void* arg)
4293 return static_cast<Editor*>(arg)->idle_visual_changer ();
4297 Editor::idle_visual_changer ()
4299 VisualChange::Type p = pending_visual_change.pending;
4300 pending_visual_change.pending = (VisualChange::Type) 0;
4302 double const last_time_origin = horizontal_position ();
4304 if (p & VisualChange::TimeOrigin) {
4305 /* This is a bit of a hack, but set_frames_per_unit
4306 below will (if called) end up with the
4307 CrossfadeViews looking at Editor::leftmost_frame,
4308 and if we're changing origin and zoom in the same
4309 operation it will be the wrong value unless we
4313 leftmost_frame = pending_visual_change.time_origin;
4314 assert (leftmost_frame >= 0);
4317 if (p & VisualChange::ZoomLevel) {
4318 set_frames_per_unit (pending_visual_change.frames_per_unit);
4320 compute_fixed_ruler_scale ();
4321 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4322 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4323 update_tempo_based_rulers ();
4325 if (p & VisualChange::TimeOrigin) {
4326 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4328 if (p & VisualChange::YOrigin) {
4329 vertical_adjustment.set_value (pending_visual_change.y_origin);
4332 if (last_time_origin == horizontal_position ()) {
4333 /* changed signal not emitted */
4334 update_fixed_rulers ();
4335 redisplay_tempo (true);
4338 _summary->set_overlays_dirty ();
4340 pending_visual_change.idle_handler_id = -1;
4341 return 0; /* this is always a one-shot call */
4344 struct EditorOrderTimeAxisSorter {
4345 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4346 return a->order () < b->order ();
4351 Editor::sort_track_selection (TrackViewList& sel)
4353 EditorOrderTimeAxisSorter cmp;
4358 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4361 framepos_t where = 0;
4362 EditPoint ep = _edit_point;
4364 if (from_context_menu && (ep == EditAtMouse)) {
4365 return event_frame (&context_click_event, 0, 0);
4368 if (entered_marker) {
4369 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4370 return entered_marker->position();
4373 if (ignore_playhead && ep == EditAtPlayhead) {
4374 ep = EditAtSelectedMarker;
4378 case EditAtPlayhead:
4379 where = _session->audible_frame();
4380 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4383 case EditAtSelectedMarker:
4384 if (!selection->markers.empty()) {
4386 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4389 where = loc->start();
4393 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4401 if (!mouse_frame (where, ignored)) {
4402 /* XXX not right but what can we do ? */
4406 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4414 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4416 if (!_session) return;
4418 begin_reversible_command (cmd);
4422 if ((tll = transport_loop_location()) == 0) {
4423 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4424 XMLNode &before = _session->locations()->get_state();
4425 _session->locations()->add (loc, true);
4426 _session->set_auto_loop_location (loc);
4427 XMLNode &after = _session->locations()->get_state();
4428 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4430 XMLNode &before = tll->get_state();
4431 tll->set_hidden (false, this);
4432 tll->set (start, end);
4433 XMLNode &after = tll->get_state();
4434 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4437 commit_reversible_command ();
4441 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4443 if (!_session) return;
4445 begin_reversible_command (cmd);
4449 if ((tpl = transport_punch_location()) == 0) {
4450 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4451 XMLNode &before = _session->locations()->get_state();
4452 _session->locations()->add (loc, true);
4453 _session->set_auto_loop_location (loc);
4454 XMLNode &after = _session->locations()->get_state();
4455 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4458 XMLNode &before = tpl->get_state();
4459 tpl->set_hidden (false, this);
4460 tpl->set (start, end);
4461 XMLNode &after = tpl->get_state();
4462 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4465 commit_reversible_command ();
4468 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4469 * @param rs List to which found regions are added.
4470 * @param where Time to look at.
4471 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4474 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4476 const TrackViewList* tracks;
4479 tracks = &track_views;
4484 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4486 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4489 boost::shared_ptr<Track> tr;
4490 boost::shared_ptr<Playlist> pl;
4492 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4494 boost::shared_ptr<Playlist::RegionList> regions = pl->regions_at (
4495 (framepos_t) floor ( (double) where * tr->speed()));
4497 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4498 RegionView* rv = rtv->view()->find_view (*i);
4509 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4511 const TrackViewList* tracks;
4514 tracks = &track_views;
4519 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4520 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4522 boost::shared_ptr<Track> tr;
4523 boost::shared_ptr<Playlist> pl;
4525 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4527 boost::shared_ptr<Playlist::RegionList> regions = pl->regions_touched (
4528 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4530 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4532 RegionView* rv = rtv->view()->find_view (*i);
4543 /** Start with regions that are selected. Then add equivalent regions
4544 * on tracks in the same active edit-enabled route group as any of
4545 * the regions that we started with.
4549 Editor::get_regions_from_selection ()
4551 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4554 /** Get regions using the following method:
4556 * Make an initial region list using the selected regions, unless
4557 * the edit point is `mouse' and the mouse is over an unselected
4558 * region. In this case, start with just that region.
4560 * Then, make an initial track list of the tracks that these
4561 * regions are on, and if the edit point is not `mouse', add the
4564 * Look at this track list and add any other tracks that are on the
4565 * same active edit-enabled route group as one of the initial tracks.
4567 * Finally take the initial region list and add any regions that are
4568 * under the edit point on one of the tracks on the track list to get
4569 * the returned region list.
4571 * The rationale here is that the mouse edit point is special in that
4572 * its position describes both a time and a track; the other edit
4573 * modes only describe a time. Hence if the edit point is `mouse' we
4574 * ignore selected tracks, as we assume the user means something by
4575 * pointing at a particular track. Also in this case we take note of
4576 * the region directly under the edit point, as there is always just one
4577 * (rather than possibly several with non-mouse edit points).
4581 Editor::get_regions_from_selection_and_edit_point ()
4583 RegionSelection regions;
4585 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4586 regions.add (entered_regionview);
4588 regions = selection->regions;
4591 TrackViewList tracks;
4593 if (_edit_point != EditAtMouse) {
4594 tracks = selection->tracks;
4597 /* Add any other tracks that have regions that are in the same
4598 edit-activated route group as one of our regions.
4600 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4602 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4604 if (g && g->is_active() && g->is_edit()) {
4605 tracks.add (axis_views_from_routes (g->route_list()));
4609 if (!tracks.empty()) {
4610 /* now find regions that are at the edit position on those tracks */
4611 framepos_t const where = get_preferred_edit_position ();
4612 get_regions_at (regions, where, tracks);
4618 /** Start with regions that are selected, or the entered regionview if none are selected.
4619 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4620 * of the regions that we started with.
4624 Editor::get_regions_from_selection_and_entered ()
4626 RegionSelection regions = selection->regions;
4628 if (regions.empty() && entered_regionview) {
4629 regions.add (entered_regionview);
4632 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4636 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4638 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4640 RouteTimeAxisView* tatv;
4642 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4644 boost::shared_ptr<Playlist> pl;
4645 vector<boost::shared_ptr<Region> > results;
4647 boost::shared_ptr<Track> tr;
4649 if ((tr = tatv->track()) == 0) {
4654 if ((pl = (tr->playlist())) != 0) {
4655 pl->get_region_list_equivalent_regions (region, results);
4658 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4659 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4660 regions.push_back (marv);
4669 Editor::show_rhythm_ferret ()
4671 if (rhythm_ferret == 0) {
4672 rhythm_ferret = new RhythmFerret(*this);
4675 rhythm_ferret->set_session (_session);
4676 rhythm_ferret->show ();
4677 rhythm_ferret->present ();
4681 Editor::first_idle ()
4683 MessageDialog* dialog = 0;
4685 if (track_views.size() > 1) {
4686 dialog = new MessageDialog (
4688 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4692 ARDOUR_UI::instance()->flush_pending ();
4695 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4699 // first idle adds route children (automation tracks), so we need to redisplay here
4700 _routes->redisplay ();
4707 Editor::_idle_resize (gpointer arg)
4709 return ((Editor*)arg)->idle_resize ();
4713 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4715 if (resize_idle_id < 0) {
4716 resize_idle_id = g_idle_add (_idle_resize, this);
4717 _pending_resize_amount = 0;
4720 /* make a note of the smallest resulting height, so that we can clamp the
4721 lower limit at TimeAxisView::hSmall */
4723 int32_t min_resulting = INT32_MAX;
4725 _pending_resize_amount += h;
4726 _pending_resize_view = view;
4728 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4730 if (selection->tracks.contains (_pending_resize_view)) {
4731 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4732 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4736 if (min_resulting < 0) {
4741 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4742 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4746 /** Handle pending resizing of tracks */
4748 Editor::idle_resize ()
4750 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4752 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4753 selection->tracks.contains (_pending_resize_view)) {
4755 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4756 if (*i != _pending_resize_view) {
4757 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4762 _pending_resize_amount = 0;
4764 _group_tabs->set_dirty ();
4765 resize_idle_id = -1;
4773 ENSURE_GUI_THREAD (*this, &Editor::located);
4775 playhead_cursor->set_position (_session->audible_frame ());
4776 if (_follow_playhead && !_pending_initial_locate) {
4777 reset_x_origin_to_follow_playhead ();
4780 _pending_locate_request = false;
4781 _pending_initial_locate = false;
4785 Editor::region_view_added (RegionView *)
4787 _summary->set_dirty ();
4791 Editor::region_view_removed ()
4793 _summary->set_dirty ();
4797 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4799 TrackViewList::const_iterator j = track_views.begin ();
4800 while (j != track_views.end()) {
4801 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4802 if (rtv && rtv->route() == r) {
4813 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4817 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4818 TimeAxisView* tv = axis_view_from_route (*i);
4829 Editor::handle_new_route (RouteList& routes)
4831 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4833 RouteTimeAxisView *rtv;
4834 list<RouteTimeAxisView*> new_views;
4836 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4837 boost::shared_ptr<Route> route = (*x);
4839 if (route->is_hidden() || route->is_monitor()) {
4843 DataType dt = route->input()->default_type();
4845 if (dt == ARDOUR::DataType::AUDIO) {
4846 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4847 rtv->set_route (route);
4848 } else if (dt == ARDOUR::DataType::MIDI) {
4849 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4850 rtv->set_route (route);
4852 throw unknown_type();
4855 new_views.push_back (rtv);
4856 track_views.push_back (rtv);
4858 rtv->effective_gain_display ();
4860 if (internal_editing()) {
4861 rtv->enter_internal_edit_mode ();
4863 rtv->leave_internal_edit_mode ();
4866 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4867 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4870 _routes->routes_added (new_views);
4871 _summary->routes_added (new_views);
4873 if (show_editor_mixer_when_tracks_arrive) {
4874 show_editor_mixer (true);
4877 editor_list_button.set_sensitive (true);
4881 Editor::timeaxisview_deleted (TimeAxisView *tv)
4883 if (_session && _session->deletion_in_progress()) {
4884 /* the situation is under control */
4888 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4890 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4892 _routes->route_removed (tv);
4894 if (tv == entered_track) {
4898 TimeAxisView::Children c = tv->get_child_list ();
4899 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4900 if (entered_track == i->get()) {
4905 /* remove it from the list of track views */
4907 TrackViewList::iterator i;
4909 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4910 i = track_views.erase (i);
4913 /* update whatever the current mixer strip is displaying, if revelant */
4915 boost::shared_ptr<Route> route;
4918 route = rtav->route ();
4921 if (current_mixer_strip && current_mixer_strip->route() == route) {
4923 TimeAxisView* next_tv;
4925 if (track_views.empty()) {
4927 } else if (i == track_views.end()) {
4928 next_tv = track_views.front();
4935 set_selected_mixer_strip (*next_tv);
4937 /* make the editor mixer strip go away setting the
4938 * button to inactive (which also unticks the menu option)
4941 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4947 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4949 if (apply_to_selection) {
4950 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4952 TrackSelection::iterator j = i;
4955 hide_track_in_display (*i, false);
4960 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4962 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4963 // this will hide the mixer strip
4964 set_selected_mixer_strip (*tv);
4967 _routes->hide_track_in_display (*tv);
4972 Editor::sync_track_view_list_and_routes ()
4974 track_views = TrackViewList (_routes->views ());
4976 _summary->set_dirty ();
4977 _group_tabs->set_dirty ();
4979 return false; // do not call again (until needed)
4983 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4985 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4990 /** Find a RouteTimeAxisView by the ID of its route */
4992 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4994 RouteTimeAxisView* v;
4996 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4997 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4998 if(v->route()->id() == id) {
5008 Editor::fit_route_group (RouteGroup *g)
5010 TrackViewList ts = axis_views_from_routes (g->route_list ());
5015 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5017 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5020 _session->cancel_audition ();
5024 if (_session->is_auditioning()) {
5025 _session->cancel_audition ();
5026 if (r == last_audition_region) {
5031 _session->audition_region (r);
5032 last_audition_region = r;
5037 Editor::hide_a_region (boost::shared_ptr<Region> r)
5039 r->set_hidden (true);
5043 Editor::show_a_region (boost::shared_ptr<Region> r)
5045 r->set_hidden (false);
5049 Editor::audition_region_from_region_list ()
5051 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5055 Editor::hide_region_from_region_list ()
5057 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5061 Editor::show_region_in_region_list ()
5063 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5067 Editor::step_edit_status_change (bool yn)
5070 start_step_editing ();
5072 stop_step_editing ();
5077 Editor::start_step_editing ()
5079 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5083 Editor::stop_step_editing ()
5085 step_edit_connection.disconnect ();
5089 Editor::check_step_edit ()
5091 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5092 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5094 mtv->check_step_edit ();
5098 return true; // do it again, till we stop
5102 Editor::scroll_press (Direction dir)
5104 ++_scroll_callbacks;
5106 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5107 /* delay the first auto-repeat */
5113 scroll_backward (1);
5121 scroll_tracks_up_line ();
5125 scroll_tracks_down_line ();
5129 /* do hacky auto-repeat */
5130 if (!_scroll_connection.connected ()) {
5132 _scroll_connection = Glib::signal_timeout().connect (
5133 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5136 _scroll_callbacks = 0;
5143 Editor::scroll_release ()
5145 _scroll_connection.disconnect ();
5148 /** Queue a change for the Editor viewport x origin to follow the playhead */
5150 Editor::reset_x_origin_to_follow_playhead ()
5152 framepos_t const frame = playhead_cursor->current_frame;
5154 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5156 if (_session->transport_speed() < 0) {
5158 if (frame > (current_page_frames() / 2)) {
5159 center_screen (frame-(current_page_frames()/2));
5161 center_screen (current_page_frames()/2);
5166 if (frame < leftmost_frame) {
5169 if (_session->transport_rolling()) {
5170 /* rolling; end up with the playhead at the right of the page */
5171 l = frame - current_page_frames ();
5173 /* not rolling: end up with the playhead 3/4 of the way along the page */
5174 l = frame - (3 * current_page_frames() / 4);
5181 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5184 if (_session->transport_rolling()) {
5185 /* rolling: end up with the playhead on the left of the page */
5186 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5188 /* not rolling: end up with the playhead 1/4 of the way along the page */
5189 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5197 Editor::super_rapid_screen_update ()
5199 if (!_session || !_session->engine().running()) {
5203 /* METERING / MIXER STRIPS */
5205 /* update track meters, if required */
5206 if (is_mapped() && meters_running) {
5207 RouteTimeAxisView* rtv;
5208 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5209 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5210 rtv->fast_update ();
5215 /* and any current mixer strip */
5216 if (current_mixer_strip) {
5217 current_mixer_strip->fast_update ();
5220 /* PLAYHEAD AND VIEWPORT */
5222 framepos_t const frame = _session->audible_frame();
5224 /* There are a few reasons why we might not update the playhead / viewport stuff:
5226 * 1. we don't update things when there's a pending locate request, otherwise
5227 * when the editor requests a locate there is a chance that this method
5228 * will move the playhead before the locate request is processed, causing
5230 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5231 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5234 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5236 last_update_frame = frame;
5238 if (!_dragging_playhead) {
5239 playhead_cursor->set_position (frame);
5242 if (!_stationary_playhead) {
5244 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5245 reset_x_origin_to_follow_playhead ();
5250 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5254 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5255 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5256 if (target <= 0.0) {
5259 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5260 target = (target * 0.15) + (current * 0.85);
5266 set_horizontal_position (current);
5275 Editor::session_going_away ()
5277 _have_idled = false;
5279 _session_connections.drop_connections ();
5281 super_rapid_screen_update_connection.disconnect ();
5283 selection->clear ();
5284 cut_buffer->clear ();
5286 clicked_regionview = 0;
5287 clicked_axisview = 0;
5288 clicked_routeview = 0;
5289 clicked_crossfadeview = 0;
5290 entered_regionview = 0;
5292 last_update_frame = 0;
5295 playhead_cursor->canvas_item.hide ();
5297 /* rip everything out of the list displays */
5301 _route_groups->clear ();
5303 /* do this first so that deleting a track doesn't reset cms to null
5304 and thus cause a leak.
5307 if (current_mixer_strip) {
5308 if (current_mixer_strip->get_parent() != 0) {
5309 global_hpacker.remove (*current_mixer_strip);
5311 delete current_mixer_strip;
5312 current_mixer_strip = 0;
5315 /* delete all trackviews */
5317 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5320 track_views.clear ();
5322 zoom_range_clock->set_session (0);
5323 nudge_clock->set_session (0);
5325 editor_list_button.set_active(false);
5326 editor_list_button.set_sensitive(false);
5328 /* clear tempo/meter rulers */
5329 remove_metric_marks ();
5331 clear_marker_display ();
5333 current_bbt_points_begin = current_bbt_points_end;
5335 /* get rid of any existing editor mixer strip */
5337 WindowTitle title(Glib::get_application_name());
5338 title += _("Editor");
5340 set_title (title.get_string());
5342 SessionHandlePtr::session_going_away ();
5347 Editor::show_editor_list (bool yn)
5350 _the_notebook.show ();
5352 _the_notebook.hide ();
5357 Editor::change_region_layering_order (bool from_context_menu)
5359 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5361 if (!clicked_routeview) {
5362 if (layering_order_editor) {
5363 layering_order_editor->hide ();
5368 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5374 boost::shared_ptr<Playlist> pl = track->playlist();
5380 if (layering_order_editor == 0) {
5381 layering_order_editor = new RegionLayeringOrderEditor (*this);
5382 layering_order_editor->set_position (WIN_POS_MOUSE);
5385 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5386 layering_order_editor->maybe_present ();
5390 Editor::update_region_layering_order_editor ()
5392 if (layering_order_editor && layering_order_editor->is_visible ()) {
5393 change_region_layering_order (true);
5398 Editor::setup_fade_images ()
5400 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5401 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5402 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5403 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5404 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5406 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5407 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5408 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5409 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5410 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5414 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5416 Editor::action_menu_item (std::string const & name)
5418 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5421 return *manage (a->create_menu_item ());
5425 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5427 EventBox* b = manage (new EventBox);
5428 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5429 Label* l = manage (new Label (name));
5433 _the_notebook.append_page (widget, *b);
5437 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5439 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5440 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5443 if (ev->type == GDK_2BUTTON_PRESS) {
5445 /* double-click on a notebook tab shrinks or expands the notebook */
5447 if (_notebook_shrunk) {
5448 edit_pane.set_position (pre_maximal_horizontal_pane_position);
5449 _notebook_shrunk = false;
5451 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
5452 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5453 _notebook_shrunk = true;
5461 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5463 using namespace Menu_Helpers;
5465 MenuList& items = _control_point_context_menu.items ();
5468 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5469 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5470 if (!can_remove_control_point (item)) {
5471 items.back().set_sensitive (false);
5474 _control_point_context_menu.popup (event->button.button, event->button.time);