2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/grouped_buttons.h"
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/tearoff.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/window_title.h"
58 #include "gtkmm2ext/choice.h"
59 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
61 #include "ardour/audio_diskstream.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioplaylist.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/midi_region.h"
67 #include "ardour/plugin_manager.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_directory.h"
71 #include "ardour/session_route.h"
72 #include "ardour/session_state_utils.h"
73 #include "ardour/tempo.h"
74 #include "ardour/utils.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/audioengine.h"
78 #include "control_protocol/control_protocol.h"
84 #include "playlist_selector.h"
85 #include "audio_region_view.h"
86 #include "rgb_macros.h"
87 #include "selection.h"
88 #include "audio_streamview.h"
89 #include "time_axis_view.h"
90 #include "audio_time_axis.h"
92 #include "crossfade_view.h"
93 #include "canvas-noevent-text.h"
95 #include "public_editor.h"
96 #include "crossfade_edit.h"
97 #include "canvas_impl.h"
100 #include "gui_thread.h"
101 #include "simpleline.h"
102 #include "rhythm_ferret.h"
104 #include "tempo_lines.h"
105 #include "analysis_window.h"
106 #include "bundle_manager.h"
107 #include "global_port_matrix.h"
108 #include "editor_drag.h"
109 #include "editor_group_tabs.h"
110 #include "automation_time_axis.h"
111 #include "editor_routes.h"
112 #include "midi_time_axis.h"
113 #include "mixer_strip.h"
114 #include "editor_route_groups.h"
115 #include "editor_regions.h"
116 #include "editor_locations.h"
117 #include "editor_snapshots.h"
118 #include "editor_summary.h"
119 #include "region_layering_order_editor.h"
120 #include "mouse_cursors.h"
121 #include "editor_cursors.h"
126 #include "imageframe_socket_handler.h"
130 using namespace ARDOUR;
133 using namespace Glib;
134 using namespace Gtkmm2ext;
135 using namespace Editing;
137 using PBD::internationalize;
139 using Gtkmm2ext::Keyboard;
141 const double Editor::timebar_height = 15.0;
143 static const gchar *_snap_type_strings[] = {
145 N_("Timecode Frames"),
146 N_("Timecode Seconds"),
147 N_("Timecode Minutes"),
175 static const gchar *_snap_mode_strings[] = {
182 static const gchar *_edit_point_strings[] = {
189 static const gchar *_zoom_focus_strings[] = {
199 #ifdef USE_RUBBERBAND
200 static const gchar *_rb_opt_strings[] = {
203 N_("Balanced multitimbral mixture"),
204 N_("Unpitched percussion with stable notes"),
205 N_("Crisp monophonic instrumental"),
206 N_("Unpitched solo percussion"),
207 N_("Resample without preserving pitch"),
213 show_me_the_size (Requisition* r, const char* what)
215 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
220 pane_size_watcher (Paned* pane)
222 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
223 it is no longer accessible. so stop that. this doesn't happen on X11,
224 just the quartz backend.
229 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
231 gint pos = pane->get_position ();
233 if (pos > max_width_of_lhs) {
234 pane->set_position (max_width_of_lhs);
240 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
242 /* time display buttons */
243 , minsec_label (_("Mins:Secs"))
244 , bbt_label (_("Bars:Beats"))
245 , timecode_label (_("Timecode"))
246 , samples_label (_("Samples"))
247 , tempo_label (_("Tempo"))
248 , meter_label (_("Meter"))
249 , mark_label (_("Location Markers"))
250 , range_mark_label (_("Range Markers"))
251 , transport_mark_label (_("Loop/Punch Ranges"))
252 , cd_mark_label (_("CD Markers"))
253 , edit_packer (4, 4, true)
255 /* the values here don't matter: layout widgets
256 reset them as needed.
259 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
261 /* tool bar related */
263 , zoom_range_clock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true)
265 , toolbar_selection_clock_table (2,3)
267 , automation_mode_button (_("mode"))
268 , global_automation_button (_("automation"))
270 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271 , midi_panic_button (_("Panic"))
274 , image_socket_listener(0)
279 , nudge_clock (X_("nudge"), false, X_("NudgeClock"), true, false, true)
280 , meters_running(false)
281 , _pending_locate_request (false)
282 , _pending_initial_locate (false)
283 , _last_cut_copy_source_track (0)
285 , _region_selection_change_updates_region_list (true)
289 /* we are a singleton */
291 PublicEditor::_instance = this;
295 selection = new Selection (this);
296 cut_buffer = new Selection (this);
298 clicked_regionview = 0;
299 clicked_axisview = 0;
300 clicked_routeview = 0;
301 clicked_crossfadeview = 0;
302 clicked_control_point = 0;
303 last_update_frame = 0;
304 pre_press_cursor = 0;
305 _drags = new DragManager (this);
306 current_mixer_strip = 0;
307 current_bbt_points = 0;
310 snap_type_strings = I18N (_snap_type_strings);
311 snap_mode_strings = I18N (_snap_mode_strings);
312 zoom_focus_strings = I18N (_zoom_focus_strings);
313 edit_point_strings = I18N (_edit_point_strings);
314 #ifdef USE_RUBBERBAND
315 rb_opt_strings = I18N (_rb_opt_strings);
319 snap_threshold = 5.0;
320 bbt_beat_subdivision = 4;
323 last_autoscroll_x = 0;
324 last_autoscroll_y = 0;
325 autoscroll_active = false;
326 autoscroll_timeout_tag = -1;
331 current_interthread_info = 0;
332 _show_measures = true;
333 show_gain_after_trim = false;
334 last_item_entered = 0;
336 have_pending_keyboard_selection = false;
337 _follow_playhead = true;
338 _stationary_playhead = false;
339 _xfade_visibility = true;
340 editor_ruler_menu = 0;
341 no_ruler_shown_update = false;
343 range_marker_menu = 0;
344 marker_menu_item = 0;
345 tempo_or_meter_marker_menu = 0;
346 transport_marker_menu = 0;
347 new_transport_marker_menu = 0;
348 editor_mixer_strip_width = Wide;
349 show_editor_mixer_when_tracks_arrive = false;
350 region_edit_menu_split_multichannel_item = 0;
351 region_edit_menu_split_item = 0;
354 current_stepping_trackview = 0;
356 entered_regionview = 0;
358 clear_entered_track = false;
361 button_release_can_deselect = true;
362 _dragging_playhead = false;
363 _dragging_edit_point = false;
364 select_new_marker = false;
366 layering_order_editor = 0;
367 no_save_visual = false;
370 scrubbing_direction = 0;
374 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
375 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
376 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
377 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
378 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
380 _edit_point = EditAtMouse;
381 _internal_editing = false;
382 current_canvas_cursor = 0;
384 frames_per_unit = 2048; /* too early to use reset_zoom () */
386 _scroll_callbacks = 0;
388 zoom_focus = ZoomFocusLeft;
389 set_zoom_focus (ZoomFocusLeft);
390 zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
392 bbt_label.set_name ("EditorTimeButton");
393 bbt_label.set_size_request (-1, (int)timebar_height);
394 bbt_label.set_alignment (1.0, 0.5);
395 bbt_label.set_padding (5,0);
397 bbt_label.set_no_show_all();
398 minsec_label.set_name ("EditorTimeButton");
399 minsec_label.set_size_request (-1, (int)timebar_height);
400 minsec_label.set_alignment (1.0, 0.5);
401 minsec_label.set_padding (5,0);
402 minsec_label.hide ();
403 minsec_label.set_no_show_all();
404 timecode_label.set_name ("EditorTimeButton");
405 timecode_label.set_size_request (-1, (int)timebar_height);
406 timecode_label.set_alignment (1.0, 0.5);
407 timecode_label.set_padding (5,0);
408 timecode_label.hide ();
409 timecode_label.set_no_show_all();
410 samples_label.set_name ("EditorTimeButton");
411 samples_label.set_size_request (-1, (int)timebar_height);
412 samples_label.set_alignment (1.0, 0.5);
413 samples_label.set_padding (5,0);
414 samples_label.hide ();
415 samples_label.set_no_show_all();
417 tempo_label.set_name ("EditorTimeButton");
418 tempo_label.set_size_request (-1, (int)timebar_height);
419 tempo_label.set_alignment (1.0, 0.5);
420 tempo_label.set_padding (5,0);
422 tempo_label.set_no_show_all();
424 meter_label.set_name ("EditorTimeButton");
425 meter_label.set_size_request (-1, (int)timebar_height);
426 meter_label.set_alignment (1.0, 0.5);
427 meter_label.set_padding (5,0);
429 meter_label.set_no_show_all();
431 mark_label.set_name ("EditorTimeButton");
432 mark_label.set_size_request (-1, (int)timebar_height);
433 mark_label.set_alignment (1.0, 0.5);
434 mark_label.set_padding (5,0);
436 mark_label.set_no_show_all();
438 cd_mark_label.set_name ("EditorTimeButton");
439 cd_mark_label.set_size_request (-1, (int)timebar_height);
440 cd_mark_label.set_alignment (1.0, 0.5);
441 cd_mark_label.set_padding (5,0);
442 cd_mark_label.hide();
443 cd_mark_label.set_no_show_all();
445 range_mark_label.set_name ("EditorTimeButton");
446 range_mark_label.set_size_request (-1, (int)timebar_height);
447 range_mark_label.set_alignment (1.0, 0.5);
448 range_mark_label.set_padding (5,0);
449 range_mark_label.hide();
450 range_mark_label.set_no_show_all();
452 transport_mark_label.set_name ("EditorTimeButton");
453 transport_mark_label.set_size_request (-1, (int)timebar_height);
454 transport_mark_label.set_alignment (1.0, 0.5);
455 transport_mark_label.set_padding (5,0);
456 transport_mark_label.hide();
457 transport_mark_label.set_no_show_all();
459 initialize_rulers ();
460 initialize_canvas ();
462 _summary = new EditorSummary (this);
464 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
465 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
467 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
469 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
470 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
472 edit_controls_vbox.set_spacing (0);
473 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
474 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
476 HBox* h = manage (new HBox);
477 _group_tabs = new EditorGroupTabs (this);
478 h->pack_start (*_group_tabs, PACK_SHRINK);
479 h->pack_start (edit_controls_vbox);
480 controls_layout.add (*h);
482 controls_layout.set_name ("EditControlsBase");
483 controls_layout.add_events (Gdk::SCROLL_MASK);
484 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
486 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
487 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
489 _cursors = new MouseCursors;
491 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
492 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
493 0.0, 1.0, 100.0, 1.0));
495 pad_line_1->property_color_rgba() = 0xFF0000FF;
500 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
501 time_canvas_vbox.set_size_request (-1, -1);
503 ruler_label_event_box.add (ruler_label_vbox);
504 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
505 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
507 time_button_event_box.add (time_button_vbox);
508 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
509 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
511 /* these enable us to have a dedicated window (for cursor setting, etc.)
512 for the canvas areas.
515 track_canvas_event_box.add (*track_canvas);
517 time_canvas_event_box.add (time_canvas_vbox);
518 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
520 edit_packer.set_col_spacings (0);
521 edit_packer.set_row_spacings (0);
522 edit_packer.set_homogeneous (false);
523 edit_packer.set_border_width (0);
524 edit_packer.set_name ("EditorWindow");
526 /* labels for the rulers */
527 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
528 /* labels for the marker "tracks" */
529 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
531 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
533 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
535 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
537 bottom_hbox.set_border_width (2);
538 bottom_hbox.set_spacing (3);
540 _route_groups = new EditorRouteGroups (this);
541 _routes = new EditorRoutes (this);
542 _regions = new EditorRegions (this);
543 _snapshots = new EditorSnapshots (this);
544 _locations = new EditorLocations (this);
546 add_notebook_page (_("Regions"), _regions->widget ());
547 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
548 add_notebook_page (_("Snapshots"), _snapshots->widget ());
549 add_notebook_page (_("Route Groups"), _route_groups->widget ());
550 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
552 _the_notebook.set_show_tabs (true);
553 _the_notebook.set_scrollable (true);
554 _the_notebook.popup_disable ();
555 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
556 _the_notebook.show_all ();
558 post_maximal_editor_width = 0;
559 post_maximal_horizontal_pane_position = 0;
560 post_maximal_editor_height = 0;
561 post_maximal_vertical_pane_position = 0;
562 _notebook_shrunk = false;
564 editor_summary_pane.pack1(edit_packer);
566 Button* summary_arrows_left_left = manage (new Button);
567 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
568 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
569 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
571 Button* summary_arrows_left_right = manage (new Button);
572 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
573 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
574 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
576 VBox* summary_arrows_left = manage (new VBox);
577 summary_arrows_left->pack_start (*summary_arrows_left_left);
578 summary_arrows_left->pack_start (*summary_arrows_left_right);
580 Button* summary_arrows_right_up = manage (new Button);
581 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
582 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
583 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
585 Button* summary_arrows_right_down = manage (new Button);
586 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
587 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
588 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
590 VBox* summary_arrows_right = manage (new VBox);
591 summary_arrows_right->pack_start (*summary_arrows_right_up);
592 summary_arrows_right->pack_start (*summary_arrows_right_down);
594 Frame* summary_frame = manage (new Frame);
595 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
597 summary_frame->add (*_summary);
598 summary_frame->show ();
600 _summary_hbox.pack_start (*summary_arrows_left, false, false);
601 _summary_hbox.pack_start (*summary_frame, true, true);
602 _summary_hbox.pack_start (*summary_arrows_right, false, false);
604 editor_summary_pane.pack2 (_summary_hbox);
606 edit_pane.pack1 (editor_summary_pane, true, true);
607 edit_pane.pack2 (_the_notebook, false, true);
609 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
611 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
613 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
615 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
616 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
618 top_hbox.pack_start (toolbar_frame);
620 HBox *hbox = manage (new HBox);
621 hbox->pack_start (edit_pane, true, true);
623 global_vpacker.pack_start (top_hbox, false, false);
624 global_vpacker.pack_start (*hbox, true, true);
626 global_hpacker.pack_start (global_vpacker, true, true);
628 set_name ("EditorWindow");
629 add_accel_group (ActionManager::ui_manager->get_accel_group());
631 status_bar_hpacker.show ();
633 vpacker.pack_end (status_bar_hpacker, false, false);
634 vpacker.pack_end (global_hpacker, true, true);
636 /* register actions now so that set_state() can find them and set toggles/checks etc */
641 setup_midi_toolbar ();
643 _snap_type = SnapToBeat;
644 set_snap_to (_snap_type);
645 _snap_mode = SnapOff;
646 set_snap_mode (_snap_mode);
647 set_mouse_mode (MouseObject, true);
648 pre_internal_mouse_mode = MouseObject;
649 set_edit_point_preference (EditAtMouse, true);
651 _playlist_selector = new PlaylistSelector();
652 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
654 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
658 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
659 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
661 nudge_forward_button.set_name ("TransportButton");
662 nudge_backward_button.set_name ("TransportButton");
664 fade_context_menu.set_name ("ArdourContextMenu");
666 /* icons, titles, WM stuff */
668 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
669 Glib::RefPtr<Gdk::Pixbuf> icon;
671 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
672 window_icons.push_back (icon);
674 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
681 window_icons.push_back (icon);
683 if (!window_icons.empty()) {
684 // set_icon_list (window_icons);
685 set_default_icon_list (window_icons);
688 WindowTitle title(Glib::get_application_name());
689 title += _("Editor");
690 set_title (title.get_string());
691 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
694 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
696 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
697 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
699 /* allow external control surfaces/protocols to do various things */
701 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
702 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
703 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
704 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
705 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
707 /* problematic: has to return a value and thus cannot be x-thread */
709 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
711 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
713 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
715 _ignore_region_action = false;
716 _last_region_menu_was_main = false;
717 _popup_region_menu_item = 0;
719 _show_marker_lines = false;
720 _over_region_trim_target = false;
722 /* Button bindings */
724 button_bindings = new Bindings;
726 XMLNode* node = button_settings();
728 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
729 button_bindings->load (**i);
736 setup_fade_images ();
742 if(image_socket_listener) {
743 if(image_socket_listener->is_connected())
745 image_socket_listener->close_connection() ;
748 delete image_socket_listener ;
749 image_socket_listener = 0 ;
753 delete button_bindings;
755 delete _route_groups;
761 Editor::button_settings () const
763 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
764 XMLNode* node = find_named_node (*settings, X_("Buttons"));
767 cerr << "new empty Button node\n";
768 node = new XMLNode (X_("Buttons"));
775 Editor::add_toplevel_controls (Container& cont)
777 vpacker.pack_start (cont, false, false);
782 Editor::catch_vanishing_regionview (RegionView *rv)
784 /* note: the selection will take care of the vanishing
785 audioregionview by itself.
788 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
792 if (clicked_regionview == rv) {
793 clicked_regionview = 0;
796 if (entered_regionview == rv) {
797 set_entered_regionview (0);
800 if (!_all_region_actions_sensitized) {
801 sensitize_all_region_actions (true);
804 _over_region_trim_target = false;
808 Editor::set_entered_regionview (RegionView* rv)
810 if (rv == entered_regionview) {
814 if (entered_regionview) {
815 entered_regionview->exited ();
818 if ((entered_regionview = rv) != 0) {
819 entered_regionview->entered (internal_editing ());
822 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
823 /* This RegionView entry might have changed what region actions
824 are allowed, so sensitize them all in case a key is pressed.
826 sensitize_all_region_actions (true);
831 Editor::set_entered_track (TimeAxisView* tav)
834 entered_track->exited ();
837 if ((entered_track = tav) != 0) {
838 entered_track->entered ();
843 Editor::show_window ()
845 if (!is_visible ()) {
848 /* XXX: this is a bit unfortunate; it would probably
849 be nicer if we could just call show () above rather
850 than needing the show_all ()
853 /* re-hide stuff if necessary */
854 editor_list_button_toggled ();
855 parameter_changed ("show-summary");
856 parameter_changed ("show-group-tabs");
857 parameter_changed ("show-zoom-tools");
859 /* now reset all audio_time_axis heights, because widgets might need
865 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
866 tv = (static_cast<TimeAxisView*>(*i));
870 if (current_mixer_strip) {
871 current_mixer_strip->hide_things ();
879 Editor::instant_save ()
881 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
886 _session->add_instant_xml(get_state());
888 Config->add_instant_xml(get_state());
893 Editor::zoom_adjustment_changed ()
899 double fpu = zoom_range_clock.current_duration() / _canvas_width;
903 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
904 } else if (fpu > _session->current_end_frame() / _canvas_width) {
905 fpu = _session->current_end_frame() / _canvas_width;
906 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
913 Editor::control_scroll (float fraction)
915 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
921 double step = fraction * current_page_frames();
924 _control_scroll_target is an optional<T>
926 it acts like a pointer to an framepos_t, with
927 a operator conversion to boolean to check
928 that it has a value could possibly use
929 playhead_cursor->current_frame to store the
930 value and a boolean in the class to know
931 when it's out of date
934 if (!_control_scroll_target) {
935 _control_scroll_target = _session->transport_frame();
936 _dragging_playhead = true;
939 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
940 *_control_scroll_target = 0;
941 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
942 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
944 *_control_scroll_target += (framepos_t) floor (step);
947 /* move visuals, we'll catch up with it later */
949 playhead_cursor->set_position (*_control_scroll_target);
950 UpdateAllTransportClocks (*_control_scroll_target);
952 if (*_control_scroll_target > (current_page_frames() / 2)) {
953 /* try to center PH in window */
954 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
960 Now we do a timeout to actually bring the session to the right place
961 according to the playhead. This is to avoid reading disk buffers on every
962 call to control_scroll, which is driven by ScrollTimeline and therefore
963 probably by a control surface wheel which can generate lots of events.
965 /* cancel the existing timeout */
967 control_scroll_connection.disconnect ();
969 /* add the next timeout */
971 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
975 Editor::deferred_control_scroll (framepos_t /*target*/)
977 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
978 // reset for next stream
979 _control_scroll_target = boost::none;
980 _dragging_playhead = false;
985 Editor::access_action (std::string action_group, std::string action_item)
991 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
994 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1002 Editor::on_realize ()
1004 Window::on_realize ();
1009 Editor::map_position_change (framepos_t frame)
1011 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1013 if (_session == 0) {
1017 if (_follow_playhead) {
1018 center_screen (frame);
1021 playhead_cursor->set_position (frame);
1025 Editor::center_screen (framepos_t frame)
1027 double page = _canvas_width * frames_per_unit;
1029 /* if we're off the page, then scroll.
1032 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1033 center_screen_internal (frame, page);
1038 Editor::center_screen_internal (framepos_t frame, float page)
1043 frame -= (framepos_t) page;
1048 reset_x_origin (frame);
1053 Editor::update_title ()
1055 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1058 bool dirty = _session->dirty();
1060 string session_name;
1062 if (_session->snap_name() != _session->name()) {
1063 session_name = _session->snap_name();
1065 session_name = _session->name();
1069 session_name = "*" + session_name;
1072 WindowTitle title(session_name);
1073 title += Glib::get_application_name();
1074 set_title (title.get_string());
1079 Editor::set_session (Session *t)
1081 SessionHandlePtr::set_session (t);
1087 zoom_range_clock.set_session (_session);
1088 _playlist_selector->set_session (_session);
1089 nudge_clock.set_session (_session);
1090 _summary->set_session (_session);
1091 _group_tabs->set_session (_session);
1092 _route_groups->set_session (_session);
1093 _regions->set_session (_session);
1094 _snapshots->set_session (_session);
1095 _routes->set_session (_session);
1096 _locations->set_session (_session);
1098 if (rhythm_ferret) {
1099 rhythm_ferret->set_session (_session);
1102 if (analysis_window) {
1103 analysis_window->set_session (_session);
1107 sfbrowser->set_session (_session);
1110 compute_fixed_ruler_scale ();
1112 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1113 set_state (*node, Stateful::loading_state_version);
1115 /* catch up with the playhead */
1117 _session->request_locate (playhead_cursor->current_frame);
1118 _pending_initial_locate = true;
1122 /* These signals can all be emitted by a non-GUI thread. Therefore the
1123 handlers for them must not attempt to directly interact with the GUI,
1124 but use Gtkmm2ext::UI::instance()->call_slot();
1127 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1128 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1129 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1130 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1131 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1132 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1133 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1134 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1135 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1136 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1137 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1138 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1139 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display, this), gui_context());
1140 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1142 if (Profile->get_sae()) {
1143 Timecode::BBT_Time bbt;
1147 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1148 nudge_clock.set_mode(AudioClock::BBT);
1149 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1152 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1155 playhead_cursor->canvas_item.show ();
1157 Location* loc = _session->locations()->auto_loop_location();
1159 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1161 if (loc->start() == loc->end()) {
1162 loc->set_end (loc->start() + 1);
1165 _session->locations()->add (loc, false);
1166 _session->set_auto_loop_location (loc);
1169 loc->set_name (_("Loop"));
1172 loc = _session->locations()->auto_punch_location();
1175 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1177 if (loc->start() == loc->end()) {
1178 loc->set_end (loc->start() + 1);
1181 _session->locations()->add (loc, false);
1182 _session->set_auto_punch_location (loc);
1185 loc->set_name (_("Punch"));
1188 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1189 Config->map_parameters (pc);
1190 _session->config.map_parameters (pc);
1192 refresh_location_display ();
1194 restore_ruler_visibility ();
1195 //tempo_map_changed (PropertyChange (0));
1196 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1198 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1199 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1202 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1203 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1206 switch (_snap_type) {
1207 case SnapToRegionStart:
1208 case SnapToRegionEnd:
1209 case SnapToRegionSync:
1210 case SnapToRegionBoundary:
1211 build_region_boundary_cache ();
1218 /* register for undo history */
1219 _session->register_with_memento_command_factory(_id, this);
1221 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1223 start_updating_meters ();
1227 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1229 if (a->get_name() == "RegionMenu") {
1230 /* When the main menu's region menu is opened, we setup the actions so that they look right
1231 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1232 so we resensitize all region actions when the entered regionview or the region selection
1233 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1234 happens after the region context menu is opened. So we set a flag here, too.
1238 sensitize_the_right_region_actions ();
1239 _last_region_menu_was_main = true;
1243 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1245 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1247 using namespace Menu_Helpers;
1248 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1251 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1255 MenuList& items (fade_context_menu.items());
1259 switch (item_type) {
1261 case FadeInHandleItem:
1262 if (arv->audio_region()->fade_in_active()) {
1263 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1265 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1268 items.push_back (SeparatorElem());
1270 if (Profile->get_sae()) {
1272 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1273 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1280 *_fade_in_images[FadeLinear],
1281 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1285 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1290 *_fade_in_images[FadeFast],
1291 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1294 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1299 *_fade_in_images[FadeLogB],
1300 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1303 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1308 *_fade_in_images[FadeLogA],
1309 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1312 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1317 *_fade_in_images[FadeSlow],
1318 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1321 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1327 case FadeOutHandleItem:
1328 if (arv->audio_region()->fade_out_active()) {
1329 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1331 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1334 items.push_back (SeparatorElem());
1336 if (Profile->get_sae()) {
1337 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1338 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1344 *_fade_out_images[FadeLinear],
1345 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1349 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1354 *_fade_out_images[FadeFast],
1355 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1358 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1363 *_fade_out_images[FadeLogB],
1364 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1367 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1372 *_fade_out_images[FadeLogA],
1373 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1376 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1381 *_fade_out_images[FadeSlow],
1382 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1391 fatal << _("programming error: ")
1392 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1397 fade_context_menu.popup (button, time);
1401 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1403 using namespace Menu_Helpers;
1404 Menu* (Editor::*build_menu_function)();
1407 switch (item_type) {
1409 case RegionViewName:
1410 case RegionViewNameHighlight:
1411 case LeftFrameHandle:
1412 case RightFrameHandle:
1413 if (with_selection) {
1414 build_menu_function = &Editor::build_track_selection_context_menu;
1416 build_menu_function = &Editor::build_track_region_context_menu;
1421 if (with_selection) {
1422 build_menu_function = &Editor::build_track_selection_context_menu;
1424 build_menu_function = &Editor::build_track_context_menu;
1428 case CrossfadeViewItem:
1429 build_menu_function = &Editor::build_track_crossfade_context_menu;
1433 if (clicked_routeview->track()) {
1434 build_menu_function = &Editor::build_track_context_menu;
1436 build_menu_function = &Editor::build_track_bus_context_menu;
1441 /* probably shouldn't happen but if it does, we don't care */
1445 menu = (this->*build_menu_function)();
1446 menu->set_name ("ArdourContextMenu");
1448 /* now handle specific situations */
1450 switch (item_type) {
1452 case RegionViewName:
1453 case RegionViewNameHighlight:
1454 case LeftFrameHandle:
1455 case RightFrameHandle:
1456 if (!with_selection) {
1457 if (region_edit_menu_split_item) {
1458 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1459 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1461 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1464 if (region_edit_menu_split_multichannel_item) {
1465 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1466 region_edit_menu_split_multichannel_item->set_sensitive (true);
1468 region_edit_menu_split_multichannel_item->set_sensitive (false);
1477 case CrossfadeViewItem:
1484 /* probably shouldn't happen but if it does, we don't care */
1488 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1490 /* Bounce to disk */
1492 using namespace Menu_Helpers;
1493 MenuList& edit_items = menu->items();
1495 edit_items.push_back (SeparatorElem());
1497 switch (clicked_routeview->audio_track()->freeze_state()) {
1498 case AudioTrack::NoFreeze:
1499 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1502 case AudioTrack::Frozen:
1503 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1506 case AudioTrack::UnFrozen:
1507 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1513 if (item_type == StreamItem && clicked_routeview) {
1514 clicked_routeview->build_underlay_menu(menu);
1517 /* When the region menu is opened, we setup the actions so that they look right
1520 sensitize_the_right_region_actions ();
1521 _last_region_menu_was_main = false;
1523 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1524 menu->popup (button, time);
1528 Editor::build_track_context_menu ()
1530 using namespace Menu_Helpers;
1532 MenuList& edit_items = track_context_menu.items();
1535 add_dstream_context_items (edit_items);
1536 return &track_context_menu;
1540 Editor::build_track_bus_context_menu ()
1542 using namespace Menu_Helpers;
1544 MenuList& edit_items = track_context_menu.items();
1547 add_bus_context_items (edit_items);
1548 return &track_context_menu;
1552 Editor::build_track_region_context_menu ()
1554 using namespace Menu_Helpers;
1555 MenuList& edit_items = track_region_context_menu.items();
1558 /* we've just cleared the track region context menu, so the menu that these
1559 two items were on will have disappeared; stop them dangling.
1561 region_edit_menu_split_item = 0;
1562 region_edit_menu_split_multichannel_item = 0;
1564 /* we might try to use items that are currently attached to a crossfade menu,
1567 track_crossfade_context_menu.items().clear ();
1569 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1572 boost::shared_ptr<Track> tr;
1573 boost::shared_ptr<Playlist> pl;
1575 if ((tr = rtv->track())) {
1576 add_region_context_items (edit_items, tr);
1580 add_dstream_context_items (edit_items);
1582 return &track_region_context_menu;
1586 Editor::build_track_crossfade_context_menu ()
1588 using namespace Menu_Helpers;
1589 MenuList& edit_items = track_crossfade_context_menu.items();
1590 edit_items.clear ();
1592 /* we might try to use items that are currently attached to a crossfade menu,
1595 track_region_context_menu.items().clear ();
1597 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1600 boost::shared_ptr<Track> tr;
1601 boost::shared_ptr<Playlist> pl;
1602 boost::shared_ptr<AudioPlaylist> apl;
1604 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1606 AudioPlaylist::Crossfades xfades;
1610 /* The xfade menu is a bit of a special case, as we always use the mouse position
1611 to decide whether or not to display it (rather than the edit point). No particularly
1612 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1615 mouse_frame (where, ignored);
1616 apl->crossfades_at (where, xfades);
1618 bool const many = xfades.size() > 1;
1620 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1621 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1624 add_region_context_items (edit_items, tr);
1628 add_dstream_context_items (edit_items);
1630 return &track_crossfade_context_menu;
1634 Editor::analyze_region_selection ()
1636 if (analysis_window == 0) {
1637 analysis_window = new AnalysisWindow();
1640 analysis_window->set_session(_session);
1642 analysis_window->show_all();
1645 analysis_window->set_regionmode();
1646 analysis_window->analyze();
1648 analysis_window->present();
1652 Editor::analyze_range_selection()
1654 if (analysis_window == 0) {
1655 analysis_window = new AnalysisWindow();
1658 analysis_window->set_session(_session);
1660 analysis_window->show_all();
1663 analysis_window->set_rangemode();
1664 analysis_window->analyze();
1666 analysis_window->present();
1670 Editor::build_track_selection_context_menu ()
1672 using namespace Menu_Helpers;
1673 MenuList& edit_items = track_selection_context_menu.items();
1674 edit_items.clear ();
1676 add_selection_context_items (edit_items);
1677 // edit_items.push_back (SeparatorElem());
1678 // add_dstream_context_items (edit_items);
1680 return &track_selection_context_menu;
1683 /** Add context menu items relevant to crossfades.
1684 * @param edit_items List to add the items to.
1687 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1689 using namespace Menu_Helpers;
1690 Menu *xfade_menu = manage (new Menu);
1691 MenuList& items = xfade_menu->items();
1692 xfade_menu->set_name ("ArdourContextMenu");
1695 if (xfade->active()) {
1701 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1702 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1704 if (xfade->can_follow_overlap()) {
1706 if (xfade->following_overlap()) {
1707 str = _("Convert to Short");
1709 str = _("Convert to Full");
1712 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1716 str = xfade->out()->name();
1718 str += xfade->in()->name();
1720 str = _("Crossfade");
1723 edit_items.push_back (MenuElem (str, *xfade_menu));
1724 edit_items.push_back (SeparatorElem());
1728 Editor::xfade_edit_left_region ()
1730 if (clicked_crossfadeview) {
1731 clicked_crossfadeview->left_view.show_region_editor ();
1736 Editor::xfade_edit_right_region ()
1738 if (clicked_crossfadeview) {
1739 clicked_crossfadeview->right_view.show_region_editor ();
1744 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1746 using namespace Menu_Helpers;
1748 /* OK, stick the region submenu at the top of the list, and then add
1752 RegionSelection rs = get_regions_from_selection_and_entered ();
1754 string::size_type pos = 0;
1755 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1757 /* we have to hack up the region name because "_" has a special
1758 meaning for menu titles.
1761 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1762 menu_item_name.replace (pos, 1, "__");
1766 if (_popup_region_menu_item == 0) {
1767 _popup_region_menu_item = new MenuItem (menu_item_name);
1768 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1769 _popup_region_menu_item->show ();
1771 _popup_region_menu_item->set_label (menu_item_name);
1774 /* Use the mouse position rather than the edit point to decide whether to show the `choose top region'
1775 dialogue. If we use the edit point it gets a bit messy because the user still has to click over
1776 *some* region in order to get the region context menu stuff to be displayed at all.
1781 mouse_frame (mouse, ignored);
1783 edit_items.push_back (*_popup_region_menu_item);
1784 if (track->playlist()->count_regions_at (mouse) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1785 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1787 edit_items.push_back (SeparatorElem());
1790 /** Add context menu items relevant to selection ranges.
1791 * @param edit_items List to add the items to.
1794 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1796 using namespace Menu_Helpers;
1798 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1799 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1801 edit_items.push_back (SeparatorElem());
1802 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1804 edit_items.push_back (SeparatorElem());
1806 edit_items.push_back (
1808 _("Move Range Start to Previous Region Boundary"),
1809 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1813 edit_items.push_back (
1815 _("Move Range Start to Next Region Boundary"),
1816 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1820 edit_items.push_back (
1822 _("Move Range End to Previous Region Boundary"),
1823 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1827 edit_items.push_back (
1829 _("Move Range End to Next Region Boundary"),
1830 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1834 edit_items.push_back (SeparatorElem());
1835 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1836 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1838 edit_items.push_back (SeparatorElem());
1839 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1841 edit_items.push_back (SeparatorElem());
1842 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1843 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1845 edit_items.push_back (SeparatorElem());
1846 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1848 edit_items.push_back (SeparatorElem());
1849 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1850 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1851 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1853 edit_items.push_back (SeparatorElem());
1854 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1855 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1856 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1857 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1858 edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1863 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1865 using namespace Menu_Helpers;
1869 Menu *play_menu = manage (new Menu);
1870 MenuList& play_items = play_menu->items();
1871 play_menu->set_name ("ArdourContextMenu");
1873 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1874 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1875 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1876 play_items.push_back (SeparatorElem());
1877 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1879 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1883 Menu *select_menu = manage (new Menu);
1884 MenuList& select_items = select_menu->items();
1885 select_menu->set_name ("ArdourContextMenu");
1887 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1888 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1889 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1890 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1891 select_items.push_back (SeparatorElem());
1892 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1893 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1894 select_items.push_back (SeparatorElem());
1895 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1896 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1897 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1898 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1899 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1900 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1901 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1903 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1907 Menu *cutnpaste_menu = manage (new Menu);
1908 MenuList& cutnpaste_items = cutnpaste_menu->items();
1909 cutnpaste_menu->set_name ("ArdourContextMenu");
1911 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1912 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1913 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1915 cutnpaste_items.push_back (SeparatorElem());
1917 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1918 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1920 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1922 /* Adding new material */
1924 edit_items.push_back (SeparatorElem());
1925 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1926 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1930 Menu *nudge_menu = manage (new Menu());
1931 MenuList& nudge_items = nudge_menu->items();
1932 nudge_menu->set_name ("ArdourContextMenu");
1934 edit_items.push_back (SeparatorElem());
1935 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1936 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1937 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1938 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1940 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1944 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1946 using namespace Menu_Helpers;
1950 Menu *play_menu = manage (new Menu);
1951 MenuList& play_items = play_menu->items();
1952 play_menu->set_name ("ArdourContextMenu");
1954 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1955 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1956 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1960 Menu *select_menu = manage (new Menu);
1961 MenuList& select_items = select_menu->items();
1962 select_menu->set_name ("ArdourContextMenu");
1964 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1965 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1966 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1967 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1968 select_items.push_back (SeparatorElem());
1969 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1970 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1971 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1972 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1974 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1978 Menu *cutnpaste_menu = manage (new Menu);
1979 MenuList& cutnpaste_items = cutnpaste_menu->items();
1980 cutnpaste_menu->set_name ("ArdourContextMenu");
1982 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1983 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1984 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1986 Menu *nudge_menu = manage (new Menu());
1987 MenuList& nudge_items = nudge_menu->items();
1988 nudge_menu->set_name ("ArdourContextMenu");
1990 edit_items.push_back (SeparatorElem());
1991 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1992 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1993 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1994 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1996 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2000 Editor::snap_type() const
2006 Editor::snap_mode() const
2012 Editor::set_snap_to (SnapType st)
2014 unsigned int snap_ind = (unsigned int)st;
2018 if (snap_ind > snap_type_strings.size() - 1) {
2020 _snap_type = (SnapType)snap_ind;
2023 string str = snap_type_strings[snap_ind];
2025 if (str != snap_type_selector.get_active_text()) {
2026 snap_type_selector.set_active_text (str);
2031 switch (_snap_type) {
2032 case SnapToBeatDiv32:
2033 case SnapToBeatDiv28:
2034 case SnapToBeatDiv24:
2035 case SnapToBeatDiv20:
2036 case SnapToBeatDiv16:
2037 case SnapToBeatDiv14:
2038 case SnapToBeatDiv12:
2039 case SnapToBeatDiv10:
2040 case SnapToBeatDiv8:
2041 case SnapToBeatDiv7:
2042 case SnapToBeatDiv6:
2043 case SnapToBeatDiv5:
2044 case SnapToBeatDiv4:
2045 case SnapToBeatDiv3:
2046 case SnapToBeatDiv2:
2047 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2048 update_tempo_based_rulers ();
2051 case SnapToRegionStart:
2052 case SnapToRegionEnd:
2053 case SnapToRegionSync:
2054 case SnapToRegionBoundary:
2055 build_region_boundary_cache ();
2063 SnapChanged (); /* EMIT SIGNAL */
2067 Editor::set_snap_mode (SnapMode mode)
2070 string str = snap_mode_strings[(int)mode];
2072 if (str != snap_mode_selector.get_active_text ()) {
2073 snap_mode_selector.set_active_text (str);
2079 Editor::set_edit_point_preference (EditPoint ep, bool force)
2081 bool changed = (_edit_point != ep);
2084 string str = edit_point_strings[(int)ep];
2086 if (str != edit_point_selector.get_active_text ()) {
2087 edit_point_selector.set_active_text (str);
2090 set_canvas_cursor ();
2092 if (!force && !changed) {
2096 const char* action=NULL;
2098 switch (_edit_point) {
2099 case EditAtPlayhead:
2100 action = "edit-at-playhead";
2102 case EditAtSelectedMarker:
2103 action = "edit-at-marker";
2106 action = "edit-at-mouse";
2110 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2112 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2116 bool in_track_canvas;
2118 if (!mouse_frame (foo, in_track_canvas)) {
2119 in_track_canvas = false;
2122 reset_canvas_action_sensitivity (in_track_canvas);
2128 Editor::set_state (const XMLNode& node, int /*version*/)
2130 const XMLProperty* prop;
2132 int x, y, xoff, yoff;
2135 if ((prop = node.property ("id")) != 0) {
2136 _id = prop->value ();
2139 g.base_width = default_width;
2140 g.base_height = default_height;
2146 if ((geometry = find_named_node (node, "geometry")) != 0) {
2150 if ((prop = geometry->property("x_size")) == 0) {
2151 prop = geometry->property ("x-size");
2154 g.base_width = atoi(prop->value());
2156 if ((prop = geometry->property("y_size")) == 0) {
2157 prop = geometry->property ("y-size");
2160 g.base_height = atoi(prop->value());
2163 if ((prop = geometry->property ("x_pos")) == 0) {
2164 prop = geometry->property ("x-pos");
2167 x = atoi (prop->value());
2170 if ((prop = geometry->property ("y_pos")) == 0) {
2171 prop = geometry->property ("y-pos");
2174 y = atoi (prop->value());
2177 if ((prop = geometry->property ("x_off")) == 0) {
2178 prop = geometry->property ("x-off");
2181 xoff = atoi (prop->value());
2183 if ((prop = geometry->property ("y_off")) == 0) {
2184 prop = geometry->property ("y-off");
2187 yoff = atoi (prop->value());
2191 set_default_size (g.base_width, g.base_height);
2194 if (_session && (prop = node.property ("playhead"))) {
2196 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2197 playhead_cursor->set_position (pos);
2199 playhead_cursor->set_position (0);
2202 if ((prop = node.property ("mixer-width"))) {
2203 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2206 if ((prop = node.property ("zoom-focus"))) {
2207 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2210 if ((prop = node.property ("zoom"))) {
2211 reset_zoom (PBD::atof (prop->value()));
2213 reset_zoom (frames_per_unit);
2216 if ((prop = node.property ("snap-to"))) {
2217 set_snap_to ((SnapType) atoi (prop->value()));
2220 if ((prop = node.property ("snap-mode"))) {
2221 set_snap_mode ((SnapMode) atoi (prop->value()));
2224 if ((prop = node.property ("mouse-mode"))) {
2225 MouseMode m = str2mousemode(prop->value());
2226 set_mouse_mode (m, true);
2228 set_mouse_mode (MouseObject, true);
2231 if ((prop = node.property ("left-frame")) != 0) {
2233 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2234 reset_x_origin (pos);
2238 if ((prop = node.property ("y-origin")) != 0) {
2239 reset_y_origin (atof (prop->value ()));
2242 if ((prop = node.property ("internal-edit"))) {
2243 bool yn = string_is_affirmative (prop->value());
2244 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2246 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2247 tact->set_active (!yn);
2248 tact->set_active (yn);
2252 if ((prop = node.property ("join-object-range"))) {
2253 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2256 if ((prop = node.property ("edit-point"))) {
2257 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2260 if ((prop = node.property ("show-measures"))) {
2261 bool yn = string_is_affirmative (prop->value());
2262 _show_measures = yn;
2263 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2265 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2266 /* do it twice to force the change */
2267 tact->set_active (!yn);
2268 tact->set_active (yn);
2272 if ((prop = node.property ("follow-playhead"))) {
2273 bool yn = string_is_affirmative (prop->value());
2274 set_follow_playhead (yn);
2275 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2277 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2278 if (tact->get_active() != yn) {
2279 tact->set_active (yn);
2284 if ((prop = node.property ("stationary-playhead"))) {
2285 bool yn = (prop->value() == "yes");
2286 set_stationary_playhead (yn);
2287 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2289 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2290 if (tact->get_active() != yn) {
2291 tact->set_active (yn);
2296 if ((prop = node.property ("region-list-sort-type"))) {
2297 RegionListSortType st;
2298 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2301 if ((prop = node.property ("xfades-visible"))) {
2302 bool yn = string_is_affirmative (prop->value());
2303 _xfade_visibility = !yn;
2304 // set_xfade_visibility (yn);
2307 if ((prop = node.property ("show-editor-mixer"))) {
2309 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2312 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2313 bool yn = string_is_affirmative (prop->value());
2315 /* do it twice to force the change */
2317 tact->set_active (!yn);
2318 tact->set_active (yn);
2321 if ((prop = node.property ("show-editor-list"))) {
2323 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2326 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2327 bool yn = string_is_affirmative (prop->value());
2329 /* do it twice to force the change */
2331 tact->set_active (!yn);
2332 tact->set_active (yn);
2335 if ((prop = node.property (X_("editor-list-page")))) {
2336 _the_notebook.set_current_page (atoi (prop->value ()));
2339 if ((prop = node.property (X_("show-marker-lines")))) {
2340 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2342 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2343 bool yn = string_is_affirmative (prop->value ());
2345 tact->set_active (!yn);
2346 tact->set_active (yn);
2349 XMLNodeList children = node.children ();
2350 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2351 selection->set_state (**i, Stateful::current_state_version);
2352 _regions->set_state (**i);
2359 Editor::get_state ()
2361 XMLNode* node = new XMLNode ("Editor");
2364 _id.print (buf, sizeof (buf));
2365 node->add_property ("id", buf);
2367 if (is_realized()) {
2368 Glib::RefPtr<Gdk::Window> win = get_window();
2370 int x, y, xoff, yoff, width, height;
2371 win->get_root_origin(x, y);
2372 win->get_position(xoff, yoff);
2373 win->get_size(width, height);
2375 XMLNode* geometry = new XMLNode ("geometry");
2377 snprintf(buf, sizeof(buf), "%d", width);
2378 geometry->add_property("x-size", string(buf));
2379 snprintf(buf, sizeof(buf), "%d", height);
2380 geometry->add_property("y-size", string(buf));
2381 snprintf(buf, sizeof(buf), "%d", x);
2382 geometry->add_property("x-pos", string(buf));
2383 snprintf(buf, sizeof(buf), "%d", y);
2384 geometry->add_property("y-pos", string(buf));
2385 snprintf(buf, sizeof(buf), "%d", xoff);
2386 geometry->add_property("x-off", string(buf));
2387 snprintf(buf, sizeof(buf), "%d", yoff);
2388 geometry->add_property("y-off", string(buf));
2389 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2390 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2391 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2392 snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position);
2393 geometry->add_property("pre-maximal-horizontal-pane-position", string(buf));
2394 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2395 geometry->add_property("edit-vertical-pane-pos", string(buf));
2397 node->add_child_nocopy (*geometry);
2400 maybe_add_mixer_strip_width (*node);
2402 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2403 node->add_property ("zoom-focus", buf);
2404 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2405 node->add_property ("zoom", buf);
2406 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2407 node->add_property ("snap-to", buf);
2408 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2409 node->add_property ("snap-mode", buf);
2411 node->add_property ("edit-point", enum_2_string (_edit_point));
2413 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2414 node->add_property ("playhead", buf);
2415 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2416 node->add_property ("left-frame", buf);
2417 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2418 node->add_property ("y-origin", buf);
2420 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2421 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2422 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2423 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2424 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2425 node->add_property ("mouse-mode", enum2str(mouse_mode));
2426 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2427 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2429 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2431 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2432 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2435 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2437 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2438 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2441 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2442 node->add_property (X_("editor-list-page"), buf);
2444 if (button_bindings) {
2445 XMLNode* bb = new XMLNode (X_("Buttons"));
2446 button_bindings->save (*bb);
2447 node->add_child_nocopy (*bb);
2450 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2452 node->add_child_nocopy (selection->get_state ());
2453 node->add_child_nocopy (_regions->get_state ());
2460 /** @param y y offset from the top of all trackviews.
2461 * @return pair: TimeAxisView that y is over, layer index.
2462 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2463 * in stacked region display mode, otherwise 0.
2465 std::pair<TimeAxisView *, layer_t>
2466 Editor::trackview_by_y_position (double y)
2468 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2470 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2476 return std::make_pair ( (TimeAxisView *) 0, 0);
2479 /** Snap a position to the grid, if appropriate, taking into account current
2480 * grid settings and also the state of any snap modifier keys that may be pressed.
2481 * @param start Position to snap.
2482 * @param event Event to get current key modifier information from, or 0.
2485 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2487 if (!_session || !event) {
2491 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2492 if (_snap_mode == SnapOff) {
2493 snap_to_internal (start, direction, for_mark);
2496 if (_snap_mode != SnapOff) {
2497 snap_to_internal (start, direction, for_mark);
2503 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2505 if (!_session || _snap_mode == SnapOff) {
2509 snap_to_internal (start, direction, for_mark);
2513 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2515 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2516 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2518 switch (_snap_type) {
2519 case SnapToTimecodeFrame:
2520 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2521 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2523 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2527 case SnapToTimecodeSeconds:
2528 if (_session->config.get_timecode_offset_negative()) {
2529 start += _session->config.get_timecode_offset ();
2531 start -= _session->config.get_timecode_offset ();
2533 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2534 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2536 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2539 if (_session->config.get_timecode_offset_negative()) {
2540 start -= _session->config.get_timecode_offset ();
2542 start += _session->config.get_timecode_offset ();
2546 case SnapToTimecodeMinutes:
2547 if (_session->config.get_timecode_offset_negative()) {
2548 start += _session->config.get_timecode_offset ();
2550 start -= _session->config.get_timecode_offset ();
2552 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2553 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2555 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2557 if (_session->config.get_timecode_offset_negative()) {
2558 start -= _session->config.get_timecode_offset ();
2560 start += _session->config.get_timecode_offset ();
2564 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2570 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2572 const framepos_t one_second = _session->frame_rate();
2573 const framepos_t one_minute = _session->frame_rate() * 60;
2574 framepos_t presnap = start;
2578 switch (_snap_type) {
2579 case SnapToTimecodeFrame:
2580 case SnapToTimecodeSeconds:
2581 case SnapToTimecodeMinutes:
2582 return timecode_snap_to_internal (start, direction, for_mark);
2585 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2586 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2588 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2593 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2594 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2596 start = (framepos_t) floor ((double) start / one_second) * one_second;
2601 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2602 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2604 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2609 start = _session->tempo_map().round_to_bar (start, direction);
2613 start = _session->tempo_map().round_to_beat (start, direction);
2616 case SnapToBeatDiv32:
2617 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2619 case SnapToBeatDiv28:
2620 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2622 case SnapToBeatDiv24:
2623 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2625 case SnapToBeatDiv20:
2626 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2628 case SnapToBeatDiv16:
2629 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2631 case SnapToBeatDiv14:
2632 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2634 case SnapToBeatDiv12:
2635 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2637 case SnapToBeatDiv10:
2638 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2640 case SnapToBeatDiv8:
2641 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2643 case SnapToBeatDiv7:
2644 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2646 case SnapToBeatDiv6:
2647 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2649 case SnapToBeatDiv5:
2650 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2652 case SnapToBeatDiv4:
2653 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2655 case SnapToBeatDiv3:
2656 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2658 case SnapToBeatDiv2:
2659 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2667 _session->locations()->marks_either_side (start, before, after);
2669 if (before == max_framepos) {
2671 } else if (after == max_framepos) {
2673 } else if (before != max_framepos && after != max_framepos) {
2674 /* have before and after */
2675 if ((start - before) < (after - start)) {
2684 case SnapToRegionStart:
2685 case SnapToRegionEnd:
2686 case SnapToRegionSync:
2687 case SnapToRegionBoundary:
2688 if (!region_boundary_cache.empty()) {
2690 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2691 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2693 if (direction > 0) {
2694 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2696 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2699 if (next != region_boundary_cache.begin ()) {
2704 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2705 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2707 if (start > (p + n) / 2) {
2716 switch (_snap_mode) {
2722 if (presnap > start) {
2723 if (presnap > (start + unit_to_frame(snap_threshold))) {
2727 } else if (presnap < start) {
2728 if (presnap < (start - unit_to_frame(snap_threshold))) {
2734 /* handled at entry */
2742 Editor::setup_toolbar ()
2744 HBox* mode_box = manage(new HBox);
2745 mode_box->set_border_width (2);
2746 mode_box->set_spacing(4);
2748 /* table containing mode buttons */
2750 HBox* mouse_mode_button_box = manage (new HBox ());
2752 if (Profile->get_sae()) {
2753 mouse_mode_button_box->pack_start (mouse_move_button);
2755 mouse_mode_button_box->pack_start (mouse_move_button);
2756 mouse_mode_button_box->pack_start (join_object_range_button);
2757 mouse_mode_button_box->pack_start (mouse_select_button);
2760 mouse_mode_button_box->pack_start (mouse_zoom_button);
2762 if (!Profile->get_sae()) {
2763 mouse_mode_button_box->pack_start (mouse_gain_button);
2766 mouse_mode_button_box->pack_start (mouse_timefx_button);
2767 mouse_mode_button_box->pack_start (mouse_audition_button);
2768 mouse_mode_button_box->pack_start (internal_edit_button);
2770 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2771 if (!Profile->get_sae()) {
2772 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2774 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2776 edit_mode_selector.set_name ("EditModeSelector");
2777 set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2778 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2780 mode_box->pack_start (edit_mode_selector);
2781 mode_box->pack_start (*mouse_mode_button_box);
2783 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2784 _mouse_mode_tearoff->set_name ("MouseModeBase");
2785 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2787 if (Profile->get_sae()) {
2788 _mouse_mode_tearoff->set_can_be_torn_off (false);
2791 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2792 &_mouse_mode_tearoff->tearoff_window()));
2793 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2794 &_mouse_mode_tearoff->tearoff_window(), 1));
2795 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2796 &_mouse_mode_tearoff->tearoff_window()));
2797 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2798 &_mouse_mode_tearoff->tearoff_window(), 1));
2800 mouse_move_button.set_mode (false);
2801 mouse_select_button.set_mode (false);
2802 mouse_gain_button.set_mode (false);
2803 mouse_zoom_button.set_mode (false);
2804 mouse_timefx_button.set_mode (false);
2805 mouse_audition_button.set_mode (false);
2806 join_object_range_button.set_mode (false);
2808 mouse_move_button.set_name ("MouseModeButton");
2809 mouse_select_button.set_name ("MouseModeButton");
2810 mouse_gain_button.set_name ("MouseModeButton");
2811 mouse_zoom_button.set_name ("MouseModeButton");
2812 mouse_timefx_button.set_name ("MouseModeButton");
2813 mouse_audition_button.set_name ("MouseModeButton");
2814 internal_edit_button.set_name ("MouseModeButton");
2815 join_object_range_button.set_name ("MouseModeButton");
2817 mouse_move_button.unset_flags (CAN_FOCUS);
2818 mouse_select_button.unset_flags (CAN_FOCUS);
2819 mouse_gain_button.unset_flags (CAN_FOCUS);
2820 mouse_zoom_button.unset_flags (CAN_FOCUS);
2821 mouse_timefx_button.unset_flags (CAN_FOCUS);
2822 mouse_audition_button.unset_flags (CAN_FOCUS);
2823 internal_edit_button.unset_flags (CAN_FOCUS);
2824 join_object_range_button.unset_flags (CAN_FOCUS);
2828 _zoom_box.set_spacing (1);
2829 _zoom_box.set_border_width (0);
2831 zoom_in_button.set_name ("EditorTimeButton");
2832 zoom_in_button.set_image (*(manage (new Image (::get_icon ("zoom_in")))));
2833 zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2835 zoom_out_button.set_name ("EditorTimeButton");
2836 zoom_out_button.set_image (*(manage (new Image (::get_icon ("zoom_out")))));
2837 zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2839 zoom_out_full_button.set_name ("EditorTimeButton");
2840 zoom_out_full_button.set_image (*(manage (new Image (::get_icon ("zoom_full")))));
2841 zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2843 zoom_focus_selector.set_name ("ZoomFocusSelector");
2844 set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2845 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2847 _zoom_box.pack_start (zoom_out_button, false, false);
2848 _zoom_box.pack_start (zoom_in_button, false, false);
2849 _zoom_box.pack_start (zoom_out_full_button, false, false);
2851 _zoom_box.pack_start (zoom_focus_selector);
2853 /* Track zoom buttons */
2854 tav_expand_button.set_name ("TrackHeightButton");
2855 tav_expand_button.set_size_request (-1, 20);
2856 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2857 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2858 act->connect_proxy (tav_expand_button);
2860 tav_shrink_button.set_name ("TrackHeightButton");
2861 tav_shrink_button.set_size_request (-1, 20);
2862 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2863 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2864 act->connect_proxy (tav_shrink_button);
2866 _zoom_box.pack_start (tav_shrink_button);
2867 _zoom_box.pack_start (tav_expand_button);
2869 _zoom_tearoff = manage (new TearOff (_zoom_box));
2871 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2872 &_zoom_tearoff->tearoff_window()));
2873 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2874 &_zoom_tearoff->tearoff_window(), 0));
2875 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2876 &_zoom_tearoff->tearoff_window()));
2877 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2878 &_zoom_tearoff->tearoff_window(), 0));
2880 snap_box.set_spacing (1);
2881 snap_box.set_border_width (2);
2883 snap_type_selector.set_name ("SnapTypeSelector");
2884 set_popdown_strings (snap_type_selector, snap_type_strings, true);
2885 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2887 snap_mode_selector.set_name ("SnapModeSelector");
2888 set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2889 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2891 edit_point_selector.set_name ("EditPointSelector");
2892 set_popdown_strings (edit_point_selector, edit_point_strings, true);
2893 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2895 snap_box.pack_start (snap_mode_selector, false, false);
2896 snap_box.pack_start (snap_type_selector, false, false);
2897 snap_box.pack_start (edit_point_selector, false, false);
2901 HBox *nudge_box = manage (new HBox);
2902 nudge_box->set_spacing(1);
2903 nudge_box->set_border_width (2);
2905 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2906 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2908 nudge_box->pack_start (nudge_backward_button, false, false);
2909 nudge_box->pack_start (nudge_forward_button, false, false);
2910 nudge_box->pack_start (nudge_clock, false, false);
2913 /* Pack everything in... */
2915 HBox* hbox = manage (new HBox);
2916 hbox->set_spacing(10);
2918 _tools_tearoff = manage (new TearOff (*hbox));
2919 _tools_tearoff->set_name ("MouseModeBase");
2920 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2922 if (Profile->get_sae()) {
2923 _tools_tearoff->set_can_be_torn_off (false);
2926 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2927 &_tools_tearoff->tearoff_window()));
2928 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2929 &_tools_tearoff->tearoff_window(), 0));
2930 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2931 &_tools_tearoff->tearoff_window()));
2932 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2933 &_tools_tearoff->tearoff_window(), 0));
2935 toolbar_hbox.set_spacing (10);
2936 toolbar_hbox.set_border_width (1);
2938 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2939 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2940 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2942 hbox->pack_start (snap_box, false, false);
2943 if (!Profile->get_small_screen()) {
2944 hbox->pack_start (*nudge_box, false, false);
2946 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2948 hbox->pack_start (panic_box, false, false);
2952 toolbar_base.set_name ("ToolBarBase");
2953 toolbar_base.add (toolbar_hbox);
2955 _toolbar_viewport.add (toolbar_base);
2956 /* stick to the required height but allow width to vary if there's not enough room */
2957 _toolbar_viewport.set_size_request (1, -1);
2959 toolbar_frame.set_shadow_type (SHADOW_OUT);
2960 toolbar_frame.set_name ("BaseFrame");
2961 toolbar_frame.add (_toolbar_viewport);
2963 DPIReset.connect (sigc::mem_fun (*this, &Editor::resize_text_widgets));
2967 Editor::setup_tooltips ()
2969 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2970 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2971 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2972 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2973 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2974 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2975 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2976 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2977 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2978 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2979 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2980 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2981 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2982 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2983 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2984 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2985 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2986 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2987 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2988 ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
2989 ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
2990 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2994 Editor::midi_panic ()
2996 cerr << "MIDI panic\n";
2999 _session->midi_panic();
3004 Editor::setup_midi_toolbar ()
3008 /* Midi sound notes */
3009 midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
3010 midi_sound_notes.unset_flags (CAN_FOCUS);
3014 act = ActionManager::get_action (X_("MIDI"), X_("panic"));
3015 midi_panic_button.set_name("MidiPanicButton");
3016 act->connect_proxy (midi_panic_button);
3018 panic_box.pack_start (midi_sound_notes , true, true);
3019 panic_box.pack_start (midi_panic_button, true, true);
3023 Editor::convert_drop_to_paths (
3024 vector<string>& paths,
3025 const RefPtr<Gdk::DragContext>& /*context*/,
3028 const SelectionData& data,
3032 if (_session == 0) {
3036 vector<string> uris = data.get_uris();
3040 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3041 are actually URI lists. So do it by hand.
3044 if (data.get_target() != "text/plain") {
3048 /* Parse the "uri-list" format that Nautilus provides,
3049 where each pathname is delimited by \r\n.
3051 THERE MAY BE NO NULL TERMINATING CHAR!!!
3054 string txt = data.get_text();
3058 p = (const char *) malloc (txt.length() + 1);
3059 txt.copy ((char *) p, txt.length(), 0);
3060 ((char*)p)[txt.length()] = '\0';
3066 while (g_ascii_isspace (*p))
3070 while (*q && (*q != '\n') && (*q != '\r')) {
3077 while (q > p && g_ascii_isspace (*q))
3082 uris.push_back (string (p, q - p + 1));
3086 p = strchr (p, '\n');
3098 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3100 if ((*i).substr (0,7) == "file://") {
3103 PBD::url_decode (p);
3105 // scan forward past three slashes
3107 string::size_type slashcnt = 0;
3108 string::size_type n = 0;
3109 string::iterator x = p.begin();
3111 while (slashcnt < 3 && x != p.end()) {
3114 } else if (slashcnt == 3) {
3121 if (slashcnt != 3 || x == p.end()) {
3122 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3126 paths.push_back (p.substr (n - 1));
3134 Editor::new_tempo_section ()
3140 Editor::map_transport_state ()
3142 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3144 if (_session && _session->transport_stopped()) {
3145 have_pending_keyboard_selection = false;
3148 update_loop_range_view (true);
3153 Editor::State::State (PublicEditor const * e)
3155 selection = new Selection (e);
3158 Editor::State::~State ()
3164 Editor::begin_reversible_command (string name)
3167 _session->begin_reversible_command (name);
3172 Editor::begin_reversible_command (GQuark q)
3175 _session->begin_reversible_command (q);
3180 Editor::commit_reversible_command ()
3183 _session->commit_reversible_command ();
3188 Editor::history_changed ()
3192 if (undo_action && _session) {
3193 if (_session->undo_depth() == 0) {
3196 label = string_compose(_("Undo (%1)"), _session->next_undo());
3198 undo_action->property_label() = label;
3201 if (redo_action && _session) {
3202 if (_session->redo_depth() == 0) {
3205 label = string_compose(_("Redo (%1)"), _session->next_redo());
3207 redo_action->property_label() = label;
3212 Editor::duplicate_dialog (bool with_dialog)
3216 if (mouse_mode == MouseRange) {
3217 if (selection->time.length() == 0) {
3222 RegionSelection rs = get_regions_from_selection_and_entered ();
3224 if (mouse_mode != MouseRange && rs.empty()) {
3230 ArdourDialog win (_("Duplicate"));
3231 Label label (_("Number of duplications:"));
3232 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3233 SpinButton spinner (adjustment, 0.0, 1);
3236 win.get_vbox()->set_spacing (12);
3237 win.get_vbox()->pack_start (hbox);
3238 hbox.set_border_width (6);
3239 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3241 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3242 place, visually. so do this by hand.
3245 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3246 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3247 spinner.grab_focus();
3253 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3254 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3255 win.set_default_response (RESPONSE_ACCEPT);
3257 win.set_position (WIN_POS_MOUSE);
3259 spinner.grab_focus ();
3261 switch (win.run ()) {
3262 case RESPONSE_ACCEPT:
3268 times = adjustment.get_value();
3271 if (mouse_mode == MouseRange) {
3272 duplicate_selection (times);
3274 duplicate_some_regions (rs, times);
3279 Editor::set_edit_mode (EditMode m)
3281 Config->set_edit_mode (m);
3285 Editor::cycle_edit_mode ()
3287 switch (Config->get_edit_mode()) {
3289 if (Profile->get_sae()) {
3290 Config->set_edit_mode (Lock);
3292 Config->set_edit_mode (Splice);
3296 Config->set_edit_mode (Lock);
3299 Config->set_edit_mode (Slide);
3305 Editor::edit_mode_selection_done ()
3307 string s = edit_mode_selector.get_active_text ();
3310 Config->set_edit_mode (string_to_edit_mode (s));
3315 Editor::snap_type_selection_done ()
3317 string choice = snap_type_selector.get_active_text();
3318 SnapType snaptype = SnapToBeat;
3320 if (choice == _("Beats/2")) {
3321 snaptype = SnapToBeatDiv2;
3322 } else if (choice == _("Beats/3")) {
3323 snaptype = SnapToBeatDiv3;
3324 } else if (choice == _("Beats/4")) {
3325 snaptype = SnapToBeatDiv4;
3326 } else if (choice == _("Beats/5")) {
3327 snaptype = SnapToBeatDiv5;
3328 } else if (choice == _("Beats/6")) {
3329 snaptype = SnapToBeatDiv6;
3330 } else if (choice == _("Beats/7")) {
3331 snaptype = SnapToBeatDiv7;
3332 } else if (choice == _("Beats/8")) {
3333 snaptype = SnapToBeatDiv8;
3334 } else if (choice == _("Beats/10")) {
3335 snaptype = SnapToBeatDiv10;
3336 } else if (choice == _("Beats/12")) {
3337 snaptype = SnapToBeatDiv12;
3338 } else if (choice == _("Beats/14")) {
3339 snaptype = SnapToBeatDiv14;
3340 } else if (choice == _("Beats/16")) {
3341 snaptype = SnapToBeatDiv16;
3342 } else if (choice == _("Beats/20")) {
3343 snaptype = SnapToBeatDiv20;
3344 } else if (choice == _("Beats/24")) {
3345 snaptype = SnapToBeatDiv24;
3346 } else if (choice == _("Beats/28")) {
3347 snaptype = SnapToBeatDiv28;
3348 } else if (choice == _("Beats/32")) {
3349 snaptype = SnapToBeatDiv32;
3350 } else if (choice == _("Beats")) {
3351 snaptype = SnapToBeat;
3352 } else if (choice == _("Bars")) {
3353 snaptype = SnapToBar;
3354 } else if (choice == _("Marks")) {
3355 snaptype = SnapToMark;
3356 } else if (choice == _("Region starts")) {
3357 snaptype = SnapToRegionStart;
3358 } else if (choice == _("Region ends")) {
3359 snaptype = SnapToRegionEnd;
3360 } else if (choice == _("Region bounds")) {
3361 snaptype = SnapToRegionBoundary;
3362 } else if (choice == _("Region syncs")) {
3363 snaptype = SnapToRegionSync;
3364 } else if (choice == _("CD Frames")) {
3365 snaptype = SnapToCDFrame;
3366 } else if (choice == _("Timecode Frames")) {
3367 snaptype = SnapToTimecodeFrame;
3368 } else if (choice == _("Timecode Seconds")) {
3369 snaptype = SnapToTimecodeSeconds;
3370 } else if (choice == _("Timecode Minutes")) {
3371 snaptype = SnapToTimecodeMinutes;
3372 } else if (choice == _("Seconds")) {
3373 snaptype = SnapToSeconds;
3374 } else if (choice == _("Minutes")) {
3375 snaptype = SnapToMinutes;
3378 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3380 ract->set_active ();
3385 Editor::snap_mode_selection_done ()
3387 string choice = snap_mode_selector.get_active_text();
3388 SnapMode mode = SnapNormal;
3390 if (choice == _("No Grid")) {
3392 } else if (choice == _("Grid")) {
3394 } else if (choice == _("Magnetic")) {
3395 mode = SnapMagnetic;
3398 RefPtr<RadioAction> ract = snap_mode_action (mode);
3401 ract->set_active (true);
3406 Editor::cycle_edit_point (bool with_marker)
3408 switch (_edit_point) {
3410 set_edit_point_preference (EditAtPlayhead);
3412 case EditAtPlayhead:
3414 set_edit_point_preference (EditAtSelectedMarker);
3416 set_edit_point_preference (EditAtMouse);
3419 case EditAtSelectedMarker:
3420 set_edit_point_preference (EditAtMouse);
3426 Editor::edit_point_selection_done ()
3428 string choice = edit_point_selector.get_active_text();
3429 EditPoint ep = EditAtSelectedMarker;
3431 if (choice == _("Marker")) {
3432 set_edit_point_preference (EditAtSelectedMarker);
3433 } else if (choice == _("Playhead")) {
3434 set_edit_point_preference (EditAtPlayhead);
3436 set_edit_point_preference (EditAtMouse);
3439 RefPtr<RadioAction> ract = edit_point_action (ep);
3442 ract->set_active (true);
3447 Editor::zoom_focus_selection_done ()
3449 string choice = zoom_focus_selector.get_active_text();
3450 ZoomFocus focus_type = ZoomFocusLeft;
3452 if (choice == _("Left")) {
3453 focus_type = ZoomFocusLeft;
3454 } else if (choice == _("Right")) {
3455 focus_type = ZoomFocusRight;
3456 } else if (choice == _("Center")) {
3457 focus_type = ZoomFocusCenter;
3458 } else if (choice == _("Playhead")) {
3459 focus_type = ZoomFocusPlayhead;
3460 } else if (choice == _("Mouse")) {
3461 focus_type = ZoomFocusMouse;
3462 } else if (choice == _("Edit point")) {
3463 focus_type = ZoomFocusEdit;
3466 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3469 ract->set_active ();
3474 Editor::edit_controls_button_release (GdkEventButton* ev)
3476 if (Keyboard::is_context_menu_event (ev)) {
3477 ARDOUR_UI::instance()->add_route (this);
3478 } else if (ev->button == 1) {
3479 selection->clear_tracks ();
3486 Editor::mouse_select_button_release (GdkEventButton* ev)
3488 /* this handles just right-clicks */
3490 if (ev->button != 3) {
3498 Editor::set_zoom_focus (ZoomFocus f)
3500 string str = zoom_focus_strings[(int)f];
3502 if (str != zoom_focus_selector.get_active_text()) {
3503 zoom_focus_selector.set_active_text (str);
3506 if (zoom_focus != f) {
3513 Editor::ensure_float (Window& win)
3515 win.set_transient_for (*this);
3519 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3521 /* recover or initialize pane positions. do this here rather than earlier because
3522 we don't want the positions to change the child allocations, which they seem to do.
3528 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3540 width = default_width;
3541 height = default_height;
3543 if ((geometry = find_named_node (*node, "geometry")) != 0) {
3545 prop = geometry->property ("x-size");
3547 width = atoi (prop->value());
3549 prop = geometry->property ("y-size");
3551 height = atoi (prop->value());
3555 if (which == static_cast<Paned*> (&edit_pane)) {
3557 if (done & Horizontal) {
3561 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3562 _notebook_shrunk = string_is_affirmative (prop->value ());
3565 if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) {
3566 pre_maximal_horizontal_pane_position = atoi (prop->value ());
3569 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3570 /* initial allocation is 90% to canvas, 10% to notebook */
3571 pos = (int) floor (alloc.get_width() * 0.90f);
3572 snprintf (buf, sizeof(buf), "%d", pos);
3574 pos = atoi (prop->value());
3577 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3578 edit_pane.set_position (pos);
3579 if (pre_maximal_horizontal_pane_position == 0) {
3580 pre_maximal_horizontal_pane_position = pos;
3584 done = (Pane) (done | Horizontal);
3586 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3588 if (done & Vertical) {
3592 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3593 /* initial allocation is 90% to canvas, 10% to summary */
3594 pos = (int) floor (alloc.get_height() * 0.90f);
3595 snprintf (buf, sizeof(buf), "%d", pos);
3597 pos = atoi (prop->value());
3600 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3601 editor_summary_pane.set_position (pos);
3602 pre_maximal_vertical_pane_position = pos;
3605 done = (Pane) (done | Vertical);
3610 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3612 if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3613 top_hbox.remove (toolbar_frame);
3618 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3620 if (toolbar_frame.get_parent() == 0) {
3621 top_hbox.pack_end (toolbar_frame);
3626 Editor::set_show_measures (bool yn)
3628 if (_show_measures != yn) {
3631 if ((_show_measures = yn) == true) {
3633 tempo_lines->show();
3641 Editor::toggle_follow_playhead ()
3643 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3645 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3646 set_follow_playhead (tact->get_active());
3650 /** @param yn true to follow playhead, otherwise false.
3651 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3654 Editor::set_follow_playhead (bool yn, bool catch_up)
3656 if (_follow_playhead != yn) {
3657 if ((_follow_playhead = yn) == true && catch_up) {
3659 reset_x_origin_to_follow_playhead ();
3666 Editor::toggle_stationary_playhead ()
3668 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3670 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3671 set_stationary_playhead (tact->get_active());
3676 Editor::set_stationary_playhead (bool yn)
3678 if (_stationary_playhead != yn) {
3679 if ((_stationary_playhead = yn) == true) {
3681 // FIXME need a 3.0 equivalent of this 2.X call
3682 // update_current_screen ();
3689 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3691 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3693 xfade->set_active (!xfade->active());
3698 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3700 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3702 xfade->set_follow_overlap (!xfade->following_overlap());
3707 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3709 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3715 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3719 switch (cew.run ()) {
3720 case RESPONSE_ACCEPT:
3727 PropertyChange all_crossfade_properties;
3728 all_crossfade_properties.add (ARDOUR::Properties::active);
3729 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3730 xfade->PropertyChanged (all_crossfade_properties);
3734 Editor::playlist_selector () const
3736 return *_playlist_selector;
3740 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3744 switch (_snap_type) {
3749 case SnapToBeatDiv32:
3752 case SnapToBeatDiv28:
3755 case SnapToBeatDiv24:
3758 case SnapToBeatDiv20:
3761 case SnapToBeatDiv16:
3764 case SnapToBeatDiv14:
3767 case SnapToBeatDiv12:
3770 case SnapToBeatDiv10:
3773 case SnapToBeatDiv8:
3776 case SnapToBeatDiv7:
3779 case SnapToBeatDiv6:
3782 case SnapToBeatDiv5:
3785 case SnapToBeatDiv4:
3788 case SnapToBeatDiv3:
3791 case SnapToBeatDiv2:
3797 return _session->tempo_map().meter_at (position).beats_per_bar();
3802 case SnapToTimecodeFrame:
3803 case SnapToTimecodeSeconds:
3804 case SnapToTimecodeMinutes:
3807 case SnapToRegionStart:
3808 case SnapToRegionEnd:
3809 case SnapToRegionSync:
3810 case SnapToRegionBoundary:
3820 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3824 ret = nudge_clock.current_duration (pos);
3825 next = ret + 1; /* XXXX fix me */
3831 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3833 ArdourDialog dialog (_("Playlist Deletion"));
3834 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3835 "If it is kept, its audio files will not be cleaned.\n"
3836 "If it is deleted, audio files used by it alone will be cleaned."),
3839 dialog.set_position (WIN_POS_CENTER);
3840 dialog.get_vbox()->pack_start (label);
3844 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3845 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3846 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3848 switch (dialog.run ()) {
3849 case RESPONSE_ACCEPT:
3850 /* delete the playlist */
3854 case RESPONSE_REJECT:
3855 /* keep the playlist */
3867 Editor::audio_region_selection_covers (framepos_t where)
3869 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3870 if ((*a)->region()->covers (where)) {
3879 Editor::prepare_for_cleanup ()
3881 cut_buffer->clear_regions ();
3882 cut_buffer->clear_playlists ();
3884 selection->clear_regions ();
3885 selection->clear_playlists ();
3887 _regions->suspend_redisplay ();
3891 Editor::finish_cleanup ()
3893 _regions->resume_redisplay ();
3897 Editor::transport_loop_location()
3900 return _session->locations()->auto_loop_location();
3907 Editor::transport_punch_location()
3910 return _session->locations()->auto_punch_location();
3917 Editor::control_layout_scroll (GdkEventScroll* ev)
3919 if (Keyboard::some_magic_widget_has_focus()) {
3923 switch (ev->direction) {
3925 scroll_tracks_up_line ();
3929 case GDK_SCROLL_DOWN:
3930 scroll_tracks_down_line ();
3934 /* no left/right handling yet */
3942 Editor::session_state_saved (string)
3945 _snapshots->redisplay ();
3949 Editor::maximise_editing_space ()
3951 _mouse_mode_tearoff->set_visible (false);
3952 _tools_tearoff->set_visible (false);
3953 _zoom_tearoff->set_visible (false);
3955 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
3956 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
3957 pre_maximal_editor_width = this->get_width ();
3958 pre_maximal_editor_height = this->get_height ();
3960 if (post_maximal_horizontal_pane_position == 0) {
3961 post_maximal_horizontal_pane_position = edit_pane.get_width();
3964 if (post_maximal_vertical_pane_position == 0) {
3965 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
3970 if (post_maximal_editor_width) {
3971 edit_pane.set_position (post_maximal_horizontal_pane_position -
3972 abs(post_maximal_editor_width - pre_maximal_editor_width));
3974 edit_pane.set_position (post_maximal_horizontal_pane_position);
3977 if (post_maximal_editor_height) {
3978 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
3979 abs(post_maximal_editor_height - pre_maximal_editor_height));
3981 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
3984 if (Config->get_keep_tearoffs()) {
3985 _mouse_mode_tearoff->set_visible (true);
3986 _tools_tearoff->set_visible (true);
3987 if (Config->get_show_zoom_tools ()) {
3988 _zoom_tearoff->set_visible (true);
3995 Editor::restore_editing_space ()
3997 // user changed width/height of panes during fullscreen
3999 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
4000 post_maximal_horizontal_pane_position = edit_pane.get_position();
4003 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
4004 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
4009 _mouse_mode_tearoff->set_visible (true);
4010 _tools_tearoff->set_visible (true);
4011 if (Config->get_show_zoom_tools ()) {
4012 _zoom_tearoff->set_visible (true);
4014 post_maximal_editor_width = this->get_width();
4015 post_maximal_editor_height = this->get_height();
4017 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
4018 editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
4022 * Make new playlists for a given track and also any others that belong
4023 * to the same active route group with the `edit' property.
4028 Editor::new_playlists (TimeAxisView* v)
4030 begin_reversible_command (_("new playlists"));
4031 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4032 _session->playlists->get (playlists);
4033 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4034 commit_reversible_command ();
4038 * Use a copy of the current playlist for a given track and also any others that belong
4039 * to the same active route group with the `edit' property.
4044 Editor::copy_playlists (TimeAxisView* v)
4046 begin_reversible_command (_("copy playlists"));
4047 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4048 _session->playlists->get (playlists);
4049 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4050 commit_reversible_command ();
4053 /** Clear the current playlist for a given track and also any others that belong
4054 * to the same active route group with the `edit' property.
4059 Editor::clear_playlists (TimeAxisView* v)
4061 begin_reversible_command (_("clear playlists"));
4062 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4063 _session->playlists->get (playlists);
4064 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4065 commit_reversible_command ();
4069 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4071 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4075 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4077 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4081 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4083 atv.clear_playlist ();
4087 Editor::on_key_press_event (GdkEventKey* ev)
4089 return key_press_focus_accelerator_handler (*this, ev);
4093 Editor::on_key_release_event (GdkEventKey* ev)
4095 return Gtk::Window::on_key_release_event (ev);
4096 // return key_press_focus_accelerator_handler (*this, ev);
4099 /** Queue up a change to the viewport x origin.
4100 * @param frame New x origin.
4103 Editor::reset_x_origin (framepos_t frame)
4105 queue_visual_change (frame);
4109 Editor::reset_y_origin (double y)
4111 queue_visual_change_y (y);
4115 Editor::reset_zoom (double fpu)
4117 queue_visual_change (fpu);
4121 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4123 reset_x_origin (frame);
4126 if (!no_save_visual) {
4127 undo_visual_stack.push_back (current_visual_state(false));
4131 Editor::VisualState*
4132 Editor::current_visual_state (bool with_tracks)
4134 VisualState* vs = new VisualState;
4135 vs->y_position = vertical_adjustment.get_value();
4136 vs->frames_per_unit = frames_per_unit;
4137 vs->leftmost_frame = leftmost_frame;
4138 vs->zoom_focus = zoom_focus;
4141 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4142 vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
4150 Editor::undo_visual_state ()
4152 if (undo_visual_stack.empty()) {
4156 redo_visual_stack.push_back (current_visual_state());
4158 VisualState* vs = undo_visual_stack.back();
4159 undo_visual_stack.pop_back();
4160 use_visual_state (*vs);
4164 Editor::redo_visual_state ()
4166 if (redo_visual_stack.empty()) {
4170 undo_visual_stack.push_back (current_visual_state());
4172 VisualState* vs = redo_visual_stack.back();
4173 redo_visual_stack.pop_back();
4174 use_visual_state (*vs);
4178 Editor::swap_visual_state ()
4180 if (undo_visual_stack.empty()) {
4181 redo_visual_state ();
4183 undo_visual_state ();
4188 Editor::use_visual_state (VisualState& vs)
4190 no_save_visual = true;
4192 _routes->suspend_redisplay ();
4194 vertical_adjustment.set_value (vs.y_position);
4196 set_zoom_focus (vs.zoom_focus);
4197 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4199 for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
4200 TrackViewList::iterator t;
4202 /* check if the track still exists - it could have been deleted */
4204 if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
4205 (*t)->set_state (*(i->second), Stateful::loading_state_version);
4210 if (!vs.track_states.empty()) {
4211 _routes->update_visibility ();
4214 _routes->resume_redisplay ();
4216 no_save_visual = false;
4220 Editor::set_frames_per_unit (double fpu)
4222 /* this is the core function that controls the zoom level of the canvas. it is called
4223 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4226 if (fpu == frames_per_unit) {
4235 /* don't allow zooms that fit more than the maximum number
4236 of frames into an 800 pixel wide space.
4239 if (max_framepos / fpu < 800.0) {
4244 tempo_lines->tempo_map_changed();
4246 frames_per_unit = fpu;
4251 Editor::post_zoom ()
4253 // convert fpu to frame count
4255 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4257 if (frames_per_unit != zoom_range_clock.current_duration()) {
4258 zoom_range_clock.set (frames);
4261 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4262 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4263 (*i)->reshow_selection (selection->time);
4267 ZoomChanged (); /* EMIT_SIGNAL */
4269 //reset_scrolling_region ();
4271 if (playhead_cursor) {
4272 playhead_cursor->set_position (playhead_cursor->current_frame);
4275 refresh_location_display();
4276 _summary->set_overlays_dirty ();
4278 update_marker_labels ();
4284 Editor::queue_visual_change (framepos_t where)
4286 pending_visual_change.add (VisualChange::TimeOrigin);
4287 pending_visual_change.time_origin = where;
4288 ensure_visual_change_idle_handler ();
4292 Editor::queue_visual_change (double fpu)
4294 pending_visual_change.add (VisualChange::ZoomLevel);
4295 pending_visual_change.frames_per_unit = fpu;
4297 ensure_visual_change_idle_handler ();
4301 Editor::queue_visual_change_y (double y)
4303 pending_visual_change.add (VisualChange::YOrigin);
4304 pending_visual_change.y_origin = y;
4306 ensure_visual_change_idle_handler ();
4310 Editor::ensure_visual_change_idle_handler ()
4312 if (pending_visual_change.idle_handler_id < 0) {
4313 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4318 Editor::_idle_visual_changer (void* arg)
4320 return static_cast<Editor*>(arg)->idle_visual_changer ();
4324 Editor::idle_visual_changer ()
4326 VisualChange::Type p = pending_visual_change.pending;
4327 pending_visual_change.pending = (VisualChange::Type) 0;
4329 double const last_time_origin = horizontal_position ();
4331 if (p & VisualChange::TimeOrigin) {
4332 /* This is a bit of a hack, but set_frames_per_unit
4333 below will (if called) end up with the
4334 CrossfadeViews looking at Editor::leftmost_frame,
4335 and if we're changing origin and zoom in the same
4336 operation it will be the wrong value unless we
4340 leftmost_frame = pending_visual_change.time_origin;
4343 if (p & VisualChange::ZoomLevel) {
4344 set_frames_per_unit (pending_visual_change.frames_per_unit);
4346 compute_fixed_ruler_scale ();
4347 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4348 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4349 update_tempo_based_rulers ();
4351 if (p & VisualChange::TimeOrigin) {
4352 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4354 if (p & VisualChange::YOrigin) {
4355 vertical_adjustment.set_value (pending_visual_change.y_origin);
4358 if (last_time_origin == horizontal_position ()) {
4359 /* changed signal not emitted */
4360 update_fixed_rulers ();
4361 redisplay_tempo (true);
4364 _summary->set_overlays_dirty ();
4366 pending_visual_change.idle_handler_id = -1;
4367 return 0; /* this is always a one-shot call */
4370 struct EditorOrderTimeAxisSorter {
4371 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4372 return a->order () < b->order ();
4377 Editor::sort_track_selection (TrackViewList* sel)
4379 EditorOrderTimeAxisSorter cmp;
4384 selection->tracks.sort (cmp);
4389 Editor::get_preferred_edit_position (bool ignore_playhead)
4392 framepos_t where = 0;
4393 EditPoint ep = _edit_point;
4395 if (entered_marker) {
4396 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4397 return entered_marker->position();
4400 if (ignore_playhead && ep == EditAtPlayhead) {
4401 ep = EditAtSelectedMarker;
4405 case EditAtPlayhead:
4406 where = _session->audible_frame();
4407 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4410 case EditAtSelectedMarker:
4411 if (!selection->markers.empty()) {
4413 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4416 where = loc->start();
4420 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4428 if (!mouse_frame (where, ignored)) {
4429 /* XXX not right but what can we do ? */
4433 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4441 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4443 if (!_session) return;
4445 begin_reversible_command (cmd);
4449 if ((tll = transport_loop_location()) == 0) {
4450 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4451 XMLNode &before = _session->locations()->get_state();
4452 _session->locations()->add (loc, true);
4453 _session->set_auto_loop_location (loc);
4454 XMLNode &after = _session->locations()->get_state();
4455 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4457 XMLNode &before = tll->get_state();
4458 tll->set_hidden (false, this);
4459 tll->set (start, end);
4460 XMLNode &after = tll->get_state();
4461 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4464 commit_reversible_command ();
4468 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4470 if (!_session) return;
4472 begin_reversible_command (cmd);
4476 if ((tpl = transport_punch_location()) == 0) {
4477 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4478 XMLNode &before = _session->locations()->get_state();
4479 _session->locations()->add (loc, true);
4480 _session->set_auto_loop_location (loc);
4481 XMLNode &after = _session->locations()->get_state();
4482 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4485 XMLNode &before = tpl->get_state();
4486 tpl->set_hidden (false, this);
4487 tpl->set (start, end);
4488 XMLNode &after = tpl->get_state();
4489 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4492 commit_reversible_command ();
4495 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4496 * @param rs List to which found regions are added.
4497 * @param where Time to look at.
4498 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4501 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4503 const TrackViewList* tracks;
4506 tracks = &track_views;
4511 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4513 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4516 boost::shared_ptr<Track> tr;
4517 boost::shared_ptr<Playlist> pl;
4519 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4521 Playlist::RegionList* regions = pl->regions_at (
4522 (framepos_t) floor ( (double) where * tr->speed()));
4524 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4525 RegionView* rv = rtv->view()->find_view (*i);
4538 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4540 const TrackViewList* tracks;
4543 tracks = &track_views;
4548 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4549 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4551 boost::shared_ptr<Track> tr;
4552 boost::shared_ptr<Playlist> pl;
4554 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4556 Playlist::RegionList* regions = pl->regions_touched (
4557 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4559 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4561 RegionView* rv = rtv->view()->find_view (*i);
4574 /** Start with regions that are selected. Then add equivalent regions
4575 * on tracks in the same active edit-enabled route group as any of
4576 * the regions that we started with.
4580 Editor::get_regions_from_selection ()
4582 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4585 /** Get regions using the following method:
4587 * Make an initial region list using the selected regions, unless
4588 * the edit point is `mouse' and the mouse is over an unselected
4589 * region. In this case, start with just that region.
4591 * Then, make an initial track list of the tracks that these
4592 * regions are on, and if the edit point is not `mouse', add the
4595 * Look at this track list and add any other tracks that are on the
4596 * same active edit-enabled route group as one of the initial tracks.
4598 * Finally take the initial region list and add any regions that are
4599 * under the edit point on one of the tracks on the track list to get
4600 * the returned region list.
4602 * The rationale here is that the mouse edit point is special in that
4603 * its position describes both a time and a track; the other edit
4604 * modes only describe a time. Hence if the edit point is `mouse' we
4605 * ignore selected tracks, as we assume the user means something by
4606 * pointing at a particular track. Also in this case we take note of
4607 * the region directly under the edit point, as there is always just one
4608 * (rather than possibly several with non-mouse edit points).
4612 Editor::get_regions_from_selection_and_edit_point ()
4614 RegionSelection regions;
4616 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4617 regions.add (entered_regionview);
4619 regions = selection->regions;
4622 TrackViewList tracks;
4624 if (_edit_point != EditAtMouse) {
4625 tracks = selection->tracks;
4628 /* Add any other tracks that have regions that are in the same
4629 edit-activated route group as one of our regions.
4631 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4633 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4635 if (g && g->is_active() && g->is_edit()) {
4636 tracks.add (axis_views_from_routes (g->route_list()));
4640 if (!tracks.empty()) {
4641 /* now find regions that are at the edit position on those tracks */
4642 framepos_t const where = get_preferred_edit_position ();
4643 get_regions_at (regions, where, tracks);
4649 /** Start with regions that are selected, or the entered regionview if none are selected.
4650 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4651 * of the regions that we started with.
4655 Editor::get_regions_from_selection_and_entered ()
4657 RegionSelection regions = selection->regions;
4659 if (regions.empty() && entered_regionview) {
4660 regions.add (entered_regionview);
4663 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4667 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4669 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4671 RouteTimeAxisView* tatv;
4673 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4675 boost::shared_ptr<Playlist> pl;
4676 vector<boost::shared_ptr<Region> > results;
4678 boost::shared_ptr<Track> tr;
4680 if ((tr = tatv->track()) == 0) {
4685 if ((pl = (tr->playlist())) != 0) {
4686 pl->get_region_list_equivalent_regions (region, results);
4689 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4690 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4691 regions.push_back (marv);
4700 Editor::show_rhythm_ferret ()
4702 if (rhythm_ferret == 0) {
4703 rhythm_ferret = new RhythmFerret(*this);
4706 rhythm_ferret->set_session (_session);
4707 rhythm_ferret->show ();
4708 rhythm_ferret->present ();
4712 Editor::first_idle ()
4714 MessageDialog* dialog = 0;
4716 if (track_views.size() > 1) {
4717 dialog = new MessageDialog (*this,
4718 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4723 ARDOUR_UI::instance()->flush_pending ();
4726 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4730 // first idle adds route children (automation tracks), so we need to redisplay here
4731 _routes->redisplay ();
4739 Editor::_idle_resize (gpointer arg)
4741 return ((Editor*)arg)->idle_resize ();
4745 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4747 if (resize_idle_id < 0) {
4748 resize_idle_id = g_idle_add (_idle_resize, this);
4749 _pending_resize_amount = 0;
4752 /* make a note of the smallest resulting height, so that we can clamp the
4753 lower limit at TimeAxisView::hSmall */
4755 int32_t min_resulting = INT32_MAX;
4757 _pending_resize_amount += h;
4758 _pending_resize_view = view;
4760 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4762 if (selection->tracks.contains (_pending_resize_view)) {
4763 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4764 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4768 if (min_resulting < 0) {
4773 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4774 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4778 /** Handle pending resizing of tracks */
4780 Editor::idle_resize ()
4782 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4784 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4785 selection->tracks.contains (_pending_resize_view)) {
4787 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4788 if (*i != _pending_resize_view) {
4789 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4794 _pending_resize_amount = 0;
4796 _group_tabs->set_dirty ();
4797 resize_idle_id = -1;
4805 ENSURE_GUI_THREAD (*this, &Editor::located);
4807 playhead_cursor->set_position (_session->audible_frame ());
4808 if (_follow_playhead && !_pending_initial_locate) {
4809 reset_x_origin_to_follow_playhead ();
4812 _pending_locate_request = false;
4813 _pending_initial_locate = false;
4817 Editor::region_view_added (RegionView *)
4819 _summary->set_dirty ();
4823 Editor::region_view_removed ()
4825 _summary->set_dirty ();
4829 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4831 TrackViewList::const_iterator j = track_views.begin ();
4832 while (j != track_views.end()) {
4833 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4834 if (rtv && rtv->route() == r) {
4845 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4849 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4850 TimeAxisView* tv = axis_view_from_route (*i);
4861 Editor::handle_new_route (RouteList& routes)
4863 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4865 RouteTimeAxisView *rtv;
4866 list<RouteTimeAxisView*> new_views;
4868 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4869 boost::shared_ptr<Route> route = (*x);
4871 if (route->is_hidden() || route->is_monitor()) {
4875 DataType dt = route->input()->default_type();
4877 if (dt == ARDOUR::DataType::AUDIO) {
4878 rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas);
4879 } else if (dt == ARDOUR::DataType::MIDI) {
4880 rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas);
4882 throw unknown_type();
4885 new_views.push_back (rtv);
4886 track_views.push_back (rtv);
4888 rtv->effective_gain_display ();
4890 if (internal_editing()) {
4891 rtv->enter_internal_edit_mode ();
4893 rtv->leave_internal_edit_mode ();
4896 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4897 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4900 _routes->routes_added (new_views);
4901 _summary->routes_added (new_views);
4903 if (show_editor_mixer_when_tracks_arrive) {
4904 show_editor_mixer (true);
4907 editor_list_button.set_sensitive (true);
4911 Editor::timeaxisview_deleted (TimeAxisView *tv)
4913 if (_session && _session->deletion_in_progress()) {
4914 /* the situation is under control */
4918 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4920 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4922 _routes->route_removed (tv);
4924 if (tv == entered_track) {
4928 TimeAxisView::Children c = tv->get_child_list ();
4929 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4930 if (entered_track == i->get()) {
4935 /* remove it from the list of track views */
4937 TrackViewList::iterator i;
4939 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4940 i = track_views.erase (i);
4943 /* update whatever the current mixer strip is displaying, if revelant */
4945 boost::shared_ptr<Route> route;
4948 route = rtav->route ();
4951 if (current_mixer_strip && current_mixer_strip->route() == route) {
4953 TimeAxisView* next_tv;
4955 if (track_views.empty()) {
4957 } else if (i == track_views.end()) {
4958 next_tv = track_views.front();
4965 set_selected_mixer_strip (*next_tv);
4967 /* make the editor mixer strip go away setting the
4968 * button to inactive (which also unticks the menu option)
4971 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4977 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4979 if (apply_to_selection) {
4980 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4982 TrackSelection::iterator j = i;
4985 hide_track_in_display (*i, false);
4990 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4992 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4993 // this will hide the mixer strip
4994 set_selected_mixer_strip (*tv);
4997 _routes->hide_track_in_display (*tv);
5002 Editor::sync_track_view_list_and_routes ()
5004 track_views = TrackViewList (_routes->views ());
5006 _summary->set_dirty ();
5007 _group_tabs->set_dirty ();
5009 return false; // do not call again (until needed)
5013 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5015 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5020 /** Find a RouteTimeAxisView by the ID of its route */
5022 Editor::get_route_view_by_route_id (PBD::ID& id) const
5024 RouteTimeAxisView* v;
5026 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5027 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5028 if(v->route()->id() == id) {
5038 Editor::fit_route_group (RouteGroup *g)
5040 TrackViewList ts = axis_views_from_routes (g->route_list ());
5045 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5047 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5050 _session->cancel_audition ();
5054 if (_session->is_auditioning()) {
5055 _session->cancel_audition ();
5056 if (r == last_audition_region) {
5061 _session->audition_region (r);
5062 last_audition_region = r;
5067 Editor::hide_a_region (boost::shared_ptr<Region> r)
5069 r->set_hidden (true);
5073 Editor::show_a_region (boost::shared_ptr<Region> r)
5075 r->set_hidden (false);
5079 Editor::audition_region_from_region_list ()
5081 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5085 Editor::hide_region_from_region_list ()
5087 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5091 Editor::show_region_in_region_list ()
5093 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5097 Editor::step_edit_status_change (bool yn)
5100 start_step_editing ();
5102 stop_step_editing ();
5107 Editor::start_step_editing ()
5109 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5113 Editor::stop_step_editing ()
5115 step_edit_connection.disconnect ();
5119 Editor::check_step_edit ()
5121 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5122 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5124 mtv->check_step_edit ();
5128 return true; // do it again, till we stop
5132 Editor::scroll_press (Direction dir)
5134 ++_scroll_callbacks;
5136 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5137 /* delay the first auto-repeat */
5143 scroll_backward (1);
5151 scroll_tracks_up_line ();
5155 scroll_tracks_down_line ();
5159 /* do hacky auto-repeat */
5160 if (!_scroll_connection.connected ()) {
5162 _scroll_connection = Glib::signal_timeout().connect (
5163 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5166 _scroll_callbacks = 0;
5173 Editor::scroll_release ()
5175 _scroll_connection.disconnect ();
5178 /** Queue a change for the Editor viewport x origin to follow the playhead */
5180 Editor::reset_x_origin_to_follow_playhead ()
5182 framepos_t const frame = playhead_cursor->current_frame;
5184 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5186 if (_session->transport_speed() < 0) {
5188 if (frame > (current_page_frames() / 2)) {
5189 center_screen (frame-(current_page_frames()/2));
5191 center_screen (current_page_frames()/2);
5196 if (frame < leftmost_frame) {
5199 if (_session->transport_rolling()) {
5200 /* rolling; end up with the playhead at the right of the page */
5201 l = frame - current_page_frames ();
5203 /* not rolling: end up with the playhead 3/4 of the way along the page */
5204 l = frame - (3 * current_page_frames() / 4);
5211 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5214 if (_session->transport_rolling()) {
5215 /* rolling: end up with the playhead on the left of the page */
5216 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5218 /* not rolling: end up with the playhead 1/4 of the way along the page */
5219 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5227 Editor::super_rapid_screen_update ()
5229 if (!_session || !_session->engine().running()) {
5233 /* METERING / MIXER STRIPS */
5235 /* update track meters, if required */
5236 if (is_mapped() && meters_running) {
5237 RouteTimeAxisView* rtv;
5238 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5239 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5240 rtv->fast_update ();
5245 /* and any current mixer strip */
5246 if (current_mixer_strip) {
5247 current_mixer_strip->fast_update ();
5250 /* PLAYHEAD AND VIEWPORT */
5252 framepos_t const frame = _session->audible_frame();
5254 /* There are a few reasons why we might not update the playhead / viewport stuff:
5256 * 1. we don't update things when there's a pending locate request, otherwise
5257 * when the editor requests a locate there is a chance that this method
5258 * will move the playhead before the locate request is processed, causing
5260 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5261 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5264 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5266 last_update_frame = frame;
5268 if (!_dragging_playhead) {
5269 playhead_cursor->set_position (frame);
5272 if (!_stationary_playhead) {
5274 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5275 reset_x_origin_to_follow_playhead ();
5280 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5284 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5285 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5286 if (target <= 0.0) {
5289 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5290 target = (target * 0.15) + (current * 0.85);
5296 set_horizontal_position (current);
5305 Editor::session_going_away ()
5307 _have_idled = false;
5309 _session_connections.drop_connections ();
5311 super_rapid_screen_update_connection.disconnect ();
5313 selection->clear ();
5314 cut_buffer->clear ();
5316 clicked_regionview = 0;
5317 clicked_axisview = 0;
5318 clicked_routeview = 0;
5319 clicked_crossfadeview = 0;
5320 entered_regionview = 0;
5322 last_update_frame = 0;
5325 playhead_cursor->canvas_item.hide ();
5327 /* rip everything out of the list displays */
5331 _route_groups->clear ();
5333 /* do this first so that deleting a track doesn't reset cms to null
5334 and thus cause a leak.
5337 if (current_mixer_strip) {
5338 if (current_mixer_strip->get_parent() != 0) {
5339 global_hpacker.remove (*current_mixer_strip);
5341 delete current_mixer_strip;
5342 current_mixer_strip = 0;
5345 /* delete all trackviews */
5347 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5350 track_views.clear ();
5352 zoom_range_clock.set_session (0);
5353 nudge_clock.set_session (0);
5355 editor_list_button.set_active(false);
5356 editor_list_button.set_sensitive(false);
5358 /* clear tempo/meter rulers */
5359 remove_metric_marks ();
5361 clear_marker_display ();
5363 delete current_bbt_points;
5364 current_bbt_points = 0;
5366 /* get rid of any existing editor mixer strip */
5368 WindowTitle title(Glib::get_application_name());
5369 title += _("Editor");
5371 set_title (title.get_string());
5373 SessionHandlePtr::session_going_away ();
5378 Editor::show_editor_list (bool yn)
5381 _the_notebook.show ();
5383 _the_notebook.hide ();
5388 Editor::change_region_layering_order ()
5390 framepos_t const position = get_preferred_edit_position ();
5392 if (!clicked_routeview) {
5393 if (layering_order_editor) {
5394 layering_order_editor->hide ();
5399 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5405 boost::shared_ptr<Playlist> pl = track->playlist();
5411 if (layering_order_editor == 0) {
5412 layering_order_editor = new RegionLayeringOrderEditor(*this);
5415 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5416 layering_order_editor->maybe_present ();
5420 Editor::update_region_layering_order_editor ()
5422 if (layering_order_editor && layering_order_editor->is_visible ()) {
5423 change_region_layering_order ();
5428 Editor::setup_fade_images ()
5430 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5431 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5432 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5433 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5434 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5436 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5437 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5438 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5439 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5440 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5444 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5446 Editor::action_menu_item (std::string const & name)
5448 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5451 return *manage (a->create_menu_item ());
5455 Editor::resize_text_widgets ()
5457 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_FUDGE+10, 15);
5458 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_FUDGE+10, 15);
5459 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_FUDGE+10, 15);
5460 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_FUDGE+10, 15);
5461 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_FUDGE+10, 15);
5465 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5467 EventBox* b = manage (new EventBox);
5468 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5469 Label* l = manage (new Label (name));
5473 _the_notebook.append_page (widget, *b);
5477 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5479 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5480 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5483 if (ev->type == GDK_2BUTTON_PRESS) {
5485 /* double-click on a notebook tab shrinks or expands the notebook */
5487 if (_notebook_shrunk) {
5488 edit_pane.set_position (pre_maximal_horizontal_pane_position);
5489 _notebook_shrunk = false;
5491 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
5492 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5493 _notebook_shrunk = true;