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 show_me_the_size (Requisition* r, const char* what)
214 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
219 pane_size_watcher (Paned* pane)
221 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
222 it is no longer accessible. so stop that. this doesn't happen on X11,
223 just the quartz backend.
228 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
230 gint pos = pane->get_position ();
232 if (pos > max_width_of_lhs) {
233 pane->set_position (max_width_of_lhs);
239 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
241 /* time display buttons */
242 , minsec_label (_("Mins:Secs"))
243 , bbt_label (_("Bars:Beats"))
244 , timecode_label (_("Timecode"))
245 , samples_label (_("Samples"))
246 , tempo_label (_("Tempo"))
247 , meter_label (_("Meter"))
248 , mark_label (_("Location Markers"))
249 , range_mark_label (_("Range Markers"))
250 , transport_mark_label (_("Loop/Punch Ranges"))
251 , cd_mark_label (_("CD Markers"))
252 , edit_packer (4, 4, true)
254 /* the values here don't matter: layout widgets
255 reset them as needed.
258 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260 /* tool bar related */
262 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
264 , toolbar_selection_clock_table (2,3)
266 , automation_mode_button (_("mode"))
268 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271 , image_socket_listener(0)
276 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
277 , meters_running(false)
278 , _pending_locate_request (false)
279 , _pending_initial_locate (false)
280 , _last_cut_copy_source_track (0)
282 , _region_selection_change_updates_region_list (true)
283 , _following_mixer_selection (false)
287 /* we are a singleton */
289 PublicEditor::_instance = this;
293 selection = new Selection (this);
294 cut_buffer = new Selection (this);
296 clicked_regionview = 0;
297 clicked_axisview = 0;
298 clicked_routeview = 0;
299 clicked_control_point = 0;
300 last_update_frame = 0;
301 pre_press_cursor = 0;
302 _drags = new DragManager (this);
303 current_mixer_strip = 0;
306 snap_type_strings = I18N (_snap_type_strings);
307 snap_mode_strings = I18N (_snap_mode_strings);
308 zoom_focus_strings = I18N (_zoom_focus_strings);
309 edit_point_strings = I18N (_edit_point_strings);
310 #ifdef USE_RUBBERBAND
311 rb_opt_strings = I18N (_rb_opt_strings);
315 snap_threshold = 5.0;
316 bbt_beat_subdivision = 4;
319 last_autoscroll_x = 0;
320 last_autoscroll_y = 0;
321 autoscroll_active = false;
322 autoscroll_timeout_tag = -1;
327 current_interthread_info = 0;
328 _show_measures = true;
330 show_gain_after_trim = false;
332 have_pending_keyboard_selection = false;
333 _follow_playhead = true;
334 _stationary_playhead = false;
335 editor_ruler_menu = 0;
336 no_ruler_shown_update = false;
338 range_marker_menu = 0;
339 marker_menu_item = 0;
340 tempo_or_meter_marker_menu = 0;
341 transport_marker_menu = 0;
342 new_transport_marker_menu = 0;
343 editor_mixer_strip_width = Wide;
344 show_editor_mixer_when_tracks_arrive = false;
345 region_edit_menu_split_multichannel_item = 0;
346 region_edit_menu_split_item = 0;
349 current_stepping_trackview = 0;
351 entered_regionview = 0;
353 clear_entered_track = false;
356 button_release_can_deselect = true;
357 _dragging_playhead = false;
358 _dragging_edit_point = false;
359 select_new_marker = false;
361 layering_order_editor = 0;
362 no_save_visual = false;
364 within_track_canvas = false;
366 scrubbing_direction = 0;
370 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
371 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
372 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
373 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
374 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
376 _edit_point = EditAtMouse;
377 _internal_editing = false;
378 current_canvas_cursor = 0;
380 frames_per_unit = 2048; /* too early to use reset_zoom () */
382 _scroll_callbacks = 0;
384 zoom_focus = ZoomFocusLeft;
385 set_zoom_focus (ZoomFocusLeft);
386 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
388 bbt_label.set_name ("EditorTimeButton");
389 bbt_label.set_size_request (-1, (int)timebar_height);
390 bbt_label.set_alignment (1.0, 0.5);
391 bbt_label.set_padding (5,0);
393 bbt_label.set_no_show_all();
394 minsec_label.set_name ("EditorTimeButton");
395 minsec_label.set_size_request (-1, (int)timebar_height);
396 minsec_label.set_alignment (1.0, 0.5);
397 minsec_label.set_padding (5,0);
398 minsec_label.hide ();
399 minsec_label.set_no_show_all();
400 timecode_label.set_name ("EditorTimeButton");
401 timecode_label.set_size_request (-1, (int)timebar_height);
402 timecode_label.set_alignment (1.0, 0.5);
403 timecode_label.set_padding (5,0);
404 timecode_label.hide ();
405 timecode_label.set_no_show_all();
406 samples_label.set_name ("EditorTimeButton");
407 samples_label.set_size_request (-1, (int)timebar_height);
408 samples_label.set_alignment (1.0, 0.5);
409 samples_label.set_padding (5,0);
410 samples_label.hide ();
411 samples_label.set_no_show_all();
413 tempo_label.set_name ("EditorTimeButton");
414 tempo_label.set_size_request (-1, (int)timebar_height);
415 tempo_label.set_alignment (1.0, 0.5);
416 tempo_label.set_padding (5,0);
418 tempo_label.set_no_show_all();
420 meter_label.set_name ("EditorTimeButton");
421 meter_label.set_size_request (-1, (int)timebar_height);
422 meter_label.set_alignment (1.0, 0.5);
423 meter_label.set_padding (5,0);
425 meter_label.set_no_show_all();
427 mark_label.set_name ("EditorTimeButton");
428 mark_label.set_size_request (-1, (int)timebar_height);
429 mark_label.set_alignment (1.0, 0.5);
430 mark_label.set_padding (5,0);
432 mark_label.set_no_show_all();
434 cd_mark_label.set_name ("EditorTimeButton");
435 cd_mark_label.set_size_request (-1, (int)timebar_height);
436 cd_mark_label.set_alignment (1.0, 0.5);
437 cd_mark_label.set_padding (5,0);
438 cd_mark_label.hide();
439 cd_mark_label.set_no_show_all();
441 range_mark_label.set_name ("EditorTimeButton");
442 range_mark_label.set_size_request (-1, (int)timebar_height);
443 range_mark_label.set_alignment (1.0, 0.5);
444 range_mark_label.set_padding (5,0);
445 range_mark_label.hide();
446 range_mark_label.set_no_show_all();
448 transport_mark_label.set_name ("EditorTimeButton");
449 transport_mark_label.set_size_request (-1, (int)timebar_height);
450 transport_mark_label.set_alignment (1.0, 0.5);
451 transport_mark_label.set_padding (5,0);
452 transport_mark_label.hide();
453 transport_mark_label.set_no_show_all();
455 initialize_rulers ();
456 initialize_canvas ();
458 _summary = new EditorSummary (this);
460 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
461 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
463 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
465 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
466 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
468 edit_controls_vbox.set_spacing (0);
469 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
470 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
472 HBox* h = manage (new HBox);
473 _group_tabs = new EditorGroupTabs (this);
474 h->pack_start (*_group_tabs, PACK_SHRINK);
475 h->pack_start (edit_controls_vbox);
476 controls_layout.add (*h);
478 controls_layout.set_name ("EditControlsBase");
479 controls_layout.add_events (Gdk::SCROLL_MASK);
480 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
482 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
483 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
485 _cursors = new MouseCursors;
487 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
488 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
489 0.0, 1.0, 100.0, 1.0));
491 pad_line_1->property_color_rgba() = 0xFF0000FF;
496 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
497 time_canvas_vbox.set_size_request (-1, -1);
499 ruler_label_event_box.add (ruler_label_vbox);
500 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
501 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
503 time_button_event_box.add (time_button_vbox);
504 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
505 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
507 /* these enable us to have a dedicated window (for cursor setting, etc.)
508 for the canvas areas.
511 track_canvas_event_box.add (*track_canvas);
513 time_canvas_event_box.add (time_canvas_vbox);
514 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
516 edit_packer.set_col_spacings (0);
517 edit_packer.set_row_spacings (0);
518 edit_packer.set_homogeneous (false);
519 edit_packer.set_border_width (0);
520 edit_packer.set_name ("EditorWindow");
522 /* labels for the rulers */
523 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
524 /* labels for the marker "tracks" */
525 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
527 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
529 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
531 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
533 bottom_hbox.set_border_width (2);
534 bottom_hbox.set_spacing (3);
536 _route_groups = new EditorRouteGroups (this);
537 _routes = new EditorRoutes (this);
538 _regions = new EditorRegions (this);
539 _snapshots = new EditorSnapshots (this);
540 _locations = new EditorLocations (this);
542 add_notebook_page (_("Regions"), _regions->widget ());
543 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
544 add_notebook_page (_("Snapshots"), _snapshots->widget ());
545 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
546 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
548 _the_notebook.set_show_tabs (true);
549 _the_notebook.set_scrollable (true);
550 _the_notebook.popup_disable ();
551 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
552 _the_notebook.show_all ();
554 _notebook_shrunk = false;
556 editor_summary_pane.pack1(edit_packer);
558 Button* summary_arrows_left_left = manage (new Button);
559 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
560 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
561 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
563 Button* summary_arrows_left_right = manage (new Button);
564 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
565 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
566 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
568 VBox* summary_arrows_left = manage (new VBox);
569 summary_arrows_left->pack_start (*summary_arrows_left_left);
570 summary_arrows_left->pack_start (*summary_arrows_left_right);
572 Button* summary_arrows_right_up = manage (new Button);
573 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
574 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
575 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 Button* summary_arrows_right_down = manage (new Button);
578 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
579 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
580 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 VBox* summary_arrows_right = manage (new VBox);
583 summary_arrows_right->pack_start (*summary_arrows_right_up);
584 summary_arrows_right->pack_start (*summary_arrows_right_down);
586 Frame* summary_frame = manage (new Frame);
587 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
589 summary_frame->add (*_summary);
590 summary_frame->show ();
592 _summary_hbox.pack_start (*summary_arrows_left, false, false);
593 _summary_hbox.pack_start (*summary_frame, true, true);
594 _summary_hbox.pack_start (*summary_arrows_right, false, false);
596 editor_summary_pane.pack2 (_summary_hbox);
598 edit_pane.pack1 (editor_summary_pane, true, true);
599 edit_pane.pack2 (_the_notebook, false, true);
601 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
603 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
605 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
607 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
608 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
610 top_hbox.pack_start (toolbar_frame);
612 HBox *hbox = manage (new HBox);
613 hbox->pack_start (edit_pane, true, true);
615 global_vpacker.pack_start (top_hbox, false, false);
616 global_vpacker.pack_start (*hbox, true, true);
618 global_hpacker.pack_start (global_vpacker, true, true);
620 set_name ("EditorWindow");
621 add_accel_group (ActionManager::ui_manager->get_accel_group());
623 status_bar_hpacker.show ();
625 vpacker.pack_end (status_bar_hpacker, false, false);
626 vpacker.pack_end (global_hpacker, true, true);
628 /* register actions now so that set_state() can find them and set toggles/checks etc */
631 /* when we start using our own keybinding system for the editor, this
632 * will be uncommented
638 _snap_type = SnapToBeat;
639 set_snap_to (_snap_type);
640 _snap_mode = SnapOff;
641 set_snap_mode (_snap_mode);
642 set_mouse_mode (MouseObject, true);
643 pre_internal_mouse_mode = MouseObject;
644 pre_internal_snap_type = _snap_type;
645 pre_internal_snap_mode = _snap_mode;
646 internal_snap_type = _snap_type;
647 internal_snap_mode = _snap_mode;
648 set_edit_point_preference (EditAtMouse, true);
650 _playlist_selector = new PlaylistSelector();
651 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
653 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
657 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
658 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
660 nudge_forward_button.set_name ("TransportButton");
661 nudge_backward_button.set_name ("TransportButton");
663 fade_context_menu.set_name ("ArdourContextMenu");
665 /* icons, titles, WM stuff */
667 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
668 Glib::RefPtr<Gdk::Pixbuf> icon;
670 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
671 window_icons.push_back (icon);
673 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
680 window_icons.push_back (icon);
682 if (!window_icons.empty()) {
683 // set_icon_list (window_icons);
684 set_default_icon_list (window_icons);
687 WindowTitle title(Glib::get_application_name());
688 title += _("Editor");
689 set_title (title.get_string());
690 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
693 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
695 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
696 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
698 /* allow external control surfaces/protocols to do various things */
700 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
701 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
702 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
703 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
704 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
705 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
706 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
707 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
708 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
709 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
710 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
711 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
712 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
713 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
715 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
716 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
717 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
718 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
719 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
721 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
723 /* problematic: has to return a value and thus cannot be x-thread */
725 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
727 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
729 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
731 _ignore_region_action = false;
732 _last_region_menu_was_main = false;
733 _popup_region_menu_item = 0;
735 _show_marker_lines = false;
736 _over_region_trim_target = false;
738 /* Button bindings */
740 button_bindings = new Bindings;
742 XMLNode* node = button_settings();
744 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
745 button_bindings->load (**i);
752 setup_fade_images ();
758 if(image_socket_listener) {
759 if(image_socket_listener->is_connected())
761 image_socket_listener->close_connection() ;
764 delete image_socket_listener ;
765 image_socket_listener = 0 ;
769 delete button_bindings;
771 delete _route_groups;
777 Editor::button_settings () const
779 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
780 XMLNode* node = find_named_node (*settings, X_("Buttons"));
783 node = new XMLNode (X_("Buttons"));
790 Editor::add_toplevel_controls (Container& cont)
792 vpacker.pack_start (cont, false, false);
797 Editor::catch_vanishing_regionview (RegionView *rv)
799 /* note: the selection will take care of the vanishing
800 audioregionview by itself.
803 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
807 if (clicked_regionview == rv) {
808 clicked_regionview = 0;
811 if (entered_regionview == rv) {
812 set_entered_regionview (0);
815 if (!_all_region_actions_sensitized) {
816 sensitize_all_region_actions (true);
819 _over_region_trim_target = false;
823 Editor::set_entered_regionview (RegionView* rv)
825 if (rv == entered_regionview) {
829 if (entered_regionview) {
830 entered_regionview->exited ();
833 if ((entered_regionview = rv) != 0) {
834 entered_regionview->entered (internal_editing ());
837 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
838 /* This RegionView entry might have changed what region actions
839 are allowed, so sensitize them all in case a key is pressed.
841 sensitize_all_region_actions (true);
846 Editor::set_entered_track (TimeAxisView* tav)
849 entered_track->exited ();
852 if ((entered_track = tav) != 0) {
853 entered_track->entered ();
858 Editor::show_window ()
860 if (!is_visible ()) {
863 /* XXX: this is a bit unfortunate; it would probably
864 be nicer if we could just call show () above rather
865 than needing the show_all ()
868 /* re-hide stuff if necessary */
869 editor_list_button_toggled ();
870 parameter_changed ("show-summary");
871 parameter_changed ("show-group-tabs");
872 parameter_changed ("show-zoom-tools");
874 /* now reset all audio_time_axis heights, because widgets might need
880 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
881 tv = (static_cast<TimeAxisView*>(*i));
885 if (current_mixer_strip) {
886 current_mixer_strip->hide_things ();
887 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
895 Editor::instant_save ()
897 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
902 _session->add_instant_xml(get_state());
904 Config->add_instant_xml(get_state());
909 Editor::zoom_adjustment_changed ()
915 double fpu = zoom_range_clock->current_duration() / _canvas_width;
919 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
920 } else if (fpu > _session->current_end_frame() / _canvas_width) {
921 fpu = _session->current_end_frame() / _canvas_width;
922 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
929 Editor::control_vertical_zoom_in_all ()
931 tav_zoom_smooth (false, true);
935 Editor::control_vertical_zoom_out_all ()
937 tav_zoom_smooth (true, true);
941 Editor::control_vertical_zoom_in_selected ()
943 tav_zoom_smooth (false, false);
947 Editor::control_vertical_zoom_out_selected ()
949 tav_zoom_smooth (true, false);
953 Editor::control_view (uint32_t view)
955 goto_visual_state (view);
959 Editor::control_unselect ()
961 selection->clear_tracks ();
965 Editor::control_select (uint32_t rid, Selection::Operation op)
967 /* handles the (static) signal from the ControlProtocol class that
968 * requests setting the selected track to a given RID
975 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
981 TimeAxisView* tav = axis_view_from_route (r);
986 selection->add (tav);
988 case Selection::Toggle:
989 selection->toggle (tav);
991 case Selection::Extend:
994 selection->set (tav);
998 selection->clear_tracks ();
1003 Editor::control_step_tracks_up ()
1005 scroll_tracks_up_line ();
1009 Editor::control_step_tracks_down ()
1011 scroll_tracks_down_line ();
1015 Editor::control_scroll (float fraction)
1017 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1023 double step = fraction * current_page_frames();
1026 _control_scroll_target is an optional<T>
1028 it acts like a pointer to an framepos_t, with
1029 a operator conversion to boolean to check
1030 that it has a value could possibly use
1031 playhead_cursor->current_frame to store the
1032 value and a boolean in the class to know
1033 when it's out of date
1036 if (!_control_scroll_target) {
1037 _control_scroll_target = _session->transport_frame();
1038 _dragging_playhead = true;
1041 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1042 *_control_scroll_target = 0;
1043 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1044 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1046 *_control_scroll_target += (framepos_t) floor (step);
1049 /* move visuals, we'll catch up with it later */
1051 playhead_cursor->set_position (*_control_scroll_target);
1052 UpdateAllTransportClocks (*_control_scroll_target);
1054 if (*_control_scroll_target > (current_page_frames() / 2)) {
1055 /* try to center PH in window */
1056 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1062 Now we do a timeout to actually bring the session to the right place
1063 according to the playhead. This is to avoid reading disk buffers on every
1064 call to control_scroll, which is driven by ScrollTimeline and therefore
1065 probably by a control surface wheel which can generate lots of events.
1067 /* cancel the existing timeout */
1069 control_scroll_connection.disconnect ();
1071 /* add the next timeout */
1073 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1077 Editor::deferred_control_scroll (framepos_t /*target*/)
1079 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1080 // reset for next stream
1081 _control_scroll_target = boost::none;
1082 _dragging_playhead = false;
1087 Editor::access_action (std::string action_group, std::string action_item)
1093 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1096 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1104 Editor::on_realize ()
1106 Window::on_realize ();
1111 Editor::map_position_change (framepos_t frame)
1113 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1115 if (_session == 0) {
1119 if (_follow_playhead) {
1120 center_screen (frame);
1123 playhead_cursor->set_position (frame);
1127 Editor::center_screen (framepos_t frame)
1129 double page = _canvas_width * frames_per_unit;
1131 /* if we're off the page, then scroll.
1134 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1135 center_screen_internal (frame, page);
1140 Editor::center_screen_internal (framepos_t frame, float page)
1145 frame -= (framepos_t) page;
1150 reset_x_origin (frame);
1155 Editor::update_title ()
1157 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1160 bool dirty = _session->dirty();
1162 string session_name;
1164 if (_session->snap_name() != _session->name()) {
1165 session_name = _session->snap_name();
1167 session_name = _session->name();
1171 session_name = "*" + session_name;
1174 WindowTitle title(session_name);
1175 title += Glib::get_application_name();
1176 set_title (title.get_string());
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::handle_new_route, 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_dialog), 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) {
2744 } else if (after == max_framepos) {
2746 } else if (before != max_framepos && after != max_framepos) {
2747 /* have before and after */
2748 if ((start - before) < (after - start)) {
2757 case SnapToRegionStart:
2758 case SnapToRegionEnd:
2759 case SnapToRegionSync:
2760 case SnapToRegionBoundary:
2761 if (!region_boundary_cache.empty()) {
2763 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2764 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2766 if (direction > 0) {
2767 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2769 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2772 if (next != region_boundary_cache.begin ()) {
2777 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2778 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2780 if (start > (p + n) / 2) {
2789 switch (_snap_mode) {
2795 if (presnap > start) {
2796 if (presnap > (start + unit_to_frame(snap_threshold))) {
2800 } else if (presnap < start) {
2801 if (presnap < (start - unit_to_frame(snap_threshold))) {
2807 /* handled at entry */
2815 Editor::setup_toolbar ()
2817 HBox* mode_box = manage(new HBox);
2818 mode_box->set_border_width (2);
2819 mode_box->set_spacing(4);
2821 HBox* mouse_mode_box = manage (new HBox);
2822 HBox* mouse_mode_hbox1 = manage (new HBox);
2823 HBox* mouse_mode_hbox2 = manage (new HBox);
2824 VBox* mouse_mode_vbox1 = manage (new VBox);
2825 VBox* mouse_mode_vbox2 = manage (new VBox);
2826 Alignment* mouse_mode_align1 = manage (new Alignment);
2827 Alignment* mouse_mode_align2 = manage (new Alignment);
2829 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2830 mouse_mode_size_group->add_widget (mouse_move_button);
2831 mouse_mode_size_group->add_widget (mouse_select_button);
2832 mouse_mode_size_group->add_widget (mouse_zoom_button);
2833 mouse_mode_size_group->add_widget (mouse_gain_button);
2834 mouse_mode_size_group->add_widget (mouse_timefx_button);
2835 mouse_mode_size_group->add_widget (mouse_audition_button);
2836 mouse_mode_size_group->add_widget (mouse_draw_button);
2837 mouse_mode_size_group->add_widget (internal_edit_button);
2839 /* make them just a bit bigger */
2840 mouse_move_button.set_size_request (-1, 25);
2842 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2843 smart_mode_joiner->set_related_action (smart_mode_action);
2845 mouse_mode_hbox2->set_spacing (2);
2846 mouse_mode_box->set_spacing (2);
2848 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2849 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2850 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2851 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2852 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2853 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2854 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2856 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2857 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2859 mouse_mode_align1->add (*mouse_mode_vbox1);
2860 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2861 mouse_mode_align2->add (*mouse_mode_vbox2);
2862 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2864 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2865 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2867 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2868 if (!Profile->get_sae()) {
2869 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2871 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2873 edit_mode_selector.set_name ("EditModeSelector");
2874 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2875 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2877 mode_box->pack_start (edit_mode_selector, false, false);
2878 mode_box->pack_start (*mouse_mode_box, false, false);
2880 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2881 _mouse_mode_tearoff->set_name ("MouseModeBase");
2882 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2884 if (Profile->get_sae()) {
2885 _mouse_mode_tearoff->set_can_be_torn_off (false);
2888 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2889 &_mouse_mode_tearoff->tearoff_window()));
2890 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2891 &_mouse_mode_tearoff->tearoff_window(), 1));
2892 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2893 &_mouse_mode_tearoff->tearoff_window()));
2894 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2895 &_mouse_mode_tearoff->tearoff_window(), 1));
2899 _zoom_box.set_spacing (2);
2900 _zoom_box.set_border_width (2);
2904 zoom_in_button.set_name ("zoom button");
2905 zoom_in_button.set_image (::get_icon ("zoom_in"));
2906 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2907 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2908 zoom_in_button.set_related_action (act);
2910 zoom_out_button.set_name ("zoom button");
2911 zoom_out_button.set_image (::get_icon ("zoom_out"));
2912 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2913 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2914 zoom_out_button.set_related_action (act);
2916 zoom_out_full_button.set_name ("zoom button");
2917 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2918 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2919 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2920 zoom_out_full_button.set_related_action (act);
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, _("Edit Region Contents (e.g. notes)"));
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 ((char *) p, txt.length(), 0);
3109 ((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_dialog (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::maximise_editing_space ()
3939 if (!Config->get_keep_tearoffs()) {
3940 /* these calls will leave each tearoff visible *if* it is torn off,
3941 but invisible otherwise.
3943 _mouse_mode_tearoff->set_visible (false);
3944 _tools_tearoff->set_visible (false);
3945 _zoom_tearoff->set_visible (false);
3952 Editor::restore_editing_space ()
3960 if (!Config->get_keep_tearoffs()) {
3961 _mouse_mode_tearoff->set_visible (true);
3962 _tools_tearoff->set_visible (true);
3963 _zoom_tearoff->set_visible (true);
3970 * Make new playlists for a given track and also any others that belong
3971 * to the same active route group with the `edit' property.
3976 Editor::new_playlists (TimeAxisView* v)
3978 begin_reversible_command (_("new playlists"));
3979 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3980 _session->playlists->get (playlists);
3981 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3982 commit_reversible_command ();
3986 * Use a copy of the current playlist for a given track and also any others that belong
3987 * to the same active route group with the `edit' property.
3992 Editor::copy_playlists (TimeAxisView* v)
3994 begin_reversible_command (_("copy playlists"));
3995 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3996 _session->playlists->get (playlists);
3997 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3998 commit_reversible_command ();
4001 /** Clear the current playlist for a given track and also any others that belong
4002 * to the same active route group with the `edit' property.
4007 Editor::clear_playlists (TimeAxisView* v)
4009 begin_reversible_command (_("clear playlists"));
4010 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4011 _session->playlists->get (playlists);
4012 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4013 commit_reversible_command ();
4017 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4019 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4023 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4025 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4029 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4031 atv.clear_playlist ();
4035 Editor::on_key_press_event (GdkEventKey* ev)
4037 return key_press_focus_accelerator_handler (*this, ev);
4041 Editor::on_key_release_event (GdkEventKey* ev)
4043 return Gtk::Window::on_key_release_event (ev);
4044 // return key_press_focus_accelerator_handler (*this, ev);
4047 /** Queue up a change to the viewport x origin.
4048 * @param frame New x origin.
4051 Editor::reset_x_origin (framepos_t frame)
4053 queue_visual_change (frame);
4057 Editor::reset_y_origin (double y)
4059 queue_visual_change_y (y);
4063 Editor::reset_zoom (double fpu)
4065 queue_visual_change (fpu);
4069 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4071 reset_x_origin (frame);
4074 if (!no_save_visual) {
4075 undo_visual_stack.push_back (current_visual_state(false));
4079 Editor::VisualState::VisualState (bool with_tracks)
4080 : gui_state (with_tracks ? new GUIObjectState : 0)
4084 Editor::VisualState::~VisualState ()
4089 Editor::VisualState*
4090 Editor::current_visual_state (bool with_tracks)
4092 VisualState* vs = new VisualState (with_tracks);
4093 vs->y_position = vertical_adjustment.get_value();
4094 vs->frames_per_unit = frames_per_unit;
4095 vs->leftmost_frame = leftmost_frame;
4096 vs->zoom_focus = zoom_focus;
4099 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4106 Editor::undo_visual_state ()
4108 if (undo_visual_stack.empty()) {
4112 VisualState* vs = undo_visual_stack.back();
4113 undo_visual_stack.pop_back();
4116 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4118 use_visual_state (*vs);
4122 Editor::redo_visual_state ()
4124 if (redo_visual_stack.empty()) {
4128 VisualState* vs = redo_visual_stack.back();
4129 redo_visual_stack.pop_back();
4131 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4133 use_visual_state (*vs);
4137 Editor::swap_visual_state ()
4139 if (undo_visual_stack.empty()) {
4140 redo_visual_state ();
4142 undo_visual_state ();
4147 Editor::use_visual_state (VisualState& vs)
4149 PBD::Unwinder<bool> nsv (no_save_visual, true);
4151 _routes->suspend_redisplay ();
4153 vertical_adjustment.set_value (vs.y_position);
4155 set_zoom_focus (vs.zoom_focus);
4156 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4159 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4161 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4162 (*i)->reset_visual_state ();
4166 _routes->update_visibility ();
4167 _routes->resume_redisplay ();
4171 Editor::set_frames_per_unit (double fpu)
4173 /* this is the core function that controls the zoom level of the canvas. it is called
4174 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4177 if (fpu == frames_per_unit) {
4186 /* don't allow zooms that fit more than the maximum number
4187 of frames into an 800 pixel wide space.
4190 if (max_framepos / fpu < 800.0) {
4195 tempo_lines->tempo_map_changed();
4197 frames_per_unit = fpu;
4202 Editor::post_zoom ()
4204 // convert fpu to frame count
4206 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4208 if (frames_per_unit != zoom_range_clock->current_duration()) {
4209 zoom_range_clock->set (frames);
4212 bool const showing_time_selection =
4213 mouse_mode == MouseRange ||
4214 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4216 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4217 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4218 (*i)->reshow_selection (selection->time);
4222 ZoomChanged (); /* EMIT_SIGNAL */
4224 //reset_scrolling_region ();
4226 if (playhead_cursor) {
4227 playhead_cursor->set_position (playhead_cursor->current_frame);
4230 refresh_location_display();
4231 _summary->set_overlays_dirty ();
4233 update_marker_labels ();
4239 Editor::queue_visual_change (framepos_t where)
4241 pending_visual_change.add (VisualChange::TimeOrigin);
4242 pending_visual_change.time_origin = where;
4243 ensure_visual_change_idle_handler ();
4247 Editor::queue_visual_change (double fpu)
4249 pending_visual_change.add (VisualChange::ZoomLevel);
4250 pending_visual_change.frames_per_unit = fpu;
4252 ensure_visual_change_idle_handler ();
4256 Editor::queue_visual_change_y (double y)
4258 pending_visual_change.add (VisualChange::YOrigin);
4259 pending_visual_change.y_origin = y;
4261 ensure_visual_change_idle_handler ();
4265 Editor::ensure_visual_change_idle_handler ()
4267 if (pending_visual_change.idle_handler_id < 0) {
4268 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4273 Editor::_idle_visual_changer (void* arg)
4275 return static_cast<Editor*>(arg)->idle_visual_changer ();
4279 Editor::idle_visual_changer ()
4281 VisualChange::Type p = pending_visual_change.pending;
4282 pending_visual_change.pending = (VisualChange::Type) 0;
4284 double const last_time_origin = horizontal_position ();
4286 if (p & VisualChange::ZoomLevel) {
4287 set_frames_per_unit (pending_visual_change.frames_per_unit);
4289 compute_fixed_ruler_scale ();
4290 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4291 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4292 update_tempo_based_rulers ();
4294 if (p & VisualChange::TimeOrigin) {
4295 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4297 if (p & VisualChange::YOrigin) {
4298 vertical_adjustment.set_value (pending_visual_change.y_origin);
4301 if (last_time_origin == horizontal_position ()) {
4302 /* changed signal not emitted */
4303 update_fixed_rulers ();
4304 redisplay_tempo (true);
4307 _summary->set_overlays_dirty ();
4309 pending_visual_change.idle_handler_id = -1;
4310 return 0; /* this is always a one-shot call */
4313 struct EditorOrderTimeAxisSorter {
4314 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4315 return a->order () < b->order ();
4320 Editor::sort_track_selection (TrackViewList& sel)
4322 EditorOrderTimeAxisSorter cmp;
4327 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4330 framepos_t where = 0;
4331 EditPoint ep = _edit_point;
4333 if (from_context_menu && (ep == EditAtMouse)) {
4334 return event_frame (&context_click_event, 0, 0);
4337 if (entered_marker) {
4338 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4339 return entered_marker->position();
4342 if (ignore_playhead && ep == EditAtPlayhead) {
4343 ep = EditAtSelectedMarker;
4347 case EditAtPlayhead:
4348 where = _session->audible_frame();
4349 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4352 case EditAtSelectedMarker:
4353 if (!selection->markers.empty()) {
4355 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4358 where = loc->start();
4362 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4370 if (!mouse_frame (where, ignored)) {
4371 /* XXX not right but what can we do ? */
4375 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4383 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4385 if (!_session) return;
4387 begin_reversible_command (cmd);
4391 if ((tll = transport_loop_location()) == 0) {
4392 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4393 XMLNode &before = _session->locations()->get_state();
4394 _session->locations()->add (loc, true);
4395 _session->set_auto_loop_location (loc);
4396 XMLNode &after = _session->locations()->get_state();
4397 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4399 XMLNode &before = tll->get_state();
4400 tll->set_hidden (false, this);
4401 tll->set (start, end);
4402 XMLNode &after = tll->get_state();
4403 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4406 commit_reversible_command ();
4410 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4412 if (!_session) return;
4414 begin_reversible_command (cmd);
4418 if ((tpl = transport_punch_location()) == 0) {
4419 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4420 XMLNode &before = _session->locations()->get_state();
4421 _session->locations()->add (loc, true);
4422 _session->set_auto_loop_location (loc);
4423 XMLNode &after = _session->locations()->get_state();
4424 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4427 XMLNode &before = tpl->get_state();
4428 tpl->set_hidden (false, this);
4429 tpl->set (start, end);
4430 XMLNode &after = tpl->get_state();
4431 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4434 commit_reversible_command ();
4437 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4438 * @param rs List to which found regions are added.
4439 * @param where Time to look at.
4440 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4443 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4445 const TrackViewList* tracks;
4448 tracks = &track_views;
4453 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4455 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4458 boost::shared_ptr<Track> tr;
4459 boost::shared_ptr<Playlist> pl;
4461 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4463 boost::shared_ptr<RegionList> regions = pl->regions_at (
4464 (framepos_t) floor ( (double) where * tr->speed()));
4466 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4467 RegionView* rv = rtv->view()->find_view (*i);
4478 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4480 const TrackViewList* tracks;
4483 tracks = &track_views;
4488 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4489 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4491 boost::shared_ptr<Track> tr;
4492 boost::shared_ptr<Playlist> pl;
4494 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4496 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4497 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4499 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4501 RegionView* rv = rtv->view()->find_view (*i);
4512 /** Start with regions that are selected. Then add equivalent regions
4513 * on tracks in the same active edit-enabled route group as any of
4514 * the regions that we started with.
4518 Editor::get_regions_from_selection ()
4520 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4523 /** Get regions using the following method:
4525 * Make an initial region list using the selected regions, unless
4526 * the edit point is `mouse' and the mouse is over an unselected
4527 * region. In this case, start with just that region.
4529 * Then, add equivalent regions in active edit groups to the region list.
4531 * Then, search the list of selected tracks to find any selected tracks which
4532 * do not contain regions already in the region list. If there are no selected
4533 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4534 * than just the selected.
4536 * Add any regions that are under the edit point on these tracks to get the
4537 * returned region list.
4539 * The rationale here is that the mouse edit point is special in that
4540 * its position describes both a time and a track; the other edit
4541 * modes only describe a time. Hence if the edit point is `mouse' we
4542 * ignore selected tracks, as we assume the user means something by
4543 * pointing at a particular track. Also in this case we take note of
4544 * the region directly under the edit point, as there is always just one
4545 * (rather than possibly several with non-mouse edit points).
4549 Editor::get_regions_from_selection_and_edit_point ()
4551 RegionSelection regions;
4553 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4554 regions.add (entered_regionview);
4556 regions = selection->regions;
4559 TrackViewList tracks;
4561 if (_edit_point != EditAtMouse) {
4562 tracks = selection->tracks;
4565 /* Add any other regions that are in the same
4566 edit-activated route group as one of our regions.
4568 regions = get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4569 framepos_t const where = get_preferred_edit_position ();
4571 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4572 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4573 * is enabled, so consider all tracks
4575 tracks = track_views;
4578 if (!tracks.empty()) {
4579 /* now search the selected tracks for tracks which don't
4580 already contain regions to be acted upon, and get regions at
4581 the edit point on those tracks too.
4583 TrackViewList tracks_without_relevant_regions;
4585 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4586 if (!regions.involves (**t)) {
4587 /* there are no equivalent regions on this track */
4588 tracks_without_relevant_regions.push_back (*t);
4592 if (!tracks_without_relevant_regions.empty()) {
4593 /* there are some selected tracks with neither selected
4594 * regions or their equivalents: act upon all regions in
4597 get_regions_at (regions, where, tracks_without_relevant_regions);
4604 /** Start with regions that are selected, or the entered regionview if none are selected.
4605 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4606 * of the regions that we started with.
4610 Editor::get_regions_from_selection_and_entered ()
4612 RegionSelection regions = selection->regions;
4614 if (regions.empty() && entered_regionview) {
4615 regions.add (entered_regionview);
4618 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4622 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4624 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4626 RouteTimeAxisView* tatv;
4628 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4630 boost::shared_ptr<Playlist> pl;
4631 vector<boost::shared_ptr<Region> > results;
4633 boost::shared_ptr<Track> tr;
4635 if ((tr = tatv->track()) == 0) {
4640 if ((pl = (tr->playlist())) != 0) {
4641 pl->get_region_list_equivalent_regions (region, results);
4644 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4645 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4646 regions.push_back (marv);
4655 Editor::show_rhythm_ferret ()
4657 if (rhythm_ferret == 0) {
4658 rhythm_ferret = new RhythmFerret(*this);
4661 rhythm_ferret->set_session (_session);
4662 rhythm_ferret->show ();
4663 rhythm_ferret->present ();
4667 Editor::first_idle ()
4669 MessageDialog* dialog = 0;
4671 if (track_views.size() > 1) {
4672 dialog = new MessageDialog (
4674 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4678 ARDOUR_UI::instance()->flush_pending ();
4681 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4685 // first idle adds route children (automation tracks), so we need to redisplay here
4686 _routes->redisplay ();
4693 Editor::_idle_resize (gpointer arg)
4695 return ((Editor*)arg)->idle_resize ();
4699 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4701 if (resize_idle_id < 0) {
4702 resize_idle_id = g_idle_add (_idle_resize, this);
4703 _pending_resize_amount = 0;
4706 /* make a note of the smallest resulting height, so that we can clamp the
4707 lower limit at TimeAxisView::hSmall */
4709 int32_t min_resulting = INT32_MAX;
4711 _pending_resize_amount += h;
4712 _pending_resize_view = view;
4714 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4716 if (selection->tracks.contains (_pending_resize_view)) {
4717 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4718 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4722 if (min_resulting < 0) {
4727 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4728 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4732 /** Handle pending resizing of tracks */
4734 Editor::idle_resize ()
4736 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4738 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4739 selection->tracks.contains (_pending_resize_view)) {
4741 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4742 if (*i != _pending_resize_view) {
4743 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4748 _pending_resize_amount = 0;
4750 _group_tabs->set_dirty ();
4751 resize_idle_id = -1;
4759 ENSURE_GUI_THREAD (*this, &Editor::located);
4761 playhead_cursor->set_position (_session->audible_frame ());
4762 if (_follow_playhead && !_pending_initial_locate) {
4763 reset_x_origin_to_follow_playhead ();
4766 _pending_locate_request = false;
4767 _pending_initial_locate = false;
4771 Editor::region_view_added (RegionView *)
4773 _summary->set_dirty ();
4777 Editor::region_view_removed ()
4779 _summary->set_dirty ();
4783 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4785 TrackViewList::const_iterator j = track_views.begin ();
4786 while (j != track_views.end()) {
4787 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4788 if (rtv && rtv->route() == r) {
4799 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4803 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4804 TimeAxisView* tv = axis_view_from_route (*i);
4815 Editor::handle_new_route (RouteList& routes)
4817 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4819 RouteTimeAxisView *rtv;
4820 list<RouteTimeAxisView*> new_views;
4822 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4823 boost::shared_ptr<Route> route = (*x);
4825 if (route->is_hidden() || route->is_monitor()) {
4829 DataType dt = route->input()->default_type();
4831 if (dt == ARDOUR::DataType::AUDIO) {
4832 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4833 rtv->set_route (route);
4834 } else if (dt == ARDOUR::DataType::MIDI) {
4835 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4836 rtv->set_route (route);
4838 throw unknown_type();
4841 new_views.push_back (rtv);
4842 track_views.push_back (rtv);
4844 rtv->effective_gain_display ();
4846 if (internal_editing()) {
4847 rtv->enter_internal_edit_mode ();
4849 rtv->leave_internal_edit_mode ();
4852 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4853 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4856 _routes->routes_added (new_views);
4857 _summary->routes_added (new_views);
4859 if (show_editor_mixer_when_tracks_arrive) {
4860 show_editor_mixer (true);
4863 editor_list_button.set_sensitive (true);
4867 Editor::timeaxisview_deleted (TimeAxisView *tv)
4869 if (_session && _session->deletion_in_progress()) {
4870 /* the situation is under control */
4874 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4876 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4878 _routes->route_removed (tv);
4880 if (tv == entered_track) {
4884 TimeAxisView::Children c = tv->get_child_list ();
4885 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4886 if (entered_track == i->get()) {
4891 /* remove it from the list of track views */
4893 TrackViewList::iterator i;
4895 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4896 i = track_views.erase (i);
4899 /* update whatever the current mixer strip is displaying, if revelant */
4901 boost::shared_ptr<Route> route;
4904 route = rtav->route ();
4907 if (current_mixer_strip && current_mixer_strip->route() == route) {
4909 TimeAxisView* next_tv;
4911 if (track_views.empty()) {
4913 } else if (i == track_views.end()) {
4914 next_tv = track_views.front();
4921 set_selected_mixer_strip (*next_tv);
4923 /* make the editor mixer strip go away setting the
4924 * button to inactive (which also unticks the menu option)
4927 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4933 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4935 if (apply_to_selection) {
4936 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4938 TrackSelection::iterator j = i;
4941 hide_track_in_display (*i, false);
4946 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4948 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4949 // this will hide the mixer strip
4950 set_selected_mixer_strip (*tv);
4953 _routes->hide_track_in_display (*tv);
4958 Editor::sync_track_view_list_and_routes ()
4960 track_views = TrackViewList (_routes->views ());
4962 _summary->set_dirty ();
4963 _group_tabs->set_dirty ();
4965 return false; // do not call again (until needed)
4969 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4971 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4976 /** Find a RouteTimeAxisView by the ID of its route */
4978 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4980 RouteTimeAxisView* v;
4982 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4983 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4984 if(v->route()->id() == id) {
4994 Editor::fit_route_group (RouteGroup *g)
4996 TrackViewList ts = axis_views_from_routes (g->route_list ());
5001 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5003 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5006 _session->cancel_audition ();
5010 if (_session->is_auditioning()) {
5011 _session->cancel_audition ();
5012 if (r == last_audition_region) {
5017 _session->audition_region (r);
5018 last_audition_region = r;
5023 Editor::hide_a_region (boost::shared_ptr<Region> r)
5025 r->set_hidden (true);
5029 Editor::show_a_region (boost::shared_ptr<Region> r)
5031 r->set_hidden (false);
5035 Editor::audition_region_from_region_list ()
5037 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5041 Editor::hide_region_from_region_list ()
5043 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5047 Editor::show_region_in_region_list ()
5049 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5053 Editor::step_edit_status_change (bool yn)
5056 start_step_editing ();
5058 stop_step_editing ();
5063 Editor::start_step_editing ()
5065 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5069 Editor::stop_step_editing ()
5071 step_edit_connection.disconnect ();
5075 Editor::check_step_edit ()
5077 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5078 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5080 mtv->check_step_edit ();
5084 return true; // do it again, till we stop
5088 Editor::scroll_press (Direction dir)
5090 ++_scroll_callbacks;
5092 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5093 /* delay the first auto-repeat */
5099 scroll_backward (1);
5107 scroll_tracks_up_line ();
5111 scroll_tracks_down_line ();
5115 /* do hacky auto-repeat */
5116 if (!_scroll_connection.connected ()) {
5118 _scroll_connection = Glib::signal_timeout().connect (
5119 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5122 _scroll_callbacks = 0;
5129 Editor::scroll_release ()
5131 _scroll_connection.disconnect ();
5134 /** Queue a change for the Editor viewport x origin to follow the playhead */
5136 Editor::reset_x_origin_to_follow_playhead ()
5138 framepos_t const frame = playhead_cursor->current_frame;
5140 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5142 if (_session->transport_speed() < 0) {
5144 if (frame > (current_page_frames() / 2)) {
5145 center_screen (frame-(current_page_frames()/2));
5147 center_screen (current_page_frames()/2);
5154 if (frame < leftmost_frame) {
5156 if (_session->transport_rolling()) {
5157 /* rolling; end up with the playhead at the right of the page */
5158 l = frame - current_page_frames ();
5160 /* not rolling: end up with the playhead 1/4 of the way along the page */
5161 l = frame - current_page_frames() / 4;
5165 if (_session->transport_rolling()) {
5166 /* rolling: end up with the playhead on the left of the page */
5169 /* not rolling: end up with the playhead 3/4 of the way along the page */
5170 l = frame - 3 * current_page_frames() / 4;
5178 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5184 Editor::super_rapid_screen_update ()
5186 if (!_session || !_session->engine().running()) {
5190 /* METERING / MIXER STRIPS */
5192 /* update track meters, if required */
5193 if (is_mapped() && meters_running) {
5194 RouteTimeAxisView* rtv;
5195 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5196 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5197 rtv->fast_update ();
5202 /* and any current mixer strip */
5203 if (current_mixer_strip) {
5204 current_mixer_strip->fast_update ();
5207 /* PLAYHEAD AND VIEWPORT */
5209 framepos_t const frame = _session->audible_frame();
5211 /* There are a few reasons why we might not update the playhead / viewport stuff:
5213 * 1. we don't update things when there's a pending locate request, otherwise
5214 * when the editor requests a locate there is a chance that this method
5215 * will move the playhead before the locate request is processed, causing
5217 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5218 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5221 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5223 last_update_frame = frame;
5225 if (!_dragging_playhead) {
5226 playhead_cursor->set_position (frame);
5229 if (!_stationary_playhead) {
5231 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5232 reset_x_origin_to_follow_playhead ();
5237 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5241 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5242 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5243 if (target <= 0.0) {
5246 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5247 target = (target * 0.15) + (current * 0.85);
5253 set_horizontal_position (current);
5262 Editor::session_going_away ()
5264 _have_idled = false;
5266 _session_connections.drop_connections ();
5268 super_rapid_screen_update_connection.disconnect ();
5270 selection->clear ();
5271 cut_buffer->clear ();
5273 clicked_regionview = 0;
5274 clicked_axisview = 0;
5275 clicked_routeview = 0;
5276 entered_regionview = 0;
5278 last_update_frame = 0;
5281 playhead_cursor->canvas_item.hide ();
5283 /* rip everything out of the list displays */
5287 _route_groups->clear ();
5289 /* do this first so that deleting a track doesn't reset cms to null
5290 and thus cause a leak.
5293 if (current_mixer_strip) {
5294 if (current_mixer_strip->get_parent() != 0) {
5295 global_hpacker.remove (*current_mixer_strip);
5297 delete current_mixer_strip;
5298 current_mixer_strip = 0;
5301 /* delete all trackviews */
5303 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5306 track_views.clear ();
5308 zoom_range_clock->set_session (0);
5309 nudge_clock->set_session (0);
5311 editor_list_button.set_active(false);
5312 editor_list_button.set_sensitive(false);
5314 /* clear tempo/meter rulers */
5315 remove_metric_marks ();
5317 clear_marker_display ();
5319 current_bbt_points_begin = current_bbt_points_end;
5321 /* get rid of any existing editor mixer strip */
5323 WindowTitle title(Glib::get_application_name());
5324 title += _("Editor");
5326 set_title (title.get_string());
5328 SessionHandlePtr::session_going_away ();
5333 Editor::show_editor_list (bool yn)
5336 _the_notebook.show ();
5338 _the_notebook.hide ();
5343 Editor::change_region_layering_order (bool from_context_menu)
5345 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5347 if (!clicked_routeview) {
5348 if (layering_order_editor) {
5349 layering_order_editor->hide ();
5354 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5360 boost::shared_ptr<Playlist> pl = track->playlist();
5366 if (layering_order_editor == 0) {
5367 layering_order_editor = new RegionLayeringOrderEditor (*this);
5368 layering_order_editor->set_position (WIN_POS_MOUSE);
5371 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5372 layering_order_editor->maybe_present ();
5376 Editor::update_region_layering_order_editor ()
5378 if (layering_order_editor && layering_order_editor->is_visible ()) {
5379 change_region_layering_order (true);
5384 Editor::setup_fade_images ()
5386 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5387 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5388 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5389 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5390 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5392 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5393 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5394 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5395 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5396 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5398 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5399 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5400 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5401 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5402 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5404 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5405 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5406 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5407 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5408 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5412 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5414 Editor::action_menu_item (std::string const & name)
5416 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5419 return *manage (a->create_menu_item ());
5423 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5425 EventBox* b = manage (new EventBox);
5426 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5427 Label* l = manage (new Label (name));
5431 _the_notebook.append_page (widget, *b);
5435 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5437 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5438 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5441 if (ev->type == GDK_2BUTTON_PRESS) {
5443 /* double-click on a notebook tab shrinks or expands the notebook */
5445 if (_notebook_shrunk) {
5446 if (pre_notebook_shrink_pane_width) {
5447 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5449 _notebook_shrunk = false;
5451 pre_notebook_shrink_pane_width = edit_pane.get_position();
5453 /* this expands the LHS of the edit pane to cover the notebook
5454 PAGE but leaves the tabs visible.
5456 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5457 _notebook_shrunk = true;
5465 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5467 using namespace Menu_Helpers;
5469 MenuList& items = _control_point_context_menu.items ();
5472 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5473 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5474 if (!can_remove_control_point (item)) {
5475 items.back().set_sensitive (false);
5478 _control_point_context_menu.popup (event->button.button, event->button.time);