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, 8);
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.add (*(manage (new Image (::get_icon ("zoom_in")))));
2909 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2910 act->connect_proxy (zoom_in_button);
2912 zoom_out_button.set_name ("zoom button");
2913 zoom_out_button.add (*(manage (new Image (::get_icon ("zoom_out")))));
2914 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2915 act->connect_proxy (zoom_out_button);
2917 zoom_out_full_button.set_name ("zoom button");
2918 zoom_out_full_button.add (*(manage (new Image (::get_icon ("zoom_full")))));
2919 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2920 act->connect_proxy (zoom_out_full_button);
2922 zoom_focus_selector.set_name ("ZoomFocusSelector");
2923 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2924 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2926 _zoom_box.pack_start (zoom_out_button, false, false);
2927 _zoom_box.pack_start (zoom_in_button, false, false);
2928 _zoom_box.pack_start (zoom_out_full_button, false, false);
2930 _zoom_box.pack_start (zoom_focus_selector, false, false);
2932 /* Track zoom buttons */
2933 tav_expand_button.set_name ("TrackHeightButton");
2934 tav_expand_button.set_size_request (-1, 20);
2935 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2936 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2937 act->connect_proxy (tav_expand_button);
2939 tav_shrink_button.set_name ("TrackHeightButton");
2940 tav_shrink_button.set_size_request (-1, 20);
2941 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2942 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2943 act->connect_proxy (tav_shrink_button);
2945 _zoom_box.pack_start (tav_shrink_button);
2946 _zoom_box.pack_start (tav_expand_button);
2948 _zoom_tearoff = manage (new TearOff (_zoom_box));
2950 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2951 &_zoom_tearoff->tearoff_window()));
2952 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2953 &_zoom_tearoff->tearoff_window(), 0));
2954 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2955 &_zoom_tearoff->tearoff_window()));
2956 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2957 &_zoom_tearoff->tearoff_window(), 0));
2959 snap_box.set_spacing (1);
2960 snap_box.set_border_width (2);
2962 snap_type_selector.set_name ("SnapTypeSelector");
2963 set_popdown_strings (snap_type_selector, snap_type_strings);
2964 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2966 snap_mode_selector.set_name ("SnapModeSelector");
2967 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2968 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2970 edit_point_selector.set_name ("EditPointSelector");
2971 set_popdown_strings (edit_point_selector, edit_point_strings);
2972 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2974 snap_box.pack_start (snap_mode_selector, false, false);
2975 snap_box.pack_start (snap_type_selector, false, false);
2976 snap_box.pack_start (edit_point_selector, false, false);
2980 HBox *nudge_box = manage (new HBox);
2981 nudge_box->set_spacing (2);
2982 nudge_box->set_border_width (2);
2984 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2985 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2987 nudge_box->pack_start (nudge_backward_button, false, false);
2988 nudge_box->pack_start (nudge_forward_button, false, false);
2989 nudge_box->pack_start (*nudge_clock, false, false);
2992 /* Pack everything in... */
2994 HBox* hbox = manage (new HBox);
2995 hbox->set_spacing(10);
2997 _tools_tearoff = manage (new TearOff (*hbox));
2998 _tools_tearoff->set_name ("MouseModeBase");
2999 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3001 if (Profile->get_sae()) {
3002 _tools_tearoff->set_can_be_torn_off (false);
3005 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3006 &_tools_tearoff->tearoff_window()));
3007 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3008 &_tools_tearoff->tearoff_window(), 0));
3009 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3010 &_tools_tearoff->tearoff_window()));
3011 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3012 &_tools_tearoff->tearoff_window(), 0));
3014 toolbar_hbox.set_spacing (10);
3015 toolbar_hbox.set_border_width (1);
3017 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3018 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3019 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3021 hbox->pack_start (snap_box, false, false);
3022 if (!Profile->get_small_screen()) {
3023 hbox->pack_start (*nudge_box, false, false);
3025 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3027 hbox->pack_start (panic_box, false, false);
3031 toolbar_base.set_name ("ToolBarBase");
3032 toolbar_base.add (toolbar_hbox);
3034 _toolbar_viewport.add (toolbar_base);
3035 /* stick to the required height but allow width to vary if there's not enough room */
3036 _toolbar_viewport.set_size_request (1, -1);
3038 toolbar_frame.set_shadow_type (SHADOW_OUT);
3039 toolbar_frame.set_name ("BaseFrame");
3040 toolbar_frame.add (_toolbar_viewport);
3044 Editor::setup_tooltips ()
3046 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3047 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3048 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3049 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3050 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3051 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3052 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3053 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3054 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3055 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3056 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3057 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3058 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3059 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3060 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3061 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3062 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3063 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3064 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3065 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3066 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3067 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3068 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3072 Editor::convert_drop_to_paths (
3073 vector<string>& paths,
3074 const RefPtr<Gdk::DragContext>& /*context*/,
3077 const SelectionData& data,
3081 if (_session == 0) {
3085 vector<string> uris = data.get_uris();
3089 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3090 are actually URI lists. So do it by hand.
3093 if (data.get_target() != "text/plain") {
3097 /* Parse the "uri-list" format that Nautilus provides,
3098 where each pathname is delimited by \r\n.
3100 THERE MAY BE NO NULL TERMINATING CHAR!!!
3103 string txt = data.get_text();
3107 p = (const char *) malloc (txt.length() + 1);
3108 txt.copy (const_cast<char *> (p), txt.length(), 0);
3109 const_cast<char*>(p)[txt.length()] = '\0';
3115 while (g_ascii_isspace (*p))
3119 while (*q && (*q != '\n') && (*q != '\r')) {
3126 while (q > p && g_ascii_isspace (*q))
3131 uris.push_back (string (p, q - p + 1));
3135 p = strchr (p, '\n');
3147 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3149 if ((*i).substr (0,7) == "file://") {
3151 string const p = PBD::url_decode (*i);
3153 // scan forward past three slashes
3155 string::size_type slashcnt = 0;
3156 string::size_type n = 0;
3157 string::const_iterator x = p.begin();
3159 while (slashcnt < 3 && x != p.end()) {
3162 } else if (slashcnt == 3) {
3169 if (slashcnt != 3 || x == p.end()) {
3170 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3174 paths.push_back (p.substr (n - 1));
3182 Editor::new_tempo_section ()
3188 Editor::map_transport_state ()
3190 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3192 if (_session && _session->transport_stopped()) {
3193 have_pending_keyboard_selection = false;
3196 update_loop_range_view (true);
3202 Editor::begin_reversible_command (string name)
3205 _session->begin_reversible_command (name);
3210 Editor::begin_reversible_command (GQuark q)
3213 _session->begin_reversible_command (q);
3218 Editor::commit_reversible_command ()
3221 _session->commit_reversible_command ();
3226 Editor::history_changed ()
3230 if (undo_action && _session) {
3231 if (_session->undo_depth() == 0) {
3232 label = S_("Command|Undo");
3234 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3236 undo_action->property_label() = label;
3239 if (redo_action && _session) {
3240 if (_session->redo_depth() == 0) {
3243 label = string_compose(_("Redo (%1)"), _session->next_redo());
3245 redo_action->property_label() = label;
3250 Editor::duplicate_range (bool with_dialog)
3254 if (mouse_mode == MouseRange) {
3255 if (selection->time.length() == 0) {
3260 RegionSelection rs = get_regions_from_selection_and_entered ();
3262 if (mouse_mode != MouseRange && rs.empty()) {
3268 ArdourDialog win (_("Duplicate"));
3269 Label label (_("Number of duplications:"));
3270 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3271 SpinButton spinner (adjustment, 0.0, 1);
3274 win.get_vbox()->set_spacing (12);
3275 win.get_vbox()->pack_start (hbox);
3276 hbox.set_border_width (6);
3277 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3279 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3280 place, visually. so do this by hand.
3283 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3284 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3285 spinner.grab_focus();
3291 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3292 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3293 win.set_default_response (RESPONSE_ACCEPT);
3295 win.set_position (WIN_POS_MOUSE);
3297 spinner.grab_focus ();
3299 switch (win.run ()) {
3300 case RESPONSE_ACCEPT:
3306 times = adjustment.get_value();
3309 if (mouse_mode == MouseRange) {
3310 duplicate_selection (times);
3312 duplicate_some_regions (rs, times);
3317 Editor::set_edit_mode (EditMode m)
3319 Config->set_edit_mode (m);
3323 Editor::cycle_edit_mode ()
3325 switch (Config->get_edit_mode()) {
3327 if (Profile->get_sae()) {
3328 Config->set_edit_mode (Lock);
3330 Config->set_edit_mode (Splice);
3334 Config->set_edit_mode (Lock);
3337 Config->set_edit_mode (Slide);
3343 Editor::edit_mode_selection_done ()
3345 string s = edit_mode_selector.get_active_text ();
3348 Config->set_edit_mode (string_to_edit_mode (s));
3353 Editor::snap_type_selection_done ()
3355 string choice = snap_type_selector.get_active_text();
3356 SnapType snaptype = SnapToBeat;
3358 if (choice == _("Beats/2")) {
3359 snaptype = SnapToBeatDiv2;
3360 } else if (choice == _("Beats/3")) {
3361 snaptype = SnapToBeatDiv3;
3362 } else if (choice == _("Beats/4")) {
3363 snaptype = SnapToBeatDiv4;
3364 } else if (choice == _("Beats/5")) {
3365 snaptype = SnapToBeatDiv5;
3366 } else if (choice == _("Beats/6")) {
3367 snaptype = SnapToBeatDiv6;
3368 } else if (choice == _("Beats/7")) {
3369 snaptype = SnapToBeatDiv7;
3370 } else if (choice == _("Beats/8")) {
3371 snaptype = SnapToBeatDiv8;
3372 } else if (choice == _("Beats/10")) {
3373 snaptype = SnapToBeatDiv10;
3374 } else if (choice == _("Beats/12")) {
3375 snaptype = SnapToBeatDiv12;
3376 } else if (choice == _("Beats/14")) {
3377 snaptype = SnapToBeatDiv14;
3378 } else if (choice == _("Beats/16")) {
3379 snaptype = SnapToBeatDiv16;
3380 } else if (choice == _("Beats/20")) {
3381 snaptype = SnapToBeatDiv20;
3382 } else if (choice == _("Beats/24")) {
3383 snaptype = SnapToBeatDiv24;
3384 } else if (choice == _("Beats/28")) {
3385 snaptype = SnapToBeatDiv28;
3386 } else if (choice == _("Beats/32")) {
3387 snaptype = SnapToBeatDiv32;
3388 } else if (choice == _("Beats/64")) {
3389 snaptype = SnapToBeatDiv64;
3390 } else if (choice == _("Beats/128")) {
3391 snaptype = SnapToBeatDiv128;
3392 } else if (choice == _("Beats")) {
3393 snaptype = SnapToBeat;
3394 } else if (choice == _("Bars")) {
3395 snaptype = SnapToBar;
3396 } else if (choice == _("Marks")) {
3397 snaptype = SnapToMark;
3398 } else if (choice == _("Region starts")) {
3399 snaptype = SnapToRegionStart;
3400 } else if (choice == _("Region ends")) {
3401 snaptype = SnapToRegionEnd;
3402 } else if (choice == _("Region bounds")) {
3403 snaptype = SnapToRegionBoundary;
3404 } else if (choice == _("Region syncs")) {
3405 snaptype = SnapToRegionSync;
3406 } else if (choice == _("CD Frames")) {
3407 snaptype = SnapToCDFrame;
3408 } else if (choice == _("Timecode Frames")) {
3409 snaptype = SnapToTimecodeFrame;
3410 } else if (choice == _("Timecode Seconds")) {
3411 snaptype = SnapToTimecodeSeconds;
3412 } else if (choice == _("Timecode Minutes")) {
3413 snaptype = SnapToTimecodeMinutes;
3414 } else if (choice == _("Seconds")) {
3415 snaptype = SnapToSeconds;
3416 } else if (choice == _("Minutes")) {
3417 snaptype = SnapToMinutes;
3420 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3422 ract->set_active ();
3427 Editor::snap_mode_selection_done ()
3429 string choice = snap_mode_selector.get_active_text();
3430 SnapMode mode = SnapNormal;
3432 if (choice == _("No Grid")) {
3434 } else if (choice == _("Grid")) {
3436 } else if (choice == _("Magnetic")) {
3437 mode = SnapMagnetic;
3440 RefPtr<RadioAction> ract = snap_mode_action (mode);
3443 ract->set_active (true);
3448 Editor::cycle_edit_point (bool with_marker)
3450 switch (_edit_point) {
3452 set_edit_point_preference (EditAtPlayhead);
3454 case EditAtPlayhead:
3456 set_edit_point_preference (EditAtSelectedMarker);
3458 set_edit_point_preference (EditAtMouse);
3461 case EditAtSelectedMarker:
3462 set_edit_point_preference (EditAtMouse);
3468 Editor::edit_point_selection_done ()
3470 string choice = edit_point_selector.get_active_text();
3471 EditPoint ep = EditAtSelectedMarker;
3473 if (choice == _("Marker")) {
3474 set_edit_point_preference (EditAtSelectedMarker);
3475 } else if (choice == _("Playhead")) {
3476 set_edit_point_preference (EditAtPlayhead);
3478 set_edit_point_preference (EditAtMouse);
3481 RefPtr<RadioAction> ract = edit_point_action (ep);
3484 ract->set_active (true);
3489 Editor::zoom_focus_selection_done ()
3491 string choice = zoom_focus_selector.get_active_text();
3492 ZoomFocus focus_type = ZoomFocusLeft;
3494 if (choice == _("Left")) {
3495 focus_type = ZoomFocusLeft;
3496 } else if (choice == _("Right")) {
3497 focus_type = ZoomFocusRight;
3498 } else if (choice == _("Center")) {
3499 focus_type = ZoomFocusCenter;
3500 } else if (choice == _("Playhead")) {
3501 focus_type = ZoomFocusPlayhead;
3502 } else if (choice == _("Mouse")) {
3503 focus_type = ZoomFocusMouse;
3504 } else if (choice == _("Edit point")) {
3505 focus_type = ZoomFocusEdit;
3508 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3511 ract->set_active ();
3516 Editor::edit_controls_button_release (GdkEventButton* ev)
3518 if (Keyboard::is_context_menu_event (ev)) {
3519 ARDOUR_UI::instance()->add_route (this);
3520 } else if (ev->button == 1) {
3521 selection->clear_tracks ();
3528 Editor::mouse_select_button_release (GdkEventButton* ev)
3530 /* this handles just right-clicks */
3532 if (ev->button != 3) {
3540 Editor::set_zoom_focus (ZoomFocus f)
3542 string str = zoom_focus_strings[(int)f];
3544 if (str != zoom_focus_selector.get_active_text()) {
3545 zoom_focus_selector.set_active_text (str);
3548 if (zoom_focus != f) {
3555 Editor::ensure_float (Window& win)
3557 win.set_transient_for (*this);
3561 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3563 /* recover or initialize pane positions. do this here rather than earlier because
3564 we don't want the positions to change the child allocations, which they seem to do.
3570 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3579 XMLNode* geometry = find_named_node (*node, "geometry");
3581 if (which == static_cast<Paned*> (&edit_pane)) {
3583 if (done & Horizontal) {
3587 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3588 _notebook_shrunk = string_is_affirmative (prop->value ());
3591 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3592 /* initial allocation is 90% to canvas, 10% to notebook */
3593 pos = (int) floor (alloc.get_width() * 0.90f);
3594 snprintf (buf, sizeof(buf), "%d", pos);
3596 pos = atoi (prop->value());
3599 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3600 edit_pane.set_position (pos);
3603 done = (Pane) (done | Horizontal);
3605 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3607 if (done & Vertical) {
3611 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3612 /* initial allocation is 90% to canvas, 10% to summary */
3613 pos = (int) floor (alloc.get_height() * 0.90f);
3614 snprintf (buf, sizeof(buf), "%d", pos);
3617 pos = atoi (prop->value());
3620 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3621 editor_summary_pane.set_position (pos);
3624 done = (Pane) (done | Vertical);
3629 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3631 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3632 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3633 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3634 top_hbox.remove (toolbar_frame);
3639 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3641 if (toolbar_frame.get_parent() == 0) {
3642 top_hbox.pack_end (toolbar_frame);
3647 Editor::set_show_measures (bool yn)
3649 if (_show_measures != yn) {
3652 if ((_show_measures = yn) == true) {
3654 tempo_lines->show();
3662 Editor::toggle_follow_playhead ()
3664 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3666 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3667 set_follow_playhead (tact->get_active());
3671 /** @param yn true to follow playhead, otherwise false.
3672 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3675 Editor::set_follow_playhead (bool yn, bool catch_up)
3677 if (_follow_playhead != yn) {
3678 if ((_follow_playhead = yn) == true && catch_up) {
3680 reset_x_origin_to_follow_playhead ();
3687 Editor::toggle_stationary_playhead ()
3689 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3691 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3692 set_stationary_playhead (tact->get_active());
3697 Editor::set_stationary_playhead (bool yn)
3699 if (_stationary_playhead != yn) {
3700 if ((_stationary_playhead = yn) == true) {
3702 // FIXME need a 3.0 equivalent of this 2.X call
3703 // update_current_screen ();
3710 Editor::playlist_selector () const
3712 return *_playlist_selector;
3716 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3720 switch (_snap_type) {
3725 case SnapToBeatDiv128:
3728 case SnapToBeatDiv64:
3731 case SnapToBeatDiv32:
3734 case SnapToBeatDiv28:
3737 case SnapToBeatDiv24:
3740 case SnapToBeatDiv20:
3743 case SnapToBeatDiv16:
3746 case SnapToBeatDiv14:
3749 case SnapToBeatDiv12:
3752 case SnapToBeatDiv10:
3755 case SnapToBeatDiv8:
3758 case SnapToBeatDiv7:
3761 case SnapToBeatDiv6:
3764 case SnapToBeatDiv5:
3767 case SnapToBeatDiv4:
3770 case SnapToBeatDiv3:
3773 case SnapToBeatDiv2:
3779 return _session->tempo_map().meter_at (position).divisions_per_bar();
3784 case SnapToTimecodeFrame:
3785 case SnapToTimecodeSeconds:
3786 case SnapToTimecodeMinutes:
3789 case SnapToRegionStart:
3790 case SnapToRegionEnd:
3791 case SnapToRegionSync:
3792 case SnapToRegionBoundary:
3802 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3806 ret = nudge_clock->current_duration (pos);
3807 next = ret + 1; /* XXXX fix me */
3813 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3815 ArdourDialog dialog (_("Playlist Deletion"));
3816 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3817 "If it is kept, its audio files will not be cleaned.\n"
3818 "If it is deleted, audio files used by it alone will be cleaned."),
3821 dialog.set_position (WIN_POS_CENTER);
3822 dialog.get_vbox()->pack_start (label);
3826 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3827 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3828 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3830 switch (dialog.run ()) {
3831 case RESPONSE_ACCEPT:
3832 /* delete the playlist */
3836 case RESPONSE_REJECT:
3837 /* keep the playlist */
3849 Editor::audio_region_selection_covers (framepos_t where)
3851 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3852 if ((*a)->region()->covers (where)) {
3861 Editor::prepare_for_cleanup ()
3863 cut_buffer->clear_regions ();
3864 cut_buffer->clear_playlists ();
3866 selection->clear_regions ();
3867 selection->clear_playlists ();
3869 _regions->suspend_redisplay ();
3873 Editor::finish_cleanup ()
3875 _regions->resume_redisplay ();
3879 Editor::transport_loop_location()
3882 return _session->locations()->auto_loop_location();
3889 Editor::transport_punch_location()
3892 return _session->locations()->auto_punch_location();
3899 Editor::control_layout_scroll (GdkEventScroll* ev)
3901 if (Keyboard::some_magic_widget_has_focus()) {
3905 switch (ev->direction) {
3907 scroll_tracks_up_line ();
3911 case GDK_SCROLL_DOWN:
3912 scroll_tracks_down_line ();
3916 /* no left/right handling yet */
3924 Editor::session_state_saved (string)
3927 _snapshots->redisplay ();
3931 Editor::update_tearoff_visibility()
3933 bool visible = Config->get_keep_tearoffs();
3934 _mouse_mode_tearoff->set_visible (visible);
3935 _tools_tearoff->set_visible (visible);
3936 _zoom_tearoff->set_visible (visible);
3940 Editor::maximise_editing_space ()
3952 Editor::restore_editing_space ()
3964 * Make new playlists for a given track and also any others that belong
3965 * to the same active route group with the `edit' property.
3970 Editor::new_playlists (TimeAxisView* v)
3972 begin_reversible_command (_("new playlists"));
3973 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3974 _session->playlists->get (playlists);
3975 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3976 commit_reversible_command ();
3980 * Use a copy of the current playlist for a given track and also any others that belong
3981 * to the same active route group with the `edit' property.
3986 Editor::copy_playlists (TimeAxisView* v)
3988 begin_reversible_command (_("copy playlists"));
3989 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3990 _session->playlists->get (playlists);
3991 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3992 commit_reversible_command ();
3995 /** Clear the current playlist for a given track and also any others that belong
3996 * to the same active route group with the `edit' property.
4001 Editor::clear_playlists (TimeAxisView* v)
4003 begin_reversible_command (_("clear playlists"));
4004 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4005 _session->playlists->get (playlists);
4006 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4007 commit_reversible_command ();
4011 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4013 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4017 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4019 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4023 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4025 atv.clear_playlist ();
4029 Editor::on_key_press_event (GdkEventKey* ev)
4031 return key_press_focus_accelerator_handler (*this, ev);
4035 Editor::on_key_release_event (GdkEventKey* ev)
4037 return Gtk::Window::on_key_release_event (ev);
4038 // return key_press_focus_accelerator_handler (*this, ev);
4041 /** Queue up a change to the viewport x origin.
4042 * @param frame New x origin.
4045 Editor::reset_x_origin (framepos_t frame)
4047 pending_visual_change.add (VisualChange::TimeOrigin);
4048 pending_visual_change.time_origin = frame;
4049 ensure_visual_change_idle_handler ();
4053 Editor::reset_y_origin (double y)
4055 pending_visual_change.add (VisualChange::YOrigin);
4056 pending_visual_change.y_origin = y;
4057 ensure_visual_change_idle_handler ();
4061 Editor::reset_zoom (double fpu)
4063 clamp_frames_per_unit (fpu);
4065 if (fpu == frames_per_unit) {
4069 pending_visual_change.add (VisualChange::ZoomLevel);
4070 pending_visual_change.frames_per_unit = fpu;
4071 ensure_visual_change_idle_handler ();
4075 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4077 reset_x_origin (frame);
4080 if (!no_save_visual) {
4081 undo_visual_stack.push_back (current_visual_state(false));
4085 Editor::VisualState::VisualState (bool with_tracks)
4086 : gui_state (with_tracks ? new GUIObjectState : 0)
4090 Editor::VisualState::~VisualState ()
4095 Editor::VisualState*
4096 Editor::current_visual_state (bool with_tracks)
4098 VisualState* vs = new VisualState (with_tracks);
4099 vs->y_position = vertical_adjustment.get_value();
4100 vs->frames_per_unit = frames_per_unit;
4101 vs->leftmost_frame = leftmost_frame;
4102 vs->zoom_focus = zoom_focus;
4105 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4112 Editor::undo_visual_state ()
4114 if (undo_visual_stack.empty()) {
4118 VisualState* vs = undo_visual_stack.back();
4119 undo_visual_stack.pop_back();
4122 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4124 use_visual_state (*vs);
4128 Editor::redo_visual_state ()
4130 if (redo_visual_stack.empty()) {
4134 VisualState* vs = redo_visual_stack.back();
4135 redo_visual_stack.pop_back();
4137 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4139 use_visual_state (*vs);
4143 Editor::swap_visual_state ()
4145 if (undo_visual_stack.empty()) {
4146 redo_visual_state ();
4148 undo_visual_state ();
4153 Editor::use_visual_state (VisualState& vs)
4155 PBD::Unwinder<bool> nsv (no_save_visual, true);
4157 _routes->suspend_redisplay ();
4159 vertical_adjustment.set_value (vs.y_position);
4161 set_zoom_focus (vs.zoom_focus);
4162 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4165 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4167 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4168 (*i)->reset_visual_state ();
4172 _routes->update_visibility ();
4173 _routes->resume_redisplay ();
4176 /** This is the core function that controls the zoom level of the canvas. It is called
4177 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4178 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4181 Editor::set_frames_per_unit (double fpu)
4184 tempo_lines->tempo_map_changed();
4187 frames_per_unit = fpu;
4189 /* convert fpu to frame count */
4191 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4193 if (frames_per_unit != zoom_range_clock->current_duration()) {
4194 zoom_range_clock->set (frames);
4197 bool const showing_time_selection =
4198 mouse_mode == MouseRange ||
4199 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4201 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4202 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4203 (*i)->reshow_selection (selection->time);
4207 ZoomChanged (); /* EMIT_SIGNAL */
4209 //reset_scrolling_region ();
4211 if (playhead_cursor) {
4212 playhead_cursor->set_position (playhead_cursor->current_frame);
4215 refresh_location_display();
4216 _summary->set_overlays_dirty ();
4218 update_marker_labels ();
4224 Editor::ensure_visual_change_idle_handler ()
4226 if (pending_visual_change.idle_handler_id < 0) {
4227 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4232 Editor::_idle_visual_changer (void* arg)
4234 return static_cast<Editor*>(arg)->idle_visual_changer ();
4238 Editor::idle_visual_changer ()
4240 /* set_horizontal_position() below (and maybe other calls) call
4241 gtk_main_iteration(), so it's possible that a signal will be handled
4242 half-way through this method. If this signal wants an
4243 idle_visual_changer we must schedule another one after this one, so
4244 mark the idle_handler_id as -1 here to allow that. Also make a note
4245 that we are doing the visual change, so that changes in response to
4246 super-rapid-screen-update can be dropped if we are still processing
4249 pending_visual_change.idle_handler_id = -1;
4250 pending_visual_change.being_handled = true;
4252 VisualChange::Type p = pending_visual_change.pending;
4253 pending_visual_change.pending = (VisualChange::Type) 0;
4255 double const last_time_origin = horizontal_position ();
4257 if (p & VisualChange::ZoomLevel) {
4258 set_frames_per_unit (pending_visual_change.frames_per_unit);
4260 compute_fixed_ruler_scale ();
4261 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4262 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4263 update_tempo_based_rulers ();
4265 if (p & VisualChange::TimeOrigin) {
4266 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4268 if (p & VisualChange::YOrigin) {
4269 vertical_adjustment.set_value (pending_visual_change.y_origin);
4272 if (last_time_origin == horizontal_position ()) {
4273 /* changed signal not emitted */
4274 update_fixed_rulers ();
4275 redisplay_tempo (true);
4278 _summary->set_overlays_dirty ();
4280 pending_visual_change.being_handled = false;
4281 return 0; /* this is always a one-shot call */
4284 struct EditorOrderTimeAxisSorter {
4285 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4286 return a->order () < b->order ();
4291 Editor::sort_track_selection (TrackViewList& sel)
4293 EditorOrderTimeAxisSorter cmp;
4298 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4301 framepos_t where = 0;
4302 EditPoint ep = _edit_point;
4304 if (from_context_menu && (ep == EditAtMouse)) {
4305 return event_frame (&context_click_event, 0, 0);
4308 if (entered_marker) {
4309 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4310 return entered_marker->position();
4313 if (ignore_playhead && ep == EditAtPlayhead) {
4314 ep = EditAtSelectedMarker;
4318 case EditAtPlayhead:
4319 where = _session->audible_frame();
4320 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4323 case EditAtSelectedMarker:
4324 if (!selection->markers.empty()) {
4326 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4329 where = loc->start();
4333 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4341 if (!mouse_frame (where, ignored)) {
4342 /* XXX not right but what can we do ? */
4346 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4354 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4356 if (!_session) return;
4358 begin_reversible_command (cmd);
4362 if ((tll = transport_loop_location()) == 0) {
4363 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4364 XMLNode &before = _session->locations()->get_state();
4365 _session->locations()->add (loc, true);
4366 _session->set_auto_loop_location (loc);
4367 XMLNode &after = _session->locations()->get_state();
4368 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4370 XMLNode &before = tll->get_state();
4371 tll->set_hidden (false, this);
4372 tll->set (start, end);
4373 XMLNode &after = tll->get_state();
4374 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4377 commit_reversible_command ();
4381 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4383 if (!_session) return;
4385 begin_reversible_command (cmd);
4389 if ((tpl = transport_punch_location()) == 0) {
4390 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4391 XMLNode &before = _session->locations()->get_state();
4392 _session->locations()->add (loc, true);
4393 _session->set_auto_loop_location (loc);
4394 XMLNode &after = _session->locations()->get_state();
4395 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4398 XMLNode &before = tpl->get_state();
4399 tpl->set_hidden (false, this);
4400 tpl->set (start, end);
4401 XMLNode &after = tpl->get_state();
4402 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4405 commit_reversible_command ();
4408 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4409 * @param rs List to which found regions are added.
4410 * @param where Time to look at.
4411 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4414 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4416 const TrackViewList* tracks;
4419 tracks = &track_views;
4424 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4426 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4429 boost::shared_ptr<Track> tr;
4430 boost::shared_ptr<Playlist> pl;
4432 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4434 boost::shared_ptr<RegionList> regions = pl->regions_at (
4435 (framepos_t) floor ( (double) where * tr->speed()));
4437 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4438 RegionView* rv = rtv->view()->find_view (*i);
4449 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4451 const TrackViewList* tracks;
4454 tracks = &track_views;
4459 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4460 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4462 boost::shared_ptr<Track> tr;
4463 boost::shared_ptr<Playlist> pl;
4465 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4467 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4468 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4470 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4472 RegionView* rv = rtv->view()->find_view (*i);
4483 /** Start with regions that are selected. Then add equivalent regions
4484 * on tracks in the same active edit-enabled route group as any of
4485 * the regions that we started with.
4489 Editor::get_regions_from_selection ()
4491 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4494 /** Get regions using the following method:
4496 * Make an initial region list using the selected regions, unless
4497 * the edit point is `mouse' and the mouse is over an unselected
4498 * region. In this case, start with just that region.
4500 * Then, add equivalent regions in active edit groups to the region list.
4502 * Then, search the list of selected tracks to find any selected tracks which
4503 * do not contain regions already in the region list. If there are no selected
4504 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4505 * than just the selected.
4507 * Add any regions that are under the edit point on these tracks to get the
4508 * returned region list.
4510 * The rationale here is that the mouse edit point is special in that
4511 * its position describes both a time and a track; the other edit
4512 * modes only describe a time. Hence if the edit point is `mouse' we
4513 * ignore selected tracks, as we assume the user means something by
4514 * pointing at a particular track. Also in this case we take note of
4515 * the region directly under the edit point, as there is always just one
4516 * (rather than possibly several with non-mouse edit points).
4520 Editor::get_regions_from_selection_and_edit_point ()
4522 RegionSelection regions;
4524 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4525 regions.add (entered_regionview);
4527 regions = selection->regions;
4530 TrackViewList tracks;
4532 if (_edit_point != EditAtMouse) {
4533 tracks = selection->tracks;
4536 /* Add any other regions that are in the same
4537 edit-activated route group as one of our regions.
4539 regions = get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4540 framepos_t const where = get_preferred_edit_position ();
4542 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4543 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4544 * is enabled, so consider all tracks
4546 tracks = track_views;
4549 if (!tracks.empty()) {
4550 /* now search the selected tracks for tracks which don't
4551 already contain regions to be acted upon, and get regions at
4552 the edit point on those tracks too.
4554 TrackViewList tracks_without_relevant_regions;
4556 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4557 if (!regions.involves (**t)) {
4558 /* there are no equivalent regions on this track */
4559 tracks_without_relevant_regions.push_back (*t);
4563 if (!tracks_without_relevant_regions.empty()) {
4564 /* there are some selected tracks with neither selected
4565 * regions or their equivalents: act upon all regions in
4568 get_regions_at (regions, where, tracks_without_relevant_regions);
4575 /** Start with regions that are selected, or the entered regionview if none are selected.
4576 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4577 * of the regions that we started with.
4581 Editor::get_regions_from_selection_and_entered ()
4583 RegionSelection regions = selection->regions;
4585 if (regions.empty() && entered_regionview) {
4586 regions.add (entered_regionview);
4589 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4593 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4595 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4597 RouteTimeAxisView* tatv;
4599 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4601 boost::shared_ptr<Playlist> pl;
4602 vector<boost::shared_ptr<Region> > results;
4604 boost::shared_ptr<Track> tr;
4606 if ((tr = tatv->track()) == 0) {
4611 if ((pl = (tr->playlist())) != 0) {
4612 pl->get_region_list_equivalent_regions (region, results);
4615 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4616 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4617 regions.push_back (marv);
4626 Editor::show_rhythm_ferret ()
4628 if (rhythm_ferret == 0) {
4629 rhythm_ferret = new RhythmFerret(*this);
4632 rhythm_ferret->set_session (_session);
4633 rhythm_ferret->show ();
4634 rhythm_ferret->present ();
4638 Editor::first_idle ()
4640 MessageDialog* dialog = 0;
4642 if (track_views.size() > 1) {
4643 dialog = new MessageDialog (
4645 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4649 ARDOUR_UI::instance()->flush_pending ();
4652 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4656 // first idle adds route children (automation tracks), so we need to redisplay here
4657 _routes->redisplay ();
4664 Editor::_idle_resize (gpointer arg)
4666 return ((Editor*)arg)->idle_resize ();
4670 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4672 if (resize_idle_id < 0) {
4673 resize_idle_id = g_idle_add (_idle_resize, this);
4674 _pending_resize_amount = 0;
4677 /* make a note of the smallest resulting height, so that we can clamp the
4678 lower limit at TimeAxisView::hSmall */
4680 int32_t min_resulting = INT32_MAX;
4682 _pending_resize_amount += h;
4683 _pending_resize_view = view;
4685 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4687 if (selection->tracks.contains (_pending_resize_view)) {
4688 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4689 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4693 if (min_resulting < 0) {
4698 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4699 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4703 /** Handle pending resizing of tracks */
4705 Editor::idle_resize ()
4707 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4709 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4710 selection->tracks.contains (_pending_resize_view)) {
4712 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4713 if (*i != _pending_resize_view) {
4714 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4719 _pending_resize_amount = 0;
4721 _group_tabs->set_dirty ();
4722 resize_idle_id = -1;
4730 ENSURE_GUI_THREAD (*this, &Editor::located);
4733 playhead_cursor->set_position (_session->audible_frame ());
4734 if (_follow_playhead && !_pending_initial_locate) {
4735 reset_x_origin_to_follow_playhead ();
4739 _pending_locate_request = false;
4740 _pending_initial_locate = false;
4744 Editor::region_view_added (RegionView *)
4746 _summary->set_dirty ();
4750 Editor::region_view_removed ()
4752 _summary->set_dirty ();
4756 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4758 TrackViewList::const_iterator j = track_views.begin ();
4759 while (j != track_views.end()) {
4760 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4761 if (rtv && rtv->route() == r) {
4772 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4776 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4777 TimeAxisView* tv = axis_view_from_route (*i);
4787 Editor::add_routes (RouteList& routes)
4789 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4791 RouteTimeAxisView *rtv;
4792 list<RouteTimeAxisView*> new_views;
4794 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4795 boost::shared_ptr<Route> route = (*x);
4797 if (route->is_hidden() || route->is_monitor()) {
4801 DataType dt = route->input()->default_type();
4803 if (dt == ARDOUR::DataType::AUDIO) {
4804 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4805 rtv->set_route (route);
4806 } else if (dt == ARDOUR::DataType::MIDI) {
4807 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4808 rtv->set_route (route);
4810 throw unknown_type();
4813 new_views.push_back (rtv);
4814 track_views.push_back (rtv);
4816 rtv->effective_gain_display ();
4818 if (internal_editing()) {
4819 rtv->enter_internal_edit_mode ();
4821 rtv->leave_internal_edit_mode ();
4824 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4825 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4828 _routes->routes_added (new_views);
4829 _summary->routes_added (new_views);
4831 if (show_editor_mixer_when_tracks_arrive) {
4832 show_editor_mixer (true);
4835 editor_list_button.set_sensitive (true);
4839 Editor::timeaxisview_deleted (TimeAxisView *tv)
4841 if (_session && _session->deletion_in_progress()) {
4842 /* the situation is under control */
4846 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4848 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4850 _routes->route_removed (tv);
4852 if (tv == entered_track) {
4856 TimeAxisView::Children c = tv->get_child_list ();
4857 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4858 if (entered_track == i->get()) {
4863 /* remove it from the list of track views */
4865 TrackViewList::iterator i;
4867 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4868 i = track_views.erase (i);
4871 /* update whatever the current mixer strip is displaying, if revelant */
4873 boost::shared_ptr<Route> route;
4876 route = rtav->route ();
4879 if (current_mixer_strip && current_mixer_strip->route() == route) {
4881 TimeAxisView* next_tv;
4883 if (track_views.empty()) {
4885 } else if (i == track_views.end()) {
4886 next_tv = track_views.front();
4893 set_selected_mixer_strip (*next_tv);
4895 /* make the editor mixer strip go away setting the
4896 * button to inactive (which also unticks the menu option)
4899 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4905 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4907 if (apply_to_selection) {
4908 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4910 TrackSelection::iterator j = i;
4913 hide_track_in_display (*i, false);
4918 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4920 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4921 // this will hide the mixer strip
4922 set_selected_mixer_strip (*tv);
4925 _routes->hide_track_in_display (*tv);
4930 Editor::sync_track_view_list_and_routes ()
4932 track_views = TrackViewList (_routes->views ());
4934 _summary->set_dirty ();
4935 _group_tabs->set_dirty ();
4937 return false; // do not call again (until needed)
4941 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4943 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4948 /** Find a RouteTimeAxisView by the ID of its route */
4950 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4952 RouteTimeAxisView* v;
4954 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4955 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4956 if(v->route()->id() == id) {
4966 Editor::fit_route_group (RouteGroup *g)
4968 TrackViewList ts = axis_views_from_routes (g->route_list ());
4973 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4975 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4978 _session->cancel_audition ();
4982 if (_session->is_auditioning()) {
4983 _session->cancel_audition ();
4984 if (r == last_audition_region) {
4989 _session->audition_region (r);
4990 last_audition_region = r;
4995 Editor::hide_a_region (boost::shared_ptr<Region> r)
4997 r->set_hidden (true);
5001 Editor::show_a_region (boost::shared_ptr<Region> r)
5003 r->set_hidden (false);
5007 Editor::audition_region_from_region_list ()
5009 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5013 Editor::hide_region_from_region_list ()
5015 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5019 Editor::show_region_in_region_list ()
5021 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5025 Editor::step_edit_status_change (bool yn)
5028 start_step_editing ();
5030 stop_step_editing ();
5035 Editor::start_step_editing ()
5037 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5041 Editor::stop_step_editing ()
5043 step_edit_connection.disconnect ();
5047 Editor::check_step_edit ()
5049 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5050 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5052 mtv->check_step_edit ();
5056 return true; // do it again, till we stop
5060 Editor::scroll_press (Direction dir)
5062 ++_scroll_callbacks;
5064 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5065 /* delay the first auto-repeat */
5071 scroll_backward (1);
5079 scroll_tracks_up_line ();
5083 scroll_tracks_down_line ();
5087 /* do hacky auto-repeat */
5088 if (!_scroll_connection.connected ()) {
5090 _scroll_connection = Glib::signal_timeout().connect (
5091 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5094 _scroll_callbacks = 0;
5101 Editor::scroll_release ()
5103 _scroll_connection.disconnect ();
5106 /** Queue a change for the Editor viewport x origin to follow the playhead */
5108 Editor::reset_x_origin_to_follow_playhead ()
5110 framepos_t const frame = playhead_cursor->current_frame;
5112 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5114 if (_session->transport_speed() < 0) {
5116 if (frame > (current_page_frames() / 2)) {
5117 center_screen (frame-(current_page_frames()/2));
5119 center_screen (current_page_frames()/2);
5126 if (frame < leftmost_frame) {
5128 if (_session->transport_rolling()) {
5129 /* rolling; end up with the playhead at the right of the page */
5130 l = frame - current_page_frames ();
5132 /* not rolling: end up with the playhead 1/4 of the way along the page */
5133 l = frame - current_page_frames() / 4;
5137 if (_session->transport_rolling()) {
5138 /* rolling: end up with the playhead on the left of the page */
5141 /* not rolling: end up with the playhead 3/4 of the way along the page */
5142 l = frame - 3 * current_page_frames() / 4;
5150 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5156 Editor::super_rapid_screen_update ()
5158 if (!_session || !_session->engine().running()) {
5162 /* METERING / MIXER STRIPS */
5164 /* update track meters, if required */
5165 if (is_mapped() && meters_running) {
5166 RouteTimeAxisView* rtv;
5167 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5168 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5169 rtv->fast_update ();
5174 /* and any current mixer strip */
5175 if (current_mixer_strip) {
5176 current_mixer_strip->fast_update ();
5179 /* PLAYHEAD AND VIEWPORT */
5181 framepos_t const frame = _session->audible_frame();
5183 /* There are a few reasons why we might not update the playhead / viewport stuff:
5185 * 1. we don't update things when there's a pending locate request, otherwise
5186 * when the editor requests a locate there is a chance that this method
5187 * will move the playhead before the locate request is processed, causing
5189 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5190 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5193 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5195 last_update_frame = frame;
5197 if (!_dragging_playhead) {
5198 playhead_cursor->set_position (frame);
5201 if (!_stationary_playhead) {
5203 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5204 /* We only do this if we aren't already
5205 handling a visual change (ie if
5206 pending_visual_change.being_handled is
5207 false) so that these requests don't stack
5208 up there are too many of them to handle in
5211 reset_x_origin_to_follow_playhead ();
5216 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5220 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5221 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5222 if (target <= 0.0) {
5225 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5226 target = (target * 0.15) + (current * 0.85);
5232 set_horizontal_position (current);
5241 Editor::session_going_away ()
5243 _have_idled = false;
5245 _session_connections.drop_connections ();
5247 super_rapid_screen_update_connection.disconnect ();
5249 selection->clear ();
5250 cut_buffer->clear ();
5252 clicked_regionview = 0;
5253 clicked_axisview = 0;
5254 clicked_routeview = 0;
5255 entered_regionview = 0;
5257 last_update_frame = 0;
5260 playhead_cursor->canvas_item.hide ();
5262 /* rip everything out of the list displays */
5266 _route_groups->clear ();
5268 /* do this first so that deleting a track doesn't reset cms to null
5269 and thus cause a leak.
5272 if (current_mixer_strip) {
5273 if (current_mixer_strip->get_parent() != 0) {
5274 global_hpacker.remove (*current_mixer_strip);
5276 delete current_mixer_strip;
5277 current_mixer_strip = 0;
5280 /* delete all trackviews */
5282 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5285 track_views.clear ();
5287 zoom_range_clock->set_session (0);
5288 nudge_clock->set_session (0);
5290 editor_list_button.set_active(false);
5291 editor_list_button.set_sensitive(false);
5293 /* clear tempo/meter rulers */
5294 remove_metric_marks ();
5296 clear_marker_display ();
5298 stop_step_editing ();
5300 current_bbt_points_begin = current_bbt_points_end;
5302 /* get rid of any existing editor mixer strip */
5304 WindowTitle title(Glib::get_application_name());
5305 title += _("Editor");
5307 set_title (title.get_string());
5309 SessionHandlePtr::session_going_away ();
5314 Editor::show_editor_list (bool yn)
5317 _the_notebook.show ();
5319 _the_notebook.hide ();
5324 Editor::change_region_layering_order (bool from_context_menu)
5326 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5328 if (!clicked_routeview) {
5329 if (layering_order_editor) {
5330 layering_order_editor->hide ();
5335 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5341 boost::shared_ptr<Playlist> pl = track->playlist();
5347 if (layering_order_editor == 0) {
5348 layering_order_editor = new RegionLayeringOrderEditor (*this);
5349 layering_order_editor->set_position (WIN_POS_MOUSE);
5352 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5353 layering_order_editor->maybe_present ();
5357 Editor::update_region_layering_order_editor ()
5359 if (layering_order_editor && layering_order_editor->is_visible ()) {
5360 change_region_layering_order (true);
5365 Editor::setup_fade_images ()
5367 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5368 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5369 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5370 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5371 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5373 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5374 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5375 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5376 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5377 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5379 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5380 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5381 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5382 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5383 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5385 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5386 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5387 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5388 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5389 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5393 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5395 Editor::action_menu_item (std::string const & name)
5397 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5400 return *manage (a->create_menu_item ());
5404 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5406 EventBox* b = manage (new EventBox);
5407 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5408 Label* l = manage (new Label (name));
5412 _the_notebook.append_page (widget, *b);
5416 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5418 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5419 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5422 if (ev->type == GDK_2BUTTON_PRESS) {
5424 /* double-click on a notebook tab shrinks or expands the notebook */
5426 if (_notebook_shrunk) {
5427 if (pre_notebook_shrink_pane_width) {
5428 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5430 _notebook_shrunk = false;
5432 pre_notebook_shrink_pane_width = edit_pane.get_position();
5434 /* this expands the LHS of the edit pane to cover the notebook
5435 PAGE but leaves the tabs visible.
5437 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5438 _notebook_shrunk = true;
5446 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5448 using namespace Menu_Helpers;
5450 MenuList& items = _control_point_context_menu.items ();
5453 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5454 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5455 if (!can_remove_control_point (item)) {
5456 items.back().set_sensitive (false);
5459 _control_point_context_menu.popup (event->button.button, event->button.time);
5463 Editor::shift_key_released ()
5465 _stepping_axis_view = 0;