2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
48 #include <glibmm/miscutils.h>
49 #include <gtkmm/image.h>
50 #include <gdkmm/color.h>
51 #include <gdkmm/bitmap.h>
53 #include "gtkmm2ext/bindings.h"
54 #include "gtkmm2ext/grouped_buttons.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/tearoff.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/window_title.h"
59 #include "gtkmm2ext/choice.h"
60 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioengine.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/profile.h"
67 #include "ardour/route_group.h"
68 #include "ardour/session_playlists.h"
69 #include "ardour/tempo.h"
70 #include "ardour/utils.h"
72 #include "control_protocol/control_protocol.h"
76 #include "analysis_window.h"
77 #include "audio_clock.h"
78 #include "audio_region_view.h"
79 #include "audio_streamview.h"
80 #include "audio_time_axis.h"
81 #include "automation_time_axis.h"
82 #include "bundle_manager.h"
83 #include "button_joiner.h"
84 #include "canvas-noevent-text.h"
85 #include "canvas_impl.h"
86 #include "crossfade_edit.h"
90 #include "editor_cursors.h"
91 #include "editor_drag.h"
92 #include "editor_group_tabs.h"
93 #include "editor_locations.h"
94 #include "editor_regions.h"
95 #include "editor_route_groups.h"
96 #include "editor_routes.h"
97 #include "editor_snapshots.h"
98 #include "editor_summary.h"
99 #include "global_port_matrix.h"
100 #include "gui_object.h"
101 #include "gui_thread.h"
102 #include "keyboard.h"
104 #include "midi_time_axis.h"
105 #include "mixer_strip.h"
106 #include "mixer_ui.h"
107 #include "mouse_cursors.h"
108 #include "playlist_selector.h"
109 #include "public_editor.h"
110 #include "region_layering_order_editor.h"
111 #include "rgb_macros.h"
112 #include "rhythm_ferret.h"
113 #include "selection.h"
115 #include "simpleline.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
238 /* time display buttons */
239 , minsec_label (_("Mins:Secs"))
240 , bbt_label (_("Bars:Beats"))
241 , timecode_label (_("Timecode"))
242 , samples_label (_("Samples"))
243 , tempo_label (_("Tempo"))
244 , meter_label (_("Meter"))
245 , mark_label (_("Location Markers"))
246 , range_mark_label (_("Range Markers"))
247 , transport_mark_label (_("Loop/Punch Ranges"))
248 , cd_mark_label (_("CD Markers"))
249 , edit_packer (4, 4, true)
251 /* the values here don't matter: layout widgets
252 reset them as needed.
255 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
257 /* tool bar related */
259 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
261 , toolbar_selection_clock_table (2,3)
263 , automation_mode_button (_("mode"))
265 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
268 , image_socket_listener(0)
273 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
274 , meters_running(false)
275 , _pending_locate_request (false)
276 , _pending_initial_locate (false)
277 , _last_cut_copy_source_track (0)
279 , _region_selection_change_updates_region_list (true)
280 , _following_mixer_selection (false)
281 , _control_point_toggled_on_press (false)
282 , _stepping_axis_view (0)
286 /* we are a singleton */
288 PublicEditor::_instance = this;
292 selection = new Selection (this);
293 cut_buffer = new Selection (this);
295 clicked_regionview = 0;
296 clicked_axisview = 0;
297 clicked_routeview = 0;
298 clicked_control_point = 0;
299 last_update_frame = 0;
300 pre_press_cursor = 0;
301 _drags = new DragManager (this);
302 current_mixer_strip = 0;
305 snap_type_strings = I18N (_snap_type_strings);
306 snap_mode_strings = I18N (_snap_mode_strings);
307 zoom_focus_strings = I18N (_zoom_focus_strings);
308 edit_point_strings = I18N (_edit_point_strings);
309 #ifdef USE_RUBBERBAND
310 rb_opt_strings = I18N (_rb_opt_strings);
314 snap_threshold = 5.0;
315 bbt_beat_subdivision = 4;
318 last_autoscroll_x = 0;
319 last_autoscroll_y = 0;
320 autoscroll_active = false;
321 autoscroll_timeout_tag = -1;
326 current_interthread_info = 0;
327 _show_measures = true;
329 show_gain_after_trim = false;
331 have_pending_keyboard_selection = false;
332 _follow_playhead = true;
333 _stationary_playhead = false;
334 editor_ruler_menu = 0;
335 no_ruler_shown_update = false;
337 range_marker_menu = 0;
338 marker_menu_item = 0;
339 tempo_or_meter_marker_menu = 0;
340 transport_marker_menu = 0;
341 new_transport_marker_menu = 0;
342 editor_mixer_strip_width = Wide;
343 show_editor_mixer_when_tracks_arrive = false;
344 region_edit_menu_split_multichannel_item = 0;
345 region_edit_menu_split_item = 0;
348 current_stepping_trackview = 0;
350 entered_regionview = 0;
352 clear_entered_track = false;
355 button_release_can_deselect = true;
356 _dragging_playhead = false;
357 _dragging_edit_point = false;
358 select_new_marker = false;
360 layering_order_editor = 0;
361 no_save_visual = false;
363 within_track_canvas = false;
365 scrubbing_direction = 0;
369 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
370 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
371 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
372 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
373 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
375 _edit_point = EditAtMouse;
376 _internal_editing = false;
377 current_canvas_cursor = 0;
379 frames_per_unit = 2048; /* too early to use reset_zoom () */
381 _scroll_callbacks = 0;
383 zoom_focus = ZoomFocusLeft;
384 set_zoom_focus (ZoomFocusLeft);
385 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
387 bbt_label.set_name ("EditorTimeButton");
388 bbt_label.set_size_request (-1, (int)timebar_height);
389 bbt_label.set_alignment (1.0, 0.5);
390 bbt_label.set_padding (5,0);
392 bbt_label.set_no_show_all();
393 minsec_label.set_name ("EditorTimeButton");
394 minsec_label.set_size_request (-1, (int)timebar_height);
395 minsec_label.set_alignment (1.0, 0.5);
396 minsec_label.set_padding (5,0);
397 minsec_label.hide ();
398 minsec_label.set_no_show_all();
399 timecode_label.set_name ("EditorTimeButton");
400 timecode_label.set_size_request (-1, (int)timebar_height);
401 timecode_label.set_alignment (1.0, 0.5);
402 timecode_label.set_padding (5,0);
403 timecode_label.hide ();
404 timecode_label.set_no_show_all();
405 samples_label.set_name ("EditorTimeButton");
406 samples_label.set_size_request (-1, (int)timebar_height);
407 samples_label.set_alignment (1.0, 0.5);
408 samples_label.set_padding (5,0);
409 samples_label.hide ();
410 samples_label.set_no_show_all();
412 tempo_label.set_name ("EditorTimeButton");
413 tempo_label.set_size_request (-1, (int)timebar_height);
414 tempo_label.set_alignment (1.0, 0.5);
415 tempo_label.set_padding (5,0);
417 tempo_label.set_no_show_all();
419 meter_label.set_name ("EditorTimeButton");
420 meter_label.set_size_request (-1, (int)timebar_height);
421 meter_label.set_alignment (1.0, 0.5);
422 meter_label.set_padding (5,0);
424 meter_label.set_no_show_all();
426 mark_label.set_name ("EditorTimeButton");
427 mark_label.set_size_request (-1, (int)timebar_height);
428 mark_label.set_alignment (1.0, 0.5);
429 mark_label.set_padding (5,0);
431 mark_label.set_no_show_all();
433 cd_mark_label.set_name ("EditorTimeButton");
434 cd_mark_label.set_size_request (-1, (int)timebar_height);
435 cd_mark_label.set_alignment (1.0, 0.5);
436 cd_mark_label.set_padding (5,0);
437 cd_mark_label.hide();
438 cd_mark_label.set_no_show_all();
440 range_mark_label.set_name ("EditorTimeButton");
441 range_mark_label.set_size_request (-1, (int)timebar_height);
442 range_mark_label.set_alignment (1.0, 0.5);
443 range_mark_label.set_padding (5,0);
444 range_mark_label.hide();
445 range_mark_label.set_no_show_all();
447 transport_mark_label.set_name ("EditorTimeButton");
448 transport_mark_label.set_size_request (-1, (int)timebar_height);
449 transport_mark_label.set_alignment (1.0, 0.5);
450 transport_mark_label.set_padding (5,0);
451 transport_mark_label.hide();
452 transport_mark_label.set_no_show_all();
454 initialize_rulers ();
455 initialize_canvas ();
457 _summary = new EditorSummary (this);
459 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
460 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
462 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
464 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
465 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
467 edit_controls_vbox.set_spacing (0);
468 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
469 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
471 HBox* h = manage (new HBox);
472 _group_tabs = new EditorGroupTabs (this);
473 h->pack_start (*_group_tabs, PACK_SHRINK);
474 h->pack_start (edit_controls_vbox);
475 controls_layout.add (*h);
477 controls_layout.set_name ("EditControlsBase");
478 controls_layout.add_events (Gdk::SCROLL_MASK);
479 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
481 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
482 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
484 _cursors = new MouseCursors;
486 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
487 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
488 0.0, 1.0, 100.0, 1.0));
490 pad_line_1->property_color_rgba() = 0xFF0000FF;
495 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
496 time_canvas_vbox.set_size_request (-1, -1);
498 ruler_label_event_box.add (ruler_label_vbox);
499 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
500 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
502 time_button_event_box.add (time_button_vbox);
503 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
504 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
506 /* these enable us to have a dedicated window (for cursor setting, etc.)
507 for the canvas areas.
510 track_canvas_event_box.add (*track_canvas);
512 time_canvas_event_box.add (time_canvas_vbox);
513 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
515 edit_packer.set_col_spacings (0);
516 edit_packer.set_row_spacings (0);
517 edit_packer.set_homogeneous (false);
518 edit_packer.set_border_width (0);
519 edit_packer.set_name ("EditorWindow");
521 /* labels for the rulers */
522 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
523 /* labels for the marker "tracks" */
524 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
526 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
528 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
530 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
532 bottom_hbox.set_border_width (2);
533 bottom_hbox.set_spacing (3);
535 _route_groups = new EditorRouteGroups (this);
536 _routes = new EditorRoutes (this);
537 _regions = new EditorRegions (this);
538 _snapshots = new EditorSnapshots (this);
539 _locations = new EditorLocations (this);
541 add_notebook_page (_("Regions"), _regions->widget ());
542 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
543 add_notebook_page (_("Snapshots"), _snapshots->widget ());
544 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
545 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
547 _the_notebook.set_show_tabs (true);
548 _the_notebook.set_scrollable (true);
549 _the_notebook.popup_disable ();
550 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
551 _the_notebook.show_all ();
553 _notebook_shrunk = false;
555 editor_summary_pane.pack1(edit_packer);
557 Button* summary_arrows_left_left = manage (new Button);
558 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
559 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
560 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
562 Button* summary_arrows_left_right = manage (new Button);
563 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
564 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
565 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
567 VBox* summary_arrows_left = manage (new VBox);
568 summary_arrows_left->pack_start (*summary_arrows_left_left);
569 summary_arrows_left->pack_start (*summary_arrows_left_right);
571 Button* summary_arrows_right_up = manage (new Button);
572 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
573 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
574 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 Button* summary_arrows_right_down = manage (new Button);
577 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
578 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
579 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
581 VBox* summary_arrows_right = manage (new VBox);
582 summary_arrows_right->pack_start (*summary_arrows_right_up);
583 summary_arrows_right->pack_start (*summary_arrows_right_down);
585 Frame* summary_frame = manage (new Frame);
586 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
588 summary_frame->add (*_summary);
589 summary_frame->show ();
591 _summary_hbox.pack_start (*summary_arrows_left, false, false);
592 _summary_hbox.pack_start (*summary_frame, true, true);
593 _summary_hbox.pack_start (*summary_arrows_right, false, false);
595 editor_summary_pane.pack2 (_summary_hbox);
597 edit_pane.pack1 (editor_summary_pane, true, true);
598 edit_pane.pack2 (_the_notebook, false, true);
600 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
602 /* XXX: editor_summary_pane might need similar to the edit_pane */
604 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
606 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
607 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
609 top_hbox.pack_start (toolbar_frame);
611 HBox *hbox = manage (new HBox);
612 hbox->pack_start (edit_pane, true, true);
614 global_vpacker.pack_start (top_hbox, false, false);
615 global_vpacker.pack_start (*hbox, true, true);
617 global_hpacker.pack_start (global_vpacker, true, true);
619 set_name ("EditorWindow");
620 add_accel_group (ActionManager::ui_manager->get_accel_group());
622 status_bar_hpacker.show ();
624 vpacker.pack_end (status_bar_hpacker, false, false);
625 vpacker.pack_end (global_hpacker, true, true);
627 /* register actions now so that set_state() can find them and set toggles/checks etc */
630 /* when we start using our own keybinding system for the editor, this
631 * will be uncommented
637 _snap_type = SnapToBeat;
638 set_snap_to (_snap_type);
639 _snap_mode = SnapOff;
640 set_snap_mode (_snap_mode);
641 set_mouse_mode (MouseObject, true);
642 pre_internal_mouse_mode = MouseObject;
643 pre_internal_snap_type = _snap_type;
644 pre_internal_snap_mode = _snap_mode;
645 internal_snap_type = _snap_type;
646 internal_snap_mode = _snap_mode;
647 set_edit_point_preference (EditAtMouse, true);
649 _playlist_selector = new PlaylistSelector();
650 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
652 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
656 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
657 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
659 nudge_forward_button.set_name ("TransportButton");
660 nudge_backward_button.set_name ("TransportButton");
662 fade_context_menu.set_name ("ArdourContextMenu");
664 /* icons, titles, WM stuff */
666 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
667 Glib::RefPtr<Gdk::Pixbuf> icon;
669 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
670 window_icons.push_back (icon);
672 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
673 window_icons.push_back (icon);
675 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
676 window_icons.push_back (icon);
678 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
679 window_icons.push_back (icon);
681 if (!window_icons.empty()) {
682 // set_icon_list (window_icons);
683 set_default_icon_list (window_icons);
686 WindowTitle title(Glib::get_application_name());
687 title += _("Editor");
688 set_title (title.get_string());
689 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
692 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
694 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
695 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
697 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
699 /* allow external control surfaces/protocols to do various things */
701 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
702 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
703 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
704 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
705 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
706 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
707 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
708 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
709 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
710 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
711 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
712 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
713 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
714 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
716 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
717 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
718 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
719 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
720 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
722 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
724 /* problematic: has to return a value and thus cannot be x-thread */
726 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
728 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
730 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
732 _ignore_region_action = false;
733 _last_region_menu_was_main = false;
734 _popup_region_menu_item = 0;
736 _show_marker_lines = false;
737 _over_region_trim_target = false;
739 /* Button bindings */
741 button_bindings = new Bindings;
743 XMLNode* node = button_settings();
745 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
746 button_bindings->load (**i);
753 setup_fade_images ();
759 if(image_socket_listener) {
760 if(image_socket_listener->is_connected())
762 image_socket_listener->close_connection() ;
765 delete image_socket_listener ;
766 image_socket_listener = 0 ;
770 delete button_bindings;
772 delete _route_groups;
778 Editor::button_settings () const
780 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
781 XMLNode* node = find_named_node (*settings, X_("Buttons"));
784 node = new XMLNode (X_("Buttons"));
791 Editor::add_toplevel_controls (Container& cont)
793 vpacker.pack_start (cont, false, false);
798 Editor::catch_vanishing_regionview (RegionView *rv)
800 /* note: the selection will take care of the vanishing
801 audioregionview by itself.
804 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
808 if (clicked_regionview == rv) {
809 clicked_regionview = 0;
812 if (entered_regionview == rv) {
813 set_entered_regionview (0);
816 if (!_all_region_actions_sensitized) {
817 sensitize_all_region_actions (true);
820 _over_region_trim_target = false;
824 Editor::set_entered_regionview (RegionView* rv)
826 if (rv == entered_regionview) {
830 if (entered_regionview) {
831 entered_regionview->exited ();
834 if ((entered_regionview = rv) != 0) {
835 entered_regionview->entered (internal_editing ());
838 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
839 /* This RegionView entry might have changed what region actions
840 are allowed, so sensitize them all in case a key is pressed.
842 sensitize_all_region_actions (true);
847 Editor::set_entered_track (TimeAxisView* tav)
850 entered_track->exited ();
853 if ((entered_track = tav) != 0) {
854 entered_track->entered ();
859 Editor::show_window ()
861 if (!is_visible ()) {
864 /* XXX: this is a bit unfortunate; it would probably
865 be nicer if we could just call show () above rather
866 than needing the show_all ()
869 /* re-hide stuff if necessary */
870 editor_list_button_toggled ();
871 parameter_changed ("show-summary");
872 parameter_changed ("show-group-tabs");
873 parameter_changed ("show-zoom-tools");
875 /* now reset all audio_time_axis heights, because widgets might need
881 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
882 tv = (static_cast<TimeAxisView*>(*i));
886 if (current_mixer_strip) {
887 current_mixer_strip->hide_things ();
888 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
896 Editor::instant_save ()
898 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
903 _session->add_instant_xml(get_state());
905 Config->add_instant_xml(get_state());
910 Editor::zoom_adjustment_changed ()
916 double fpu = zoom_range_clock->current_duration() / _canvas_width;
917 bool clamped = clamp_frames_per_unit (fpu);
920 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
927 Editor::control_vertical_zoom_in_all ()
929 tav_zoom_smooth (false, true);
933 Editor::control_vertical_zoom_out_all ()
935 tav_zoom_smooth (true, true);
939 Editor::control_vertical_zoom_in_selected ()
941 tav_zoom_smooth (false, false);
945 Editor::control_vertical_zoom_out_selected ()
947 tav_zoom_smooth (true, false);
951 Editor::control_view (uint32_t view)
953 goto_visual_state (view);
957 Editor::control_unselect ()
959 selection->clear_tracks ();
963 Editor::control_select (uint32_t rid, Selection::Operation op)
965 /* handles the (static) signal from the ControlProtocol class that
966 * requests setting the selected track to a given RID
973 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
979 TimeAxisView* tav = axis_view_from_route (r);
984 selection->add (tav);
986 case Selection::Toggle:
987 selection->toggle (tav);
989 case Selection::Extend:
992 selection->set (tav);
996 selection->clear_tracks ();
1001 Editor::control_step_tracks_up ()
1003 scroll_tracks_up_line ();
1007 Editor::control_step_tracks_down ()
1009 scroll_tracks_down_line ();
1013 Editor::control_scroll (float fraction)
1015 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1021 double step = fraction * current_page_frames();
1024 _control_scroll_target is an optional<T>
1026 it acts like a pointer to an framepos_t, with
1027 a operator conversion to boolean to check
1028 that it has a value could possibly use
1029 playhead_cursor->current_frame to store the
1030 value and a boolean in the class to know
1031 when it's out of date
1034 if (!_control_scroll_target) {
1035 _control_scroll_target = _session->transport_frame();
1036 _dragging_playhead = true;
1039 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1040 *_control_scroll_target = 0;
1041 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1042 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1044 *_control_scroll_target += (framepos_t) floor (step);
1047 /* move visuals, we'll catch up with it later */
1049 playhead_cursor->set_position (*_control_scroll_target);
1050 UpdateAllTransportClocks (*_control_scroll_target);
1052 if (*_control_scroll_target > (current_page_frames() / 2)) {
1053 /* try to center PH in window */
1054 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1060 Now we do a timeout to actually bring the session to the right place
1061 according to the playhead. This is to avoid reading disk buffers on every
1062 call to control_scroll, which is driven by ScrollTimeline and therefore
1063 probably by a control surface wheel which can generate lots of events.
1065 /* cancel the existing timeout */
1067 control_scroll_connection.disconnect ();
1069 /* add the next timeout */
1071 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1075 Editor::deferred_control_scroll (framepos_t /*target*/)
1077 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1078 // reset for next stream
1079 _control_scroll_target = boost::none;
1080 _dragging_playhead = false;
1085 Editor::access_action (std::string action_group, std::string action_item)
1091 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1094 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1102 Editor::on_realize ()
1104 Window::on_realize ();
1109 Editor::map_position_change (framepos_t frame)
1111 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1113 if (_session == 0) {
1117 if (_follow_playhead) {
1118 center_screen (frame);
1121 playhead_cursor->set_position (frame);
1125 Editor::center_screen (framepos_t frame)
1127 double page = _canvas_width * frames_per_unit;
1129 /* if we're off the page, then scroll.
1132 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1133 center_screen_internal (frame, page);
1138 Editor::center_screen_internal (framepos_t frame, float page)
1143 frame -= (framepos_t) page;
1148 reset_x_origin (frame);
1153 Editor::update_title ()
1155 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1158 bool dirty = _session->dirty();
1160 string session_name;
1162 if (_session->snap_name() != _session->name()) {
1163 session_name = _session->snap_name();
1165 session_name = _session->name();
1169 session_name = "*" + session_name;
1172 WindowTitle title(session_name);
1173 title += Glib::get_application_name();
1174 set_title (title.get_string());
1176 /* ::session_going_away() will have taken care of it */
1181 Editor::set_session (Session *t)
1183 SessionHandlePtr::set_session (t);
1189 zoom_range_clock->set_session (_session);
1190 _playlist_selector->set_session (_session);
1191 nudge_clock->set_session (_session);
1192 _summary->set_session (_session);
1193 _group_tabs->set_session (_session);
1194 _route_groups->set_session (_session);
1195 _regions->set_session (_session);
1196 _snapshots->set_session (_session);
1197 _routes->set_session (_session);
1198 _locations->set_session (_session);
1200 if (rhythm_ferret) {
1201 rhythm_ferret->set_session (_session);
1204 if (analysis_window) {
1205 analysis_window->set_session (_session);
1209 sfbrowser->set_session (_session);
1212 compute_fixed_ruler_scale ();
1214 /* Make sure we have auto loop and auto punch ranges */
1216 Location* loc = _session->locations()->auto_loop_location();
1218 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1220 if (loc->start() == loc->end()) {
1221 loc->set_end (loc->start() + 1);
1224 _session->locations()->add (loc, false);
1225 _session->set_auto_loop_location (loc);
1228 loc->set_name (_("Loop"));
1231 loc = _session->locations()->auto_punch_location();
1234 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1236 if (loc->start() == loc->end()) {
1237 loc->set_end (loc->start() + 1);
1240 _session->locations()->add (loc, false);
1241 _session->set_auto_punch_location (loc);
1244 loc->set_name (_("Punch"));
1247 refresh_location_display ();
1249 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1250 the selected Marker; this needs the LocationMarker list to be available.
1252 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1253 set_state (*node, Stateful::loading_state_version);
1255 /* catch up with the playhead */
1257 _session->request_locate (playhead_cursor->current_frame);
1258 _pending_initial_locate = true;
1262 /* These signals can all be emitted by a non-GUI thread. Therefore the
1263 handlers for them must not attempt to directly interact with the GUI,
1264 but use Gtkmm2ext::UI::instance()->call_slot();
1267 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1268 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1269 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1270 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1271 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1272 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1273 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1274 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1275 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1276 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1277 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1278 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1279 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1280 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1282 playhead_cursor->canvas_item.show ();
1284 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1285 Config->map_parameters (pc);
1286 _session->config.map_parameters (pc);
1288 restore_ruler_visibility ();
1289 //tempo_map_changed (PropertyChange (0));
1290 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1292 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1293 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1296 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1297 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1300 switch (_snap_type) {
1301 case SnapToRegionStart:
1302 case SnapToRegionEnd:
1303 case SnapToRegionSync:
1304 case SnapToRegionBoundary:
1305 build_region_boundary_cache ();
1312 /* register for undo history */
1313 _session->register_with_memento_command_factory(id(), this);
1315 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1317 start_updating_meters ();
1321 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1323 if (a->get_name() == "RegionMenu") {
1324 /* When the main menu's region menu is opened, we setup the actions so that they look right
1325 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1326 so we resensitize all region actions when the entered regionview or the region selection
1327 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1328 happens after the region context menu is opened. So we set a flag here, too.
1332 sensitize_the_right_region_actions ();
1333 _last_region_menu_was_main = true;
1338 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1340 using namespace Menu_Helpers;
1342 void (Editor::*emf)(FadeShape);
1343 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1346 images = &_xfade_in_images;
1347 emf = &Editor::set_fade_in_shape;
1349 images = &_xfade_out_images;
1350 emf = &Editor::set_fade_out_shape;
1355 _("Linear (for highly correlated material)"),
1356 *(*images)[FadeLinear],
1357 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1361 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1366 *(*images)[FadeConstantPower],
1367 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1370 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1375 *(*images)[FadeSymmetric],
1376 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1380 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1385 *(*images)[FadeSlow],
1386 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1389 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1394 *(*images)[FadeFast],
1395 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1398 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1401 /** Pop up a context menu for when the user clicks on a start crossfade */
1403 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1405 using namespace Menu_Helpers;
1407 MenuList& items (xfade_in_context_menu.items());
1409 if (items.empty()) {
1410 fill_xfade_menu (items, true);
1413 xfade_in_context_menu.popup (button, time);
1416 /** Pop up a context menu for when the user clicks on an end crossfade */
1418 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1420 using namespace Menu_Helpers;
1422 MenuList& items (xfade_out_context_menu.items());
1424 if (items.empty()) {
1425 fill_xfade_menu (items, false);
1428 xfade_out_context_menu.popup (button, time);
1432 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1434 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1436 using namespace Menu_Helpers;
1437 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1440 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1444 MenuList& items (fade_context_menu.items());
1447 switch (item_type) {
1449 case FadeInHandleItem:
1450 if (arv->audio_region()->fade_in_active()) {
1451 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1453 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1456 items.push_back (SeparatorElem());
1458 if (Profile->get_sae()) {
1460 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1461 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1468 *_fade_in_images[FadeLinear],
1469 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *_fade_in_images[FadeSlow],
1479 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *_fade_in_images[FadeFast],
1488 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1496 *_fade_in_images[FadeSymmetric],
1497 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1502 _("Constant Power"),
1503 *_fade_in_images[FadeConstantPower],
1504 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1507 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 case FadeOutHandleItem:
1514 if (arv->audio_region()->fade_out_active()) {
1515 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1517 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1520 items.push_back (SeparatorElem());
1522 if (Profile->get_sae()) {
1523 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1524 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1530 *_fade_out_images[FadeLinear],
1531 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1535 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1540 *_fade_out_images[FadeSlow],
1541 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1544 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1549 *_fade_out_images[FadeFast],
1550 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1553 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1558 *_fade_out_images[FadeSymmetric],
1559 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1564 _("Constant Power"),
1565 *_fade_out_images[FadeConstantPower],
1566 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1569 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1575 fatal << _("programming error: ")
1576 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1581 fade_context_menu.popup (button, time);
1585 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1587 using namespace Menu_Helpers;
1588 Menu* (Editor::*build_menu_function)();
1591 switch (item_type) {
1593 case RegionViewName:
1594 case RegionViewNameHighlight:
1595 case LeftFrameHandle:
1596 case RightFrameHandle:
1597 if (with_selection) {
1598 build_menu_function = &Editor::build_track_selection_context_menu;
1600 build_menu_function = &Editor::build_track_region_context_menu;
1605 if (with_selection) {
1606 build_menu_function = &Editor::build_track_selection_context_menu;
1608 build_menu_function = &Editor::build_track_context_menu;
1613 if (clicked_routeview->track()) {
1614 build_menu_function = &Editor::build_track_context_menu;
1616 build_menu_function = &Editor::build_track_bus_context_menu;
1621 /* probably shouldn't happen but if it does, we don't care */
1625 menu = (this->*build_menu_function)();
1626 menu->set_name ("ArdourContextMenu");
1628 /* now handle specific situations */
1630 switch (item_type) {
1632 case RegionViewName:
1633 case RegionViewNameHighlight:
1634 case LeftFrameHandle:
1635 case RightFrameHandle:
1636 if (!with_selection) {
1637 if (region_edit_menu_split_item) {
1638 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1639 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1641 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1644 if (region_edit_menu_split_multichannel_item) {
1645 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1646 region_edit_menu_split_multichannel_item->set_sensitive (true);
1648 region_edit_menu_split_multichannel_item->set_sensitive (false);
1661 /* probably shouldn't happen but if it does, we don't care */
1665 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1667 /* Bounce to disk */
1669 using namespace Menu_Helpers;
1670 MenuList& edit_items = menu->items();
1672 edit_items.push_back (SeparatorElem());
1674 switch (clicked_routeview->audio_track()->freeze_state()) {
1675 case AudioTrack::NoFreeze:
1676 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1679 case AudioTrack::Frozen:
1680 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1683 case AudioTrack::UnFrozen:
1684 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1690 if (item_type == StreamItem && clicked_routeview) {
1691 clicked_routeview->build_underlay_menu(menu);
1694 /* When the region menu is opened, we setup the actions so that they look right
1697 sensitize_the_right_region_actions ();
1698 _last_region_menu_was_main = false;
1700 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1701 menu->popup (button, time);
1705 Editor::build_track_context_menu ()
1707 using namespace Menu_Helpers;
1709 MenuList& edit_items = track_context_menu.items();
1712 add_dstream_context_items (edit_items);
1713 return &track_context_menu;
1717 Editor::build_track_bus_context_menu ()
1719 using namespace Menu_Helpers;
1721 MenuList& edit_items = track_context_menu.items();
1724 add_bus_context_items (edit_items);
1725 return &track_context_menu;
1729 Editor::build_track_region_context_menu ()
1731 using namespace Menu_Helpers;
1732 MenuList& edit_items = track_region_context_menu.items();
1735 /* we've just cleared the track region context menu, so the menu that these
1736 two items were on will have disappeared; stop them dangling.
1738 region_edit_menu_split_item = 0;
1739 region_edit_menu_split_multichannel_item = 0;
1741 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1744 boost::shared_ptr<Track> tr;
1745 boost::shared_ptr<Playlist> pl;
1747 if ((tr = rtv->track())) {
1748 add_region_context_items (edit_items, tr);
1752 add_dstream_context_items (edit_items);
1754 return &track_region_context_menu;
1758 Editor::analyze_region_selection ()
1760 if (analysis_window == 0) {
1761 analysis_window = new AnalysisWindow();
1764 analysis_window->set_session(_session);
1766 analysis_window->show_all();
1769 analysis_window->set_regionmode();
1770 analysis_window->analyze();
1772 analysis_window->present();
1776 Editor::analyze_range_selection()
1778 if (analysis_window == 0) {
1779 analysis_window = new AnalysisWindow();
1782 analysis_window->set_session(_session);
1784 analysis_window->show_all();
1787 analysis_window->set_rangemode();
1788 analysis_window->analyze();
1790 analysis_window->present();
1794 Editor::build_track_selection_context_menu ()
1796 using namespace Menu_Helpers;
1797 MenuList& edit_items = track_selection_context_menu.items();
1798 edit_items.clear ();
1800 add_selection_context_items (edit_items);
1801 // edit_items.push_back (SeparatorElem());
1802 // add_dstream_context_items (edit_items);
1804 return &track_selection_context_menu;
1808 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1810 using namespace Menu_Helpers;
1812 /* OK, stick the region submenu at the top of the list, and then add
1816 RegionSelection rs = get_regions_from_selection_and_entered ();
1818 string::size_type pos = 0;
1819 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1821 /* we have to hack up the region name because "_" has a special
1822 meaning for menu titles.
1825 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1826 menu_item_name.replace (pos, 1, "__");
1830 if (_popup_region_menu_item == 0) {
1831 _popup_region_menu_item = new MenuItem (menu_item_name);
1832 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1833 _popup_region_menu_item->show ();
1835 _popup_region_menu_item->set_label (menu_item_name);
1838 const framepos_t position = get_preferred_edit_position (false, true);
1840 edit_items.push_back (*_popup_region_menu_item);
1841 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1842 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1844 edit_items.push_back (SeparatorElem());
1847 /** Add context menu items relevant to selection ranges.
1848 * @param edit_items List to add the items to.
1851 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1853 using namespace Menu_Helpers;
1855 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1856 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1861 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (
1865 _("Move Range Start to Previous Region Boundary"),
1866 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1870 edit_items.push_back (
1872 _("Move Range Start to Next Region Boundary"),
1873 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1877 edit_items.push_back (
1879 _("Move Range End to Previous Region Boundary"),
1880 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1884 edit_items.push_back (
1886 _("Move Range End to Next Region Boundary"),
1887 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1891 edit_items.push_back (SeparatorElem());
1892 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1893 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1895 edit_items.push_back (SeparatorElem());
1896 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1898 edit_items.push_back (SeparatorElem());
1899 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1900 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1905 edit_items.push_back (SeparatorElem());
1906 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1907 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1908 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1910 edit_items.push_back (SeparatorElem());
1911 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1912 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1913 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1914 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1915 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1920 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1922 using namespace Menu_Helpers;
1926 Menu *play_menu = manage (new Menu);
1927 MenuList& play_items = play_menu->items();
1928 play_menu->set_name ("ArdourContextMenu");
1930 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1931 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1932 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1933 play_items.push_back (SeparatorElem());
1934 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1936 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1940 Menu *select_menu = manage (new Menu);
1941 MenuList& select_items = select_menu->items();
1942 select_menu->set_name ("ArdourContextMenu");
1944 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1945 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1946 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1947 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1948 select_items.push_back (SeparatorElem());
1949 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1950 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1951 select_items.push_back (SeparatorElem());
1952 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1953 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1954 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1955 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1956 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1957 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1958 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1960 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1964 Menu *cutnpaste_menu = manage (new Menu);
1965 MenuList& cutnpaste_items = cutnpaste_menu->items();
1966 cutnpaste_menu->set_name ("ArdourContextMenu");
1968 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1969 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1970 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1972 cutnpaste_items.push_back (SeparatorElem());
1974 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1975 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1977 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1979 /* Adding new material */
1981 edit_items.push_back (SeparatorElem());
1982 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1983 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1987 Menu *nudge_menu = manage (new Menu());
1988 MenuList& nudge_items = nudge_menu->items();
1989 nudge_menu->set_name ("ArdourContextMenu");
1991 edit_items.push_back (SeparatorElem());
1992 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1993 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1994 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1995 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1997 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2001 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2003 using namespace Menu_Helpers;
2007 Menu *play_menu = manage (new Menu);
2008 MenuList& play_items = play_menu->items();
2009 play_menu->set_name ("ArdourContextMenu");
2011 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2012 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2013 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2017 Menu *select_menu = manage (new Menu);
2018 MenuList& select_items = select_menu->items();
2019 select_menu->set_name ("ArdourContextMenu");
2021 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2022 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2023 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2024 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2025 select_items.push_back (SeparatorElem());
2026 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2027 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2028 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2029 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2031 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2035 Menu *cutnpaste_menu = manage (new Menu);
2036 MenuList& cutnpaste_items = cutnpaste_menu->items();
2037 cutnpaste_menu->set_name ("ArdourContextMenu");
2039 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2040 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2041 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2043 Menu *nudge_menu = manage (new Menu());
2044 MenuList& nudge_items = nudge_menu->items();
2045 nudge_menu->set_name ("ArdourContextMenu");
2047 edit_items.push_back (SeparatorElem());
2048 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2049 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2050 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2051 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2053 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2057 Editor::snap_type() const
2063 Editor::snap_mode() const
2069 Editor::set_snap_to (SnapType st)
2071 unsigned int snap_ind = (unsigned int)st;
2075 if (snap_ind > snap_type_strings.size() - 1) {
2077 _snap_type = (SnapType)snap_ind;
2080 string str = snap_type_strings[snap_ind];
2082 if (str != snap_type_selector.get_active_text()) {
2083 snap_type_selector.set_active_text (str);
2088 switch (_snap_type) {
2089 case SnapToBeatDiv128:
2090 case SnapToBeatDiv64:
2091 case SnapToBeatDiv32:
2092 case SnapToBeatDiv28:
2093 case SnapToBeatDiv24:
2094 case SnapToBeatDiv20:
2095 case SnapToBeatDiv16:
2096 case SnapToBeatDiv14:
2097 case SnapToBeatDiv12:
2098 case SnapToBeatDiv10:
2099 case SnapToBeatDiv8:
2100 case SnapToBeatDiv7:
2101 case SnapToBeatDiv6:
2102 case SnapToBeatDiv5:
2103 case SnapToBeatDiv4:
2104 case SnapToBeatDiv3:
2105 case SnapToBeatDiv2:
2106 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2107 update_tempo_based_rulers ();
2110 case SnapToRegionStart:
2111 case SnapToRegionEnd:
2112 case SnapToRegionSync:
2113 case SnapToRegionBoundary:
2114 build_region_boundary_cache ();
2122 SnapChanged (); /* EMIT SIGNAL */
2126 Editor::set_snap_mode (SnapMode mode)
2129 string str = snap_mode_strings[(int)mode];
2131 if (str != snap_mode_selector.get_active_text ()) {
2132 snap_mode_selector.set_active_text (str);
2138 Editor::set_edit_point_preference (EditPoint ep, bool force)
2140 bool changed = (_edit_point != ep);
2143 string str = edit_point_strings[(int)ep];
2145 if (str != edit_point_selector.get_active_text ()) {
2146 edit_point_selector.set_active_text (str);
2149 set_canvas_cursor ();
2151 if (!force && !changed) {
2155 const char* action=NULL;
2157 switch (_edit_point) {
2158 case EditAtPlayhead:
2159 action = "edit-at-playhead";
2161 case EditAtSelectedMarker:
2162 action = "edit-at-marker";
2165 action = "edit-at-mouse";
2169 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2171 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2175 bool in_track_canvas;
2177 if (!mouse_frame (foo, in_track_canvas)) {
2178 in_track_canvas = false;
2181 reset_canvas_action_sensitivity (in_track_canvas);
2187 Editor::set_state (const XMLNode& node, int /*version*/)
2189 const XMLProperty* prop;
2196 g.base_width = default_width;
2197 g.base_height = default_height;
2201 if ((geometry = find_named_node (node, "geometry")) != 0) {
2205 if ((prop = geometry->property("x_size")) == 0) {
2206 prop = geometry->property ("x-size");
2209 g.base_width = atoi(prop->value());
2211 if ((prop = geometry->property("y_size")) == 0) {
2212 prop = geometry->property ("y-size");
2215 g.base_height = atoi(prop->value());
2218 if ((prop = geometry->property ("x_pos")) == 0) {
2219 prop = geometry->property ("x-pos");
2222 x = atoi (prop->value());
2225 if ((prop = geometry->property ("y_pos")) == 0) {
2226 prop = geometry->property ("y-pos");
2229 y = atoi (prop->value());
2233 set_default_size (g.base_width, g.base_height);
2236 if (_session && (prop = node.property ("playhead"))) {
2238 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2239 playhead_cursor->set_position (pos);
2241 playhead_cursor->set_position (0);
2244 if ((prop = node.property ("mixer-width"))) {
2245 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2248 if ((prop = node.property ("zoom-focus"))) {
2249 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2252 if ((prop = node.property ("zoom"))) {
2253 reset_zoom (PBD::atof (prop->value()));
2255 reset_zoom (frames_per_unit);
2258 if ((prop = node.property ("snap-to"))) {
2259 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2262 if ((prop = node.property ("snap-mode"))) {
2263 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2266 if ((prop = node.property ("internal-snap-to"))) {
2267 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2270 if ((prop = node.property ("internal-snap-mode"))) {
2271 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2274 if ((prop = node.property ("pre-internal-snap-to"))) {
2275 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2278 if ((prop = node.property ("pre-internal-snap-mode"))) {
2279 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2282 if ((prop = node.property ("mouse-mode"))) {
2283 MouseMode m = str2mousemode(prop->value());
2284 set_mouse_mode (m, true);
2286 set_mouse_mode (MouseObject, true);
2289 if ((prop = node.property ("left-frame")) != 0) {
2291 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2295 reset_x_origin (pos);
2299 if ((prop = node.property ("y-origin")) != 0) {
2300 reset_y_origin (atof (prop->value ()));
2303 if ((prop = node.property ("internal-edit"))) {
2304 bool yn = string_is_affirmative (prop->value());
2305 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2307 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2308 tact->set_active (!yn);
2309 tact->set_active (yn);
2313 if ((prop = node.property ("join-object-range"))) {
2314 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2317 if ((prop = node.property ("edit-point"))) {
2318 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2321 if ((prop = node.property ("show-measures"))) {
2322 bool yn = string_is_affirmative (prop->value());
2323 _show_measures = yn;
2324 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2326 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2327 /* do it twice to force the change */
2328 tact->set_active (!yn);
2329 tact->set_active (yn);
2333 if ((prop = node.property ("follow-playhead"))) {
2334 bool yn = string_is_affirmative (prop->value());
2335 set_follow_playhead (yn);
2336 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2338 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2339 if (tact->get_active() != yn) {
2340 tact->set_active (yn);
2345 if ((prop = node.property ("stationary-playhead"))) {
2346 bool yn = string_is_affirmative (prop->value());
2347 set_stationary_playhead (yn);
2348 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2350 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2351 if (tact->get_active() != yn) {
2352 tact->set_active (yn);
2357 if ((prop = node.property ("region-list-sort-type"))) {
2358 RegionListSortType st;
2359 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2362 if ((prop = node.property ("show-editor-mixer"))) {
2364 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2367 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2368 bool yn = string_is_affirmative (prop->value());
2370 /* do it twice to force the change */
2372 tact->set_active (!yn);
2373 tact->set_active (yn);
2376 if ((prop = node.property ("show-editor-list"))) {
2378 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2381 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2382 bool yn = string_is_affirmative (prop->value());
2384 /* do it twice to force the change */
2386 tact->set_active (!yn);
2387 tact->set_active (yn);
2390 if ((prop = node.property (X_("editor-list-page")))) {
2391 _the_notebook.set_current_page (atoi (prop->value ()));
2394 if ((prop = node.property (X_("show-marker-lines")))) {
2395 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2397 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2398 bool yn = string_is_affirmative (prop->value ());
2400 tact->set_active (!yn);
2401 tact->set_active (yn);
2404 XMLNodeList children = node.children ();
2405 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2406 selection->set_state (**i, Stateful::current_state_version);
2407 _regions->set_state (**i);
2410 if ((prop = node.property ("maximised"))) {
2411 bool yn = string_is_affirmative (prop->value());
2413 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2417 if ((prop = node.property ("nudge-clock-value"))) {
2419 sscanf (prop->value().c_str(), "%" PRId64, &f);
2420 nudge_clock->set (f);
2422 nudge_clock->set_mode (AudioClock::Timecode);
2423 nudge_clock->set (_session->frame_rate() * 5, true);
2430 Editor::get_state ()
2432 XMLNode* node = new XMLNode ("Editor");
2435 id().print (buf, sizeof (buf));
2436 node->add_property ("id", buf);
2438 if (is_realized()) {
2439 Glib::RefPtr<Gdk::Window> win = get_window();
2441 int x, y, width, height;
2442 win->get_root_origin(x, y);
2443 win->get_size(width, height);
2445 XMLNode* geometry = new XMLNode ("geometry");
2447 snprintf(buf, sizeof(buf), "%d", width);
2448 geometry->add_property("x-size", string(buf));
2449 snprintf(buf, sizeof(buf), "%d", height);
2450 geometry->add_property("y-size", string(buf));
2451 snprintf(buf, sizeof(buf), "%d", x);
2452 geometry->add_property("x-pos", string(buf));
2453 snprintf(buf, sizeof(buf), "%d", y);
2454 geometry->add_property("y-pos", string(buf));
2455 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2456 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2457 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2458 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2459 geometry->add_property("edit-vertical-pane-pos", string(buf));
2461 node->add_child_nocopy (*geometry);
2464 maybe_add_mixer_strip_width (*node);
2466 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2467 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2468 node->add_property ("zoom", buf);
2469 node->add_property ("snap-to", enum_2_string (_snap_type));
2470 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2471 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2472 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2473 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2474 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2475 node->add_property ("edit-point", enum_2_string (_edit_point));
2477 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2478 node->add_property ("playhead", buf);
2479 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2480 node->add_property ("left-frame", buf);
2481 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2482 node->add_property ("y-origin", buf);
2484 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2485 node->add_property ("maximised", _maximised ? "yes" : "no");
2486 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2487 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2488 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2489 node->add_property ("mouse-mode", enum2str(mouse_mode));
2490 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2491 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2493 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2495 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2496 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2499 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2501 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2502 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2505 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2506 node->add_property (X_("editor-list-page"), buf);
2508 if (button_bindings) {
2509 XMLNode* bb = new XMLNode (X_("Buttons"));
2510 button_bindings->save (*bb);
2511 node->add_child_nocopy (*bb);
2514 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2516 node->add_child_nocopy (selection->get_state ());
2517 node->add_child_nocopy (_regions->get_state ());
2519 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2520 node->add_property ("nudge-clock-value", buf);
2527 /** @param y y offset from the top of all trackviews.
2528 * @return pair: TimeAxisView that y is over, layer index.
2529 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2530 * in stacked or expanded region display mode, otherwise 0.
2532 std::pair<TimeAxisView *, double>
2533 Editor::trackview_by_y_position (double y)
2535 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2537 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2543 return std::make_pair ( (TimeAxisView *) 0, 0);
2546 /** Snap a position to the grid, if appropriate, taking into account current
2547 * grid settings and also the state of any snap modifier keys that may be pressed.
2548 * @param start Position to snap.
2549 * @param event Event to get current key modifier information from, or 0.
2552 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2554 if (!_session || !event) {
2558 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2559 if (_snap_mode == SnapOff) {
2560 snap_to_internal (start, direction, for_mark);
2563 if (_snap_mode != SnapOff) {
2564 snap_to_internal (start, direction, for_mark);
2570 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2572 if (!_session || _snap_mode == SnapOff) {
2576 snap_to_internal (start, direction, for_mark);
2580 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2582 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2583 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2585 switch (_snap_type) {
2586 case SnapToTimecodeFrame:
2587 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2588 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2590 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2594 case SnapToTimecodeSeconds:
2595 if (_session->config.get_timecode_offset_negative()) {
2596 start += _session->config.get_timecode_offset ();
2598 start -= _session->config.get_timecode_offset ();
2600 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2601 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2603 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2606 if (_session->config.get_timecode_offset_negative()) {
2607 start -= _session->config.get_timecode_offset ();
2609 start += _session->config.get_timecode_offset ();
2613 case SnapToTimecodeMinutes:
2614 if (_session->config.get_timecode_offset_negative()) {
2615 start += _session->config.get_timecode_offset ();
2617 start -= _session->config.get_timecode_offset ();
2619 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2620 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2622 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2624 if (_session->config.get_timecode_offset_negative()) {
2625 start -= _session->config.get_timecode_offset ();
2627 start += _session->config.get_timecode_offset ();
2631 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2637 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2639 const framepos_t one_second = _session->frame_rate();
2640 const framepos_t one_minute = _session->frame_rate() * 60;
2641 framepos_t presnap = start;
2645 switch (_snap_type) {
2646 case SnapToTimecodeFrame:
2647 case SnapToTimecodeSeconds:
2648 case SnapToTimecodeMinutes:
2649 return timecode_snap_to_internal (start, direction, for_mark);
2652 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2653 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2655 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2660 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2661 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2663 start = (framepos_t) floor ((double) start / one_second) * one_second;
2668 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2669 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2671 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2676 start = _session->tempo_map().round_to_bar (start, direction);
2680 start = _session->tempo_map().round_to_beat (start, direction);
2683 case SnapToBeatDiv128:
2684 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2686 case SnapToBeatDiv64:
2687 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2689 case SnapToBeatDiv32:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2692 case SnapToBeatDiv28:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2695 case SnapToBeatDiv24:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2698 case SnapToBeatDiv20:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2701 case SnapToBeatDiv16:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2704 case SnapToBeatDiv14:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2707 case SnapToBeatDiv12:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2710 case SnapToBeatDiv10:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2713 case SnapToBeatDiv8:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2716 case SnapToBeatDiv7:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2719 case SnapToBeatDiv6:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2722 case SnapToBeatDiv5:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2725 case SnapToBeatDiv4:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2728 case SnapToBeatDiv3:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2731 case SnapToBeatDiv2:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2740 _session->locations()->marks_either_side (start, before, after);
2742 if (before == max_framepos && after == max_framepos) {
2743 /* No marks to snap to, so just don't snap */
2745 } else if (before == max_framepos) {
2747 } else if (after == max_framepos) {
2749 } else if (before != max_framepos && after != max_framepos) {
2750 /* have before and after */
2751 if ((start - before) < (after - start)) {
2760 case SnapToRegionStart:
2761 case SnapToRegionEnd:
2762 case SnapToRegionSync:
2763 case SnapToRegionBoundary:
2764 if (!region_boundary_cache.empty()) {
2766 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2767 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2769 if (direction > 0) {
2770 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2772 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2775 if (next != region_boundary_cache.begin ()) {
2780 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2781 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2783 if (start > (p + n) / 2) {
2792 switch (_snap_mode) {
2798 if (presnap > start) {
2799 if (presnap > (start + unit_to_frame(snap_threshold))) {
2803 } else if (presnap < start) {
2804 if (presnap < (start - unit_to_frame(snap_threshold))) {
2810 /* handled at entry */
2818 Editor::setup_toolbar ()
2820 HBox* mode_box = manage(new HBox);
2821 mode_box->set_border_width (2);
2822 mode_box->set_spacing(4);
2824 HBox* mouse_mode_box = manage (new HBox);
2825 HBox* mouse_mode_hbox1 = manage (new HBox);
2826 HBox* mouse_mode_hbox2 = manage (new HBox);
2827 VBox* mouse_mode_vbox1 = manage (new VBox);
2828 VBox* mouse_mode_vbox2 = manage (new VBox);
2829 Alignment* mouse_mode_align1 = manage (new Alignment);
2830 Alignment* mouse_mode_align2 = manage (new Alignment);
2832 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2833 mouse_mode_size_group->add_widget (mouse_move_button);
2834 mouse_mode_size_group->add_widget (mouse_select_button);
2835 mouse_mode_size_group->add_widget (mouse_zoom_button);
2836 mouse_mode_size_group->add_widget (mouse_gain_button);
2837 mouse_mode_size_group->add_widget (mouse_timefx_button);
2838 mouse_mode_size_group->add_widget (mouse_audition_button);
2839 mouse_mode_size_group->add_widget (mouse_draw_button);
2840 mouse_mode_size_group->add_widget (internal_edit_button);
2842 /* make them just a bit bigger */
2843 mouse_move_button.set_size_request (-1, 25);
2845 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2846 smart_mode_joiner->set_related_action (smart_mode_action);
2848 mouse_mode_hbox2->set_spacing (2);
2849 mouse_mode_box->set_spacing (2);
2851 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2852 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2853 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2854 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2855 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2856 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2857 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2859 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2860 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2862 mouse_mode_align1->add (*mouse_mode_vbox1);
2863 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2864 mouse_mode_align2->add (*mouse_mode_vbox2);
2865 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2867 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2868 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2870 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2871 if (!Profile->get_sae()) {
2872 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2874 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2876 edit_mode_selector.set_name ("EditModeSelector");
2877 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2878 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2880 mode_box->pack_start (edit_mode_selector, false, false);
2881 mode_box->pack_start (*mouse_mode_box, false, false);
2883 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2884 _mouse_mode_tearoff->set_name ("MouseModeBase");
2885 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2887 if (Profile->get_sae()) {
2888 _mouse_mode_tearoff->set_can_be_torn_off (false);
2891 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2892 &_mouse_mode_tearoff->tearoff_window()));
2893 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2894 &_mouse_mode_tearoff->tearoff_window(), 1));
2895 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2896 &_mouse_mode_tearoff->tearoff_window()));
2897 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2898 &_mouse_mode_tearoff->tearoff_window(), 1));
2902 _zoom_box.set_spacing (2);
2903 _zoom_box.set_border_width (2);
2907 zoom_in_button.set_name ("zoom button");
2908 zoom_in_button.set_image (::get_icon ("zoom_in"));
2909 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2910 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2911 zoom_in_button.set_related_action (act);
2913 zoom_out_button.set_name ("zoom button");
2914 zoom_out_button.set_image (::get_icon ("zoom_out"));
2915 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2916 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2917 zoom_out_button.set_related_action (act);
2919 zoom_out_full_button.set_name ("zoom button");
2920 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2921 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2922 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2923 zoom_out_full_button.set_related_action (act);
2925 zoom_focus_selector.set_name ("ZoomFocusSelector");
2926 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2927 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2929 _zoom_box.pack_start (zoom_out_button, false, false);
2930 _zoom_box.pack_start (zoom_in_button, false, false);
2931 _zoom_box.pack_start (zoom_out_full_button, false, false);
2933 _zoom_box.pack_start (zoom_focus_selector, false, false);
2935 /* Track zoom buttons */
2936 tav_expand_button.set_name ("TrackHeightButton");
2937 tav_expand_button.set_size_request (-1, 20);
2938 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2939 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2940 act->connect_proxy (tav_expand_button);
2942 tav_shrink_button.set_name ("TrackHeightButton");
2943 tav_shrink_button.set_size_request (-1, 20);
2944 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2945 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2946 act->connect_proxy (tav_shrink_button);
2948 _zoom_box.pack_start (tav_shrink_button);
2949 _zoom_box.pack_start (tav_expand_button);
2951 _zoom_tearoff = manage (new TearOff (_zoom_box));
2953 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2954 &_zoom_tearoff->tearoff_window()));
2955 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2956 &_zoom_tearoff->tearoff_window(), 0));
2957 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2958 &_zoom_tearoff->tearoff_window()));
2959 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2960 &_zoom_tearoff->tearoff_window(), 0));
2962 snap_box.set_spacing (1);
2963 snap_box.set_border_width (2);
2965 snap_type_selector.set_name ("SnapTypeSelector");
2966 set_popdown_strings (snap_type_selector, snap_type_strings);
2967 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2969 snap_mode_selector.set_name ("SnapModeSelector");
2970 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2971 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2973 edit_point_selector.set_name ("EditPointSelector");
2974 set_popdown_strings (edit_point_selector, edit_point_strings);
2975 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2977 snap_box.pack_start (snap_mode_selector, false, false);
2978 snap_box.pack_start (snap_type_selector, false, false);
2979 snap_box.pack_start (edit_point_selector, false, false);
2983 HBox *nudge_box = manage (new HBox);
2984 nudge_box->set_spacing (2);
2985 nudge_box->set_border_width (2);
2987 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2988 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2990 nudge_box->pack_start (nudge_backward_button, false, false);
2991 nudge_box->pack_start (nudge_forward_button, false, false);
2992 nudge_box->pack_start (*nudge_clock, false, false);
2995 /* Pack everything in... */
2997 HBox* hbox = manage (new HBox);
2998 hbox->set_spacing(10);
3000 _tools_tearoff = manage (new TearOff (*hbox));
3001 _tools_tearoff->set_name ("MouseModeBase");
3002 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3004 if (Profile->get_sae()) {
3005 _tools_tearoff->set_can_be_torn_off (false);
3008 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3009 &_tools_tearoff->tearoff_window()));
3010 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3011 &_tools_tearoff->tearoff_window(), 0));
3012 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3013 &_tools_tearoff->tearoff_window()));
3014 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3015 &_tools_tearoff->tearoff_window(), 0));
3017 toolbar_hbox.set_spacing (10);
3018 toolbar_hbox.set_border_width (1);
3020 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3021 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3022 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3024 hbox->pack_start (snap_box, false, false);
3025 if (!Profile->get_small_screen()) {
3026 hbox->pack_start (*nudge_box, false, false);
3028 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3030 hbox->pack_start (panic_box, false, false);
3034 toolbar_base.set_name ("ToolBarBase");
3035 toolbar_base.add (toolbar_hbox);
3037 _toolbar_viewport.add (toolbar_base);
3038 /* stick to the required height but allow width to vary if there's not enough room */
3039 _toolbar_viewport.set_size_request (1, -1);
3041 toolbar_frame.set_shadow_type (SHADOW_OUT);
3042 toolbar_frame.set_name ("BaseFrame");
3043 toolbar_frame.add (_toolbar_viewport);
3047 Editor::setup_tooltips ()
3049 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3050 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3051 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3052 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3053 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3054 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3055 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3056 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3057 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3058 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3059 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3060 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3061 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3062 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3063 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3064 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3065 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3066 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3067 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3068 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3069 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3070 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3071 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3075 Editor::convert_drop_to_paths (
3076 vector<string>& paths,
3077 const RefPtr<Gdk::DragContext>& /*context*/,
3080 const SelectionData& data,
3084 if (_session == 0) {
3088 vector<string> uris = data.get_uris();
3092 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3093 are actually URI lists. So do it by hand.
3096 if (data.get_target() != "text/plain") {
3100 /* Parse the "uri-list" format that Nautilus provides,
3101 where each pathname is delimited by \r\n.
3103 THERE MAY BE NO NULL TERMINATING CHAR!!!
3106 string txt = data.get_text();
3110 p = (const char *) malloc (txt.length() + 1);
3111 txt.copy (const_cast<char *> (p), txt.length(), 0);
3112 const_cast<char*>(p)[txt.length()] = '\0';
3118 while (g_ascii_isspace (*p))
3122 while (*q && (*q != '\n') && (*q != '\r')) {
3129 while (q > p && g_ascii_isspace (*q))
3134 uris.push_back (string (p, q - p + 1));
3138 p = strchr (p, '\n');
3150 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3152 if ((*i).substr (0,7) == "file://") {
3154 string const p = PBD::url_decode (*i);
3156 // scan forward past three slashes
3158 string::size_type slashcnt = 0;
3159 string::size_type n = 0;
3160 string::const_iterator x = p.begin();
3162 while (slashcnt < 3 && x != p.end()) {
3165 } else if (slashcnt == 3) {
3172 if (slashcnt != 3 || x == p.end()) {
3173 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3177 paths.push_back (p.substr (n - 1));
3185 Editor::new_tempo_section ()
3191 Editor::map_transport_state ()
3193 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3195 if (_session && _session->transport_stopped()) {
3196 have_pending_keyboard_selection = false;
3199 update_loop_range_view (true);
3205 Editor::begin_reversible_command (string name)
3208 _session->begin_reversible_command (name);
3213 Editor::begin_reversible_command (GQuark q)
3216 _session->begin_reversible_command (q);
3221 Editor::commit_reversible_command ()
3224 _session->commit_reversible_command ();
3229 Editor::history_changed ()
3233 if (undo_action && _session) {
3234 if (_session->undo_depth() == 0) {
3235 label = S_("Command|Undo");
3237 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3239 undo_action->property_label() = label;
3242 if (redo_action && _session) {
3243 if (_session->redo_depth() == 0) {
3246 label = string_compose(_("Redo (%1)"), _session->next_redo());
3248 redo_action->property_label() = label;
3253 Editor::duplicate_range (bool with_dialog)
3257 if (mouse_mode == MouseRange) {
3258 if (selection->time.length() == 0) {
3263 RegionSelection rs = get_regions_from_selection_and_entered ();
3265 if (mouse_mode != MouseRange && rs.empty()) {
3271 ArdourDialog win (_("Duplicate"));
3272 Label label (_("Number of duplications:"));
3273 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3274 SpinButton spinner (adjustment, 0.0, 1);
3277 win.get_vbox()->set_spacing (12);
3278 win.get_vbox()->pack_start (hbox);
3279 hbox.set_border_width (6);
3280 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3282 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3283 place, visually. so do this by hand.
3286 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3287 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3288 spinner.grab_focus();
3294 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3295 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3296 win.set_default_response (RESPONSE_ACCEPT);
3298 win.set_position (WIN_POS_MOUSE);
3300 spinner.grab_focus ();
3302 switch (win.run ()) {
3303 case RESPONSE_ACCEPT:
3309 times = adjustment.get_value();
3312 if (mouse_mode == MouseRange) {
3313 duplicate_selection (times);
3315 duplicate_some_regions (rs, times);
3320 Editor::set_edit_mode (EditMode m)
3322 Config->set_edit_mode (m);
3326 Editor::cycle_edit_mode ()
3328 switch (Config->get_edit_mode()) {
3330 if (Profile->get_sae()) {
3331 Config->set_edit_mode (Lock);
3333 Config->set_edit_mode (Splice);
3337 Config->set_edit_mode (Lock);
3340 Config->set_edit_mode (Slide);
3346 Editor::edit_mode_selection_done ()
3348 string s = edit_mode_selector.get_active_text ();
3351 Config->set_edit_mode (string_to_edit_mode (s));
3356 Editor::snap_type_selection_done ()
3358 string choice = snap_type_selector.get_active_text();
3359 SnapType snaptype = SnapToBeat;
3361 if (choice == _("Beats/2")) {
3362 snaptype = SnapToBeatDiv2;
3363 } else if (choice == _("Beats/3")) {
3364 snaptype = SnapToBeatDiv3;
3365 } else if (choice == _("Beats/4")) {
3366 snaptype = SnapToBeatDiv4;
3367 } else if (choice == _("Beats/5")) {
3368 snaptype = SnapToBeatDiv5;
3369 } else if (choice == _("Beats/6")) {
3370 snaptype = SnapToBeatDiv6;
3371 } else if (choice == _("Beats/7")) {
3372 snaptype = SnapToBeatDiv7;
3373 } else if (choice == _("Beats/8")) {
3374 snaptype = SnapToBeatDiv8;
3375 } else if (choice == _("Beats/10")) {
3376 snaptype = SnapToBeatDiv10;
3377 } else if (choice == _("Beats/12")) {
3378 snaptype = SnapToBeatDiv12;
3379 } else if (choice == _("Beats/14")) {
3380 snaptype = SnapToBeatDiv14;
3381 } else if (choice == _("Beats/16")) {
3382 snaptype = SnapToBeatDiv16;
3383 } else if (choice == _("Beats/20")) {
3384 snaptype = SnapToBeatDiv20;
3385 } else if (choice == _("Beats/24")) {
3386 snaptype = SnapToBeatDiv24;
3387 } else if (choice == _("Beats/28")) {
3388 snaptype = SnapToBeatDiv28;
3389 } else if (choice == _("Beats/32")) {
3390 snaptype = SnapToBeatDiv32;
3391 } else if (choice == _("Beats/64")) {
3392 snaptype = SnapToBeatDiv64;
3393 } else if (choice == _("Beats/128")) {
3394 snaptype = SnapToBeatDiv128;
3395 } else if (choice == _("Beats")) {
3396 snaptype = SnapToBeat;
3397 } else if (choice == _("Bars")) {
3398 snaptype = SnapToBar;
3399 } else if (choice == _("Marks")) {
3400 snaptype = SnapToMark;
3401 } else if (choice == _("Region starts")) {
3402 snaptype = SnapToRegionStart;
3403 } else if (choice == _("Region ends")) {
3404 snaptype = SnapToRegionEnd;
3405 } else if (choice == _("Region bounds")) {
3406 snaptype = SnapToRegionBoundary;
3407 } else if (choice == _("Region syncs")) {
3408 snaptype = SnapToRegionSync;
3409 } else if (choice == _("CD Frames")) {
3410 snaptype = SnapToCDFrame;
3411 } else if (choice == _("Timecode Frames")) {
3412 snaptype = SnapToTimecodeFrame;
3413 } else if (choice == _("Timecode Seconds")) {
3414 snaptype = SnapToTimecodeSeconds;
3415 } else if (choice == _("Timecode Minutes")) {
3416 snaptype = SnapToTimecodeMinutes;
3417 } else if (choice == _("Seconds")) {
3418 snaptype = SnapToSeconds;
3419 } else if (choice == _("Minutes")) {
3420 snaptype = SnapToMinutes;
3423 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3425 ract->set_active ();
3430 Editor::snap_mode_selection_done ()
3432 string choice = snap_mode_selector.get_active_text();
3433 SnapMode mode = SnapNormal;
3435 if (choice == _("No Grid")) {
3437 } else if (choice == _("Grid")) {
3439 } else if (choice == _("Magnetic")) {
3440 mode = SnapMagnetic;
3443 RefPtr<RadioAction> ract = snap_mode_action (mode);
3446 ract->set_active (true);
3451 Editor::cycle_edit_point (bool with_marker)
3453 switch (_edit_point) {
3455 set_edit_point_preference (EditAtPlayhead);
3457 case EditAtPlayhead:
3459 set_edit_point_preference (EditAtSelectedMarker);
3461 set_edit_point_preference (EditAtMouse);
3464 case EditAtSelectedMarker:
3465 set_edit_point_preference (EditAtMouse);
3471 Editor::edit_point_selection_done ()
3473 string choice = edit_point_selector.get_active_text();
3474 EditPoint ep = EditAtSelectedMarker;
3476 if (choice == _("Marker")) {
3477 set_edit_point_preference (EditAtSelectedMarker);
3478 } else if (choice == _("Playhead")) {
3479 set_edit_point_preference (EditAtPlayhead);
3481 set_edit_point_preference (EditAtMouse);
3484 RefPtr<RadioAction> ract = edit_point_action (ep);
3487 ract->set_active (true);
3492 Editor::zoom_focus_selection_done ()
3494 string choice = zoom_focus_selector.get_active_text();
3495 ZoomFocus focus_type = ZoomFocusLeft;
3497 if (choice == _("Left")) {
3498 focus_type = ZoomFocusLeft;
3499 } else if (choice == _("Right")) {
3500 focus_type = ZoomFocusRight;
3501 } else if (choice == _("Center")) {
3502 focus_type = ZoomFocusCenter;
3503 } else if (choice == _("Playhead")) {
3504 focus_type = ZoomFocusPlayhead;
3505 } else if (choice == _("Mouse")) {
3506 focus_type = ZoomFocusMouse;
3507 } else if (choice == _("Edit point")) {
3508 focus_type = ZoomFocusEdit;
3511 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3514 ract->set_active ();
3519 Editor::edit_controls_button_release (GdkEventButton* ev)
3521 if (Keyboard::is_context_menu_event (ev)) {
3522 ARDOUR_UI::instance()->add_route (this);
3523 } else if (ev->button == 1) {
3524 selection->clear_tracks ();
3531 Editor::mouse_select_button_release (GdkEventButton* ev)
3533 /* this handles just right-clicks */
3535 if (ev->button != 3) {
3543 Editor::set_zoom_focus (ZoomFocus f)
3545 string str = zoom_focus_strings[(int)f];
3547 if (str != zoom_focus_selector.get_active_text()) {
3548 zoom_focus_selector.set_active_text (str);
3551 if (zoom_focus != f) {
3558 Editor::ensure_float (Window& win)
3560 win.set_transient_for (*this);
3564 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3566 /* recover or initialize pane positions. do this here rather than earlier because
3567 we don't want the positions to change the child allocations, which they seem to do.
3573 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3582 XMLNode* geometry = find_named_node (*node, "geometry");
3584 if (which == static_cast<Paned*> (&edit_pane)) {
3586 if (done & Horizontal) {
3590 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3591 _notebook_shrunk = string_is_affirmative (prop->value ());
3594 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3595 /* initial allocation is 90% to canvas, 10% to notebook */
3596 pos = (int) floor (alloc.get_width() * 0.90f);
3597 snprintf (buf, sizeof(buf), "%d", pos);
3599 pos = atoi (prop->value());
3602 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3603 edit_pane.set_position (pos);
3606 done = (Pane) (done | Horizontal);
3608 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3610 if (done & Vertical) {
3614 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3615 /* initial allocation is 90% to canvas, 10% to summary */
3616 pos = (int) floor (alloc.get_height() * 0.90f);
3617 snprintf (buf, sizeof(buf), "%d", pos);
3620 pos = atoi (prop->value());
3623 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3624 editor_summary_pane.set_position (pos);
3627 done = (Pane) (done | Vertical);
3632 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3634 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3635 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3636 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3637 top_hbox.remove (toolbar_frame);
3642 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3644 if (toolbar_frame.get_parent() == 0) {
3645 top_hbox.pack_end (toolbar_frame);
3650 Editor::set_show_measures (bool yn)
3652 if (_show_measures != yn) {
3655 if ((_show_measures = yn) == true) {
3657 tempo_lines->show();
3665 Editor::toggle_follow_playhead ()
3667 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3669 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3670 set_follow_playhead (tact->get_active());
3674 /** @param yn true to follow playhead, otherwise false.
3675 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3678 Editor::set_follow_playhead (bool yn, bool catch_up)
3680 if (_follow_playhead != yn) {
3681 if ((_follow_playhead = yn) == true && catch_up) {
3683 reset_x_origin_to_follow_playhead ();
3690 Editor::toggle_stationary_playhead ()
3692 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3694 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3695 set_stationary_playhead (tact->get_active());
3700 Editor::set_stationary_playhead (bool yn)
3702 if (_stationary_playhead != yn) {
3703 if ((_stationary_playhead = yn) == true) {
3705 // FIXME need a 3.0 equivalent of this 2.X call
3706 // update_current_screen ();
3713 Editor::playlist_selector () const
3715 return *_playlist_selector;
3719 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3723 switch (_snap_type) {
3728 case SnapToBeatDiv128:
3731 case SnapToBeatDiv64:
3734 case SnapToBeatDiv32:
3737 case SnapToBeatDiv28:
3740 case SnapToBeatDiv24:
3743 case SnapToBeatDiv20:
3746 case SnapToBeatDiv16:
3749 case SnapToBeatDiv14:
3752 case SnapToBeatDiv12:
3755 case SnapToBeatDiv10:
3758 case SnapToBeatDiv8:
3761 case SnapToBeatDiv7:
3764 case SnapToBeatDiv6:
3767 case SnapToBeatDiv5:
3770 case SnapToBeatDiv4:
3773 case SnapToBeatDiv3:
3776 case SnapToBeatDiv2:
3782 return _session->tempo_map().meter_at (position).divisions_per_bar();
3787 case SnapToTimecodeFrame:
3788 case SnapToTimecodeSeconds:
3789 case SnapToTimecodeMinutes:
3792 case SnapToRegionStart:
3793 case SnapToRegionEnd:
3794 case SnapToRegionSync:
3795 case SnapToRegionBoundary:
3805 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3809 ret = nudge_clock->current_duration (pos);
3810 next = ret + 1; /* XXXX fix me */
3816 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3818 ArdourDialog dialog (_("Playlist Deletion"));
3819 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3820 "If it is kept, its audio files will not be cleaned.\n"
3821 "If it is deleted, audio files used by it alone will be cleaned."),
3824 dialog.set_position (WIN_POS_CENTER);
3825 dialog.get_vbox()->pack_start (label);
3829 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3830 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3831 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3833 switch (dialog.run ()) {
3834 case RESPONSE_ACCEPT:
3835 /* delete the playlist */
3839 case RESPONSE_REJECT:
3840 /* keep the playlist */
3852 Editor::audio_region_selection_covers (framepos_t where)
3854 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3855 if ((*a)->region()->covers (where)) {
3864 Editor::prepare_for_cleanup ()
3866 cut_buffer->clear_regions ();
3867 cut_buffer->clear_playlists ();
3869 selection->clear_regions ();
3870 selection->clear_playlists ();
3872 _regions->suspend_redisplay ();
3876 Editor::finish_cleanup ()
3878 _regions->resume_redisplay ();
3882 Editor::transport_loop_location()
3885 return _session->locations()->auto_loop_location();
3892 Editor::transport_punch_location()
3895 return _session->locations()->auto_punch_location();
3902 Editor::control_layout_scroll (GdkEventScroll* ev)
3904 if (Keyboard::some_magic_widget_has_focus()) {
3908 switch (ev->direction) {
3910 scroll_tracks_up_line ();
3914 case GDK_SCROLL_DOWN:
3915 scroll_tracks_down_line ();
3919 /* no left/right handling yet */
3927 Editor::session_state_saved (string)
3930 _snapshots->redisplay ();
3934 Editor::update_tearoff_visibility()
3936 bool visible = Config->get_keep_tearoffs();
3937 _mouse_mode_tearoff->set_visible (visible);
3938 _tools_tearoff->set_visible (visible);
3939 _zoom_tearoff->set_visible (visible);
3943 Editor::maximise_editing_space ()
3955 Editor::restore_editing_space ()
3967 * Make new playlists for a given track and also any others that belong
3968 * to the same active route group with the `edit' property.
3973 Editor::new_playlists (TimeAxisView* v)
3975 begin_reversible_command (_("new playlists"));
3976 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3977 _session->playlists->get (playlists);
3978 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3979 commit_reversible_command ();
3983 * Use a copy of the current playlist for a given track and also any others that belong
3984 * to the same active route group with the `edit' property.
3989 Editor::copy_playlists (TimeAxisView* v)
3991 begin_reversible_command (_("copy playlists"));
3992 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3993 _session->playlists->get (playlists);
3994 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3995 commit_reversible_command ();
3998 /** Clear the current playlist for a given track and also any others that belong
3999 * to the same active route group with the `edit' property.
4004 Editor::clear_playlists (TimeAxisView* v)
4006 begin_reversible_command (_("clear playlists"));
4007 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4008 _session->playlists->get (playlists);
4009 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4010 commit_reversible_command ();
4014 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4016 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4020 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4022 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4026 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4028 atv.clear_playlist ();
4032 Editor::on_key_press_event (GdkEventKey* ev)
4034 return key_press_focus_accelerator_handler (*this, ev);
4038 Editor::on_key_release_event (GdkEventKey* ev)
4040 return Gtk::Window::on_key_release_event (ev);
4041 // return key_press_focus_accelerator_handler (*this, ev);
4044 /** Queue up a change to the viewport x origin.
4045 * @param frame New x origin.
4048 Editor::reset_x_origin (framepos_t frame)
4050 pending_visual_change.add (VisualChange::TimeOrigin);
4051 pending_visual_change.time_origin = frame;
4052 ensure_visual_change_idle_handler ();
4056 Editor::reset_y_origin (double y)
4058 pending_visual_change.add (VisualChange::YOrigin);
4059 pending_visual_change.y_origin = y;
4060 ensure_visual_change_idle_handler ();
4064 Editor::reset_zoom (double fpu)
4066 clamp_frames_per_unit (fpu);
4068 if (fpu == frames_per_unit) {
4072 pending_visual_change.add (VisualChange::ZoomLevel);
4073 pending_visual_change.frames_per_unit = fpu;
4074 ensure_visual_change_idle_handler ();
4078 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4080 reset_x_origin (frame);
4083 if (!no_save_visual) {
4084 undo_visual_stack.push_back (current_visual_state(false));
4088 Editor::VisualState::VisualState (bool with_tracks)
4089 : gui_state (with_tracks ? new GUIObjectState : 0)
4093 Editor::VisualState::~VisualState ()
4098 Editor::VisualState*
4099 Editor::current_visual_state (bool with_tracks)
4101 VisualState* vs = new VisualState (with_tracks);
4102 vs->y_position = vertical_adjustment.get_value();
4103 vs->frames_per_unit = frames_per_unit;
4104 vs->leftmost_frame = leftmost_frame;
4105 vs->zoom_focus = zoom_focus;
4108 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4115 Editor::undo_visual_state ()
4117 if (undo_visual_stack.empty()) {
4121 VisualState* vs = undo_visual_stack.back();
4122 undo_visual_stack.pop_back();
4125 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4127 use_visual_state (*vs);
4131 Editor::redo_visual_state ()
4133 if (redo_visual_stack.empty()) {
4137 VisualState* vs = redo_visual_stack.back();
4138 redo_visual_stack.pop_back();
4140 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4142 use_visual_state (*vs);
4146 Editor::swap_visual_state ()
4148 if (undo_visual_stack.empty()) {
4149 redo_visual_state ();
4151 undo_visual_state ();
4156 Editor::use_visual_state (VisualState& vs)
4158 PBD::Unwinder<bool> nsv (no_save_visual, true);
4160 _routes->suspend_redisplay ();
4162 vertical_adjustment.set_value (vs.y_position);
4164 set_zoom_focus (vs.zoom_focus);
4165 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4168 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4170 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4171 (*i)->reset_visual_state ();
4175 _routes->update_visibility ();
4176 _routes->resume_redisplay ();
4179 /** This is the core function that controls the zoom level of the canvas. It is called
4180 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4181 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4184 Editor::set_frames_per_unit (double fpu)
4187 tempo_lines->tempo_map_changed();
4190 frames_per_unit = fpu;
4192 /* convert fpu to frame count */
4194 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4196 if (frames_per_unit != zoom_range_clock->current_duration()) {
4197 zoom_range_clock->set (frames);
4200 bool const showing_time_selection =
4201 mouse_mode == MouseRange ||
4202 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4204 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4205 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4206 (*i)->reshow_selection (selection->time);
4210 ZoomChanged (); /* EMIT_SIGNAL */
4212 //reset_scrolling_region ();
4214 if (playhead_cursor) {
4215 playhead_cursor->set_position (playhead_cursor->current_frame);
4218 refresh_location_display();
4219 _summary->set_overlays_dirty ();
4221 update_marker_labels ();
4227 Editor::ensure_visual_change_idle_handler ()
4229 if (pending_visual_change.idle_handler_id < 0) {
4230 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4235 Editor::_idle_visual_changer (void* arg)
4237 return static_cast<Editor*>(arg)->idle_visual_changer ();
4241 Editor::idle_visual_changer ()
4243 /* set_horizontal_position() below (and maybe other calls) call
4244 gtk_main_iteration(), so it's possible that a signal will be handled
4245 half-way through this method. If this signal wants an
4246 idle_visual_changer we must schedule another one after this one, so
4247 mark the idle_handler_id as -1 here to allow that. Also make a note
4248 that we are doing the visual change, so that changes in response to
4249 super-rapid-screen-update can be dropped if we are still processing
4252 pending_visual_change.idle_handler_id = -1;
4253 pending_visual_change.being_handled = true;
4255 VisualChange::Type p = pending_visual_change.pending;
4256 pending_visual_change.pending = (VisualChange::Type) 0;
4258 double const last_time_origin = horizontal_position ();
4260 if (p & VisualChange::ZoomLevel) {
4261 set_frames_per_unit (pending_visual_change.frames_per_unit);
4263 compute_fixed_ruler_scale ();
4264 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4265 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4266 update_tempo_based_rulers ();
4268 if (p & VisualChange::TimeOrigin) {
4269 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4271 if (p & VisualChange::YOrigin) {
4272 vertical_adjustment.set_value (pending_visual_change.y_origin);
4275 if (last_time_origin == horizontal_position ()) {
4276 /* changed signal not emitted */
4277 update_fixed_rulers ();
4278 redisplay_tempo (true);
4281 _summary->set_overlays_dirty ();
4283 pending_visual_change.being_handled = false;
4284 return 0; /* this is always a one-shot call */
4287 struct EditorOrderTimeAxisSorter {
4288 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4289 return a->order () < b->order ();
4294 Editor::sort_track_selection (TrackViewList& sel)
4296 EditorOrderTimeAxisSorter cmp;
4301 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4304 framepos_t where = 0;
4305 EditPoint ep = _edit_point;
4307 if (from_context_menu && (ep == EditAtMouse)) {
4308 return event_frame (&context_click_event, 0, 0);
4311 if (entered_marker) {
4312 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4313 return entered_marker->position();
4316 if (ignore_playhead && ep == EditAtPlayhead) {
4317 ep = EditAtSelectedMarker;
4321 case EditAtPlayhead:
4322 where = _session->audible_frame();
4323 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4326 case EditAtSelectedMarker:
4327 if (!selection->markers.empty()) {
4329 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4332 where = loc->start();
4336 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4344 if (!mouse_frame (where, ignored)) {
4345 /* XXX not right but what can we do ? */
4349 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4357 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4359 if (!_session) return;
4361 begin_reversible_command (cmd);
4365 if ((tll = transport_loop_location()) == 0) {
4366 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4367 XMLNode &before = _session->locations()->get_state();
4368 _session->locations()->add (loc, true);
4369 _session->set_auto_loop_location (loc);
4370 XMLNode &after = _session->locations()->get_state();
4371 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4373 XMLNode &before = tll->get_state();
4374 tll->set_hidden (false, this);
4375 tll->set (start, end);
4376 XMLNode &after = tll->get_state();
4377 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4380 commit_reversible_command ();
4384 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4386 if (!_session) return;
4388 begin_reversible_command (cmd);
4392 if ((tpl = transport_punch_location()) == 0) {
4393 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4394 XMLNode &before = _session->locations()->get_state();
4395 _session->locations()->add (loc, true);
4396 _session->set_auto_loop_location (loc);
4397 XMLNode &after = _session->locations()->get_state();
4398 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4401 XMLNode &before = tpl->get_state();
4402 tpl->set_hidden (false, this);
4403 tpl->set (start, end);
4404 XMLNode &after = tpl->get_state();
4405 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4408 commit_reversible_command ();
4411 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4412 * @param rs List to which found regions are added.
4413 * @param where Time to look at.
4414 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4417 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4419 const TrackViewList* tracks;
4422 tracks = &track_views;
4427 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4429 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4432 boost::shared_ptr<Track> tr;
4433 boost::shared_ptr<Playlist> pl;
4435 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4437 boost::shared_ptr<RegionList> regions = pl->regions_at (
4438 (framepos_t) floor ( (double) where * tr->speed()));
4440 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4441 RegionView* rv = rtv->view()->find_view (*i);
4452 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4454 const TrackViewList* tracks;
4457 tracks = &track_views;
4462 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4463 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4465 boost::shared_ptr<Track> tr;
4466 boost::shared_ptr<Playlist> pl;
4468 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4470 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4471 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4473 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4475 RegionView* rv = rtv->view()->find_view (*i);
4486 /** Start with regions that are selected. Then add equivalent regions
4487 * on tracks in the same active edit-enabled route group as any of
4488 * the regions that we started with.
4492 Editor::get_regions_from_selection ()
4494 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4497 /** Get regions using the following method:
4499 * Make an initial region list using the selected regions, unless
4500 * the edit point is `mouse' and the mouse is over an unselected
4501 * region. In this case, start with just that region.
4503 * Then, add equivalent regions in active edit groups to the region list.
4505 * Then, search the list of selected tracks to find any selected tracks which
4506 * do not contain regions already in the region list. If there are no selected
4507 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4508 * than just the selected.
4510 * Add any regions that are under the edit point on these tracks to get the
4511 * returned region list.
4513 * The rationale here is that the mouse edit point is special in that
4514 * its position describes both a time and a track; the other edit
4515 * modes only describe a time. Hence if the edit point is `mouse' we
4516 * ignore selected tracks, as we assume the user means something by
4517 * pointing at a particular track. Also in this case we take note of
4518 * the region directly under the edit point, as there is always just one
4519 * (rather than possibly several with non-mouse edit points).
4523 Editor::get_regions_from_selection_and_edit_point ()
4525 RegionSelection regions;
4527 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4528 regions.add (entered_regionview);
4530 regions = selection->regions;
4533 TrackViewList tracks;
4535 if (_edit_point != EditAtMouse) {
4536 tracks = selection->tracks;
4539 /* Add any other regions that are in the same
4540 edit-activated route group as one of our regions.
4542 regions = get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4543 framepos_t const where = get_preferred_edit_position ();
4545 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4546 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4547 * is enabled, so consider all tracks
4549 tracks = track_views;
4552 if (!tracks.empty()) {
4553 /* now search the selected tracks for tracks which don't
4554 already contain regions to be acted upon, and get regions at
4555 the edit point on those tracks too.
4557 TrackViewList tracks_without_relevant_regions;
4559 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4560 if (!regions.involves (**t)) {
4561 /* there are no equivalent regions on this track */
4562 tracks_without_relevant_regions.push_back (*t);
4566 if (!tracks_without_relevant_regions.empty()) {
4567 /* there are some selected tracks with neither selected
4568 * regions or their equivalents: act upon all regions in
4571 get_regions_at (regions, where, tracks_without_relevant_regions);
4578 /** Start with regions that are selected, or the entered regionview if none are selected.
4579 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4580 * of the regions that we started with.
4584 Editor::get_regions_from_selection_and_entered ()
4586 RegionSelection regions = selection->regions;
4588 if (regions.empty() && entered_regionview) {
4589 regions.add (entered_regionview);
4592 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4596 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4598 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4600 RouteTimeAxisView* tatv;
4602 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4604 boost::shared_ptr<Playlist> pl;
4605 vector<boost::shared_ptr<Region> > results;
4607 boost::shared_ptr<Track> tr;
4609 if ((tr = tatv->track()) == 0) {
4614 if ((pl = (tr->playlist())) != 0) {
4615 pl->get_region_list_equivalent_regions (region, results);
4618 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4619 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4620 regions.push_back (marv);
4629 Editor::show_rhythm_ferret ()
4631 if (rhythm_ferret == 0) {
4632 rhythm_ferret = new RhythmFerret(*this);
4635 rhythm_ferret->set_session (_session);
4636 rhythm_ferret->show ();
4637 rhythm_ferret->present ();
4641 Editor::first_idle ()
4643 MessageDialog* dialog = 0;
4645 if (track_views.size() > 1) {
4646 dialog = new MessageDialog (
4648 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4652 ARDOUR_UI::instance()->flush_pending ();
4655 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4659 // first idle adds route children (automation tracks), so we need to redisplay here
4660 _routes->redisplay ();
4667 Editor::_idle_resize (gpointer arg)
4669 return ((Editor*)arg)->idle_resize ();
4673 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4675 if (resize_idle_id < 0) {
4676 resize_idle_id = g_idle_add (_idle_resize, this);
4677 _pending_resize_amount = 0;
4680 /* make a note of the smallest resulting height, so that we can clamp the
4681 lower limit at TimeAxisView::hSmall */
4683 int32_t min_resulting = INT32_MAX;
4685 _pending_resize_amount += h;
4686 _pending_resize_view = view;
4688 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4690 if (selection->tracks.contains (_pending_resize_view)) {
4691 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4692 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4696 if (min_resulting < 0) {
4701 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4702 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4706 /** Handle pending resizing of tracks */
4708 Editor::idle_resize ()
4710 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4712 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4713 selection->tracks.contains (_pending_resize_view)) {
4715 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4716 if (*i != _pending_resize_view) {
4717 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4722 _pending_resize_amount = 0;
4724 _group_tabs->set_dirty ();
4725 resize_idle_id = -1;
4733 ENSURE_GUI_THREAD (*this, &Editor::located);
4736 playhead_cursor->set_position (_session->audible_frame ());
4737 if (_follow_playhead && !_pending_initial_locate) {
4738 reset_x_origin_to_follow_playhead ();
4742 _pending_locate_request = false;
4743 _pending_initial_locate = false;
4747 Editor::region_view_added (RegionView *)
4749 _summary->set_dirty ();
4753 Editor::region_view_removed ()
4755 _summary->set_dirty ();
4759 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4761 TrackViewList::const_iterator j = track_views.begin ();
4762 while (j != track_views.end()) {
4763 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4764 if (rtv && rtv->route() == r) {
4775 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4779 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4780 TimeAxisView* tv = axis_view_from_route (*i);
4790 Editor::add_routes (RouteList& routes)
4792 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4794 RouteTimeAxisView *rtv;
4795 list<RouteTimeAxisView*> new_views;
4797 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4798 boost::shared_ptr<Route> route = (*x);
4800 if (route->is_hidden() || route->is_monitor()) {
4804 DataType dt = route->input()->default_type();
4806 if (dt == ARDOUR::DataType::AUDIO) {
4807 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4808 rtv->set_route (route);
4809 } else if (dt == ARDOUR::DataType::MIDI) {
4810 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4811 rtv->set_route (route);
4813 throw unknown_type();
4816 new_views.push_back (rtv);
4817 track_views.push_back (rtv);
4819 rtv->effective_gain_display ();
4821 if (internal_editing()) {
4822 rtv->enter_internal_edit_mode ();
4824 rtv->leave_internal_edit_mode ();
4827 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4828 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4831 _routes->routes_added (new_views);
4832 _summary->routes_added (new_views);
4834 if (show_editor_mixer_when_tracks_arrive) {
4835 show_editor_mixer (true);
4838 editor_list_button.set_sensitive (true);
4842 Editor::timeaxisview_deleted (TimeAxisView *tv)
4844 if (_session && _session->deletion_in_progress()) {
4845 /* the situation is under control */
4849 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4851 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4853 _routes->route_removed (tv);
4855 if (tv == entered_track) {
4859 TimeAxisView::Children c = tv->get_child_list ();
4860 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4861 if (entered_track == i->get()) {
4866 /* remove it from the list of track views */
4868 TrackViewList::iterator i;
4870 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4871 i = track_views.erase (i);
4874 /* update whatever the current mixer strip is displaying, if revelant */
4876 boost::shared_ptr<Route> route;
4879 route = rtav->route ();
4882 if (current_mixer_strip && current_mixer_strip->route() == route) {
4884 TimeAxisView* next_tv;
4886 if (track_views.empty()) {
4888 } else if (i == track_views.end()) {
4889 next_tv = track_views.front();
4896 set_selected_mixer_strip (*next_tv);
4898 /* make the editor mixer strip go away setting the
4899 * button to inactive (which also unticks the menu option)
4902 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4908 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4910 if (apply_to_selection) {
4911 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4913 TrackSelection::iterator j = i;
4916 hide_track_in_display (*i, false);
4921 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4923 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4924 // this will hide the mixer strip
4925 set_selected_mixer_strip (*tv);
4928 _routes->hide_track_in_display (*tv);
4933 Editor::sync_track_view_list_and_routes ()
4935 track_views = TrackViewList (_routes->views ());
4937 _summary->set_dirty ();
4938 _group_tabs->set_dirty ();
4940 return false; // do not call again (until needed)
4944 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4946 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4951 /** Find a RouteTimeAxisView by the ID of its route */
4953 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4955 RouteTimeAxisView* v;
4957 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4958 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4959 if(v->route()->id() == id) {
4969 Editor::fit_route_group (RouteGroup *g)
4971 TrackViewList ts = axis_views_from_routes (g->route_list ());
4976 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4978 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4981 _session->cancel_audition ();
4985 if (_session->is_auditioning()) {
4986 _session->cancel_audition ();
4987 if (r == last_audition_region) {
4992 _session->audition_region (r);
4993 last_audition_region = r;
4998 Editor::hide_a_region (boost::shared_ptr<Region> r)
5000 r->set_hidden (true);
5004 Editor::show_a_region (boost::shared_ptr<Region> r)
5006 r->set_hidden (false);
5010 Editor::audition_region_from_region_list ()
5012 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5016 Editor::hide_region_from_region_list ()
5018 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5022 Editor::show_region_in_region_list ()
5024 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5028 Editor::step_edit_status_change (bool yn)
5031 start_step_editing ();
5033 stop_step_editing ();
5038 Editor::start_step_editing ()
5040 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5044 Editor::stop_step_editing ()
5046 step_edit_connection.disconnect ();
5050 Editor::check_step_edit ()
5052 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5053 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5055 mtv->check_step_edit ();
5059 return true; // do it again, till we stop
5063 Editor::scroll_press (Direction dir)
5065 ++_scroll_callbacks;
5067 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5068 /* delay the first auto-repeat */
5074 scroll_backward (1);
5082 scroll_tracks_up_line ();
5086 scroll_tracks_down_line ();
5090 /* do hacky auto-repeat */
5091 if (!_scroll_connection.connected ()) {
5093 _scroll_connection = Glib::signal_timeout().connect (
5094 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5097 _scroll_callbacks = 0;
5104 Editor::scroll_release ()
5106 _scroll_connection.disconnect ();
5109 /** Queue a change for the Editor viewport x origin to follow the playhead */
5111 Editor::reset_x_origin_to_follow_playhead ()
5113 framepos_t const frame = playhead_cursor->current_frame;
5115 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5117 if (_session->transport_speed() < 0) {
5119 if (frame > (current_page_frames() / 2)) {
5120 center_screen (frame-(current_page_frames()/2));
5122 center_screen (current_page_frames()/2);
5129 if (frame < leftmost_frame) {
5131 if (_session->transport_rolling()) {
5132 /* rolling; end up with the playhead at the right of the page */
5133 l = frame - current_page_frames ();
5135 /* not rolling: end up with the playhead 1/4 of the way along the page */
5136 l = frame - current_page_frames() / 4;
5140 if (_session->transport_rolling()) {
5141 /* rolling: end up with the playhead on the left of the page */
5144 /* not rolling: end up with the playhead 3/4 of the way along the page */
5145 l = frame - 3 * current_page_frames() / 4;
5153 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5159 Editor::super_rapid_screen_update ()
5161 if (!_session || !_session->engine().running()) {
5165 /* METERING / MIXER STRIPS */
5167 /* update track meters, if required */
5168 if (is_mapped() && meters_running) {
5169 RouteTimeAxisView* rtv;
5170 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5171 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5172 rtv->fast_update ();
5177 /* and any current mixer strip */
5178 if (current_mixer_strip) {
5179 current_mixer_strip->fast_update ();
5182 /* PLAYHEAD AND VIEWPORT */
5184 framepos_t const frame = _session->audible_frame();
5186 /* There are a few reasons why we might not update the playhead / viewport stuff:
5188 * 1. we don't update things when there's a pending locate request, otherwise
5189 * when the editor requests a locate there is a chance that this method
5190 * will move the playhead before the locate request is processed, causing
5192 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5193 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5196 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5198 last_update_frame = frame;
5200 if (!_dragging_playhead) {
5201 playhead_cursor->set_position (frame);
5204 if (!_stationary_playhead) {
5206 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5207 /* We only do this if we aren't already
5208 handling a visual change (ie if
5209 pending_visual_change.being_handled is
5210 false) so that these requests don't stack
5211 up there are too many of them to handle in
5214 reset_x_origin_to_follow_playhead ();
5219 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5223 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5224 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5225 if (target <= 0.0) {
5228 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5229 target = (target * 0.15) + (current * 0.85);
5235 set_horizontal_position (current);
5244 Editor::session_going_away ()
5246 _have_idled = false;
5248 _session_connections.drop_connections ();
5250 super_rapid_screen_update_connection.disconnect ();
5252 selection->clear ();
5253 cut_buffer->clear ();
5255 clicked_regionview = 0;
5256 clicked_axisview = 0;
5257 clicked_routeview = 0;
5258 entered_regionview = 0;
5260 last_update_frame = 0;
5263 playhead_cursor->canvas_item.hide ();
5265 /* rip everything out of the list displays */
5269 _route_groups->clear ();
5271 /* do this first so that deleting a track doesn't reset cms to null
5272 and thus cause a leak.
5275 if (current_mixer_strip) {
5276 if (current_mixer_strip->get_parent() != 0) {
5277 global_hpacker.remove (*current_mixer_strip);
5279 delete current_mixer_strip;
5280 current_mixer_strip = 0;
5283 /* delete all trackviews */
5285 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5288 track_views.clear ();
5290 zoom_range_clock->set_session (0);
5291 nudge_clock->set_session (0);
5293 editor_list_button.set_active(false);
5294 editor_list_button.set_sensitive(false);
5296 /* clear tempo/meter rulers */
5297 remove_metric_marks ();
5299 clear_marker_display ();
5301 stop_step_editing ();
5303 current_bbt_points_begin = current_bbt_points_end;
5305 /* get rid of any existing editor mixer strip */
5307 WindowTitle title(Glib::get_application_name());
5308 title += _("Editor");
5310 set_title (title.get_string());
5312 SessionHandlePtr::session_going_away ();
5317 Editor::show_editor_list (bool yn)
5320 _the_notebook.show ();
5322 _the_notebook.hide ();
5327 Editor::change_region_layering_order (bool from_context_menu)
5329 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5331 if (!clicked_routeview) {
5332 if (layering_order_editor) {
5333 layering_order_editor->hide ();
5338 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5344 boost::shared_ptr<Playlist> pl = track->playlist();
5350 if (layering_order_editor == 0) {
5351 layering_order_editor = new RegionLayeringOrderEditor (*this);
5352 layering_order_editor->set_position (WIN_POS_MOUSE);
5355 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5356 layering_order_editor->maybe_present ();
5360 Editor::update_region_layering_order_editor ()
5362 if (layering_order_editor && layering_order_editor->is_visible ()) {
5363 change_region_layering_order (true);
5368 Editor::setup_fade_images ()
5370 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5371 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5372 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5373 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5374 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5376 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5377 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5378 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5379 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5380 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5382 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5383 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5384 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5385 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5386 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5388 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5389 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5390 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5391 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5392 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5396 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5398 Editor::action_menu_item (std::string const & name)
5400 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5403 return *manage (a->create_menu_item ());
5407 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5409 EventBox* b = manage (new EventBox);
5410 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5411 Label* l = manage (new Label (name));
5415 _the_notebook.append_page (widget, *b);
5419 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5421 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5422 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5425 if (ev->type == GDK_2BUTTON_PRESS) {
5427 /* double-click on a notebook tab shrinks or expands the notebook */
5429 if (_notebook_shrunk) {
5430 if (pre_notebook_shrink_pane_width) {
5431 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5433 _notebook_shrunk = false;
5435 pre_notebook_shrink_pane_width = edit_pane.get_position();
5437 /* this expands the LHS of the edit pane to cover the notebook
5438 PAGE but leaves the tabs visible.
5440 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5441 _notebook_shrunk = true;
5449 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5451 using namespace Menu_Helpers;
5453 MenuList& items = _control_point_context_menu.items ();
5456 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5457 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5458 if (!can_remove_control_point (item)) {
5459 items.back().set_sensitive (false);
5462 _control_point_context_menu.popup (event->button.button, event->button.time);
5466 Editor::shift_key_released ()
5468 _stepping_axis_view = 0;