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 verbose_cursor_on = true;
335 last_item_entered = 0;
337 have_pending_keyboard_selection = false;
338 _follow_playhead = true;
339 _stationary_playhead = false;
340 _xfade_visibility = true;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
369 no_save_visual = false;
372 scrubbing_direction = 0;
376 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
377 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
378 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
379 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
380 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
382 _edit_point = EditAtMouse;
383 _internal_editing = false;
384 current_canvas_cursor = 0;
386 frames_per_unit = 2048; /* too early to use reset_zoom () */
388 _scroll_callbacks = 0;
390 zoom_focus = ZoomFocusLeft;
391 set_zoom_focus (ZoomFocusLeft);
392 zoom_range_clock.ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
394 bbt_label.set_name ("EditorTimeButton");
395 bbt_label.set_size_request (-1, (int)timebar_height);
396 bbt_label.set_alignment (1.0, 0.5);
397 bbt_label.set_padding (5,0);
399 bbt_label.set_no_show_all();
400 minsec_label.set_name ("EditorTimeButton");
401 minsec_label.set_size_request (-1, (int)timebar_height);
402 minsec_label.set_alignment (1.0, 0.5);
403 minsec_label.set_padding (5,0);
404 minsec_label.hide ();
405 minsec_label.set_no_show_all();
406 timecode_label.set_name ("EditorTimeButton");
407 timecode_label.set_size_request (-1, (int)timebar_height);
408 timecode_label.set_alignment (1.0, 0.5);
409 timecode_label.set_padding (5,0);
410 timecode_label.hide ();
411 timecode_label.set_no_show_all();
412 samples_label.set_name ("EditorTimeButton");
413 samples_label.set_size_request (-1, (int)timebar_height);
414 samples_label.set_alignment (1.0, 0.5);
415 samples_label.set_padding (5,0);
416 samples_label.hide ();
417 samples_label.set_no_show_all();
419 tempo_label.set_name ("EditorTimeButton");
420 tempo_label.set_size_request (-1, (int)timebar_height);
421 tempo_label.set_alignment (1.0, 0.5);
422 tempo_label.set_padding (5,0);
424 tempo_label.set_no_show_all();
426 meter_label.set_name ("EditorTimeButton");
427 meter_label.set_size_request (-1, (int)timebar_height);
428 meter_label.set_alignment (1.0, 0.5);
429 meter_label.set_padding (5,0);
431 meter_label.set_no_show_all();
433 mark_label.set_name ("EditorTimeButton");
434 mark_label.set_size_request (-1, (int)timebar_height);
435 mark_label.set_alignment (1.0, 0.5);
436 mark_label.set_padding (5,0);
438 mark_label.set_no_show_all();
440 cd_mark_label.set_name ("EditorTimeButton");
441 cd_mark_label.set_size_request (-1, (int)timebar_height);
442 cd_mark_label.set_alignment (1.0, 0.5);
443 cd_mark_label.set_padding (5,0);
444 cd_mark_label.hide();
445 cd_mark_label.set_no_show_all();
447 range_mark_label.set_name ("EditorTimeButton");
448 range_mark_label.set_size_request (-1, (int)timebar_height);
449 range_mark_label.set_alignment (1.0, 0.5);
450 range_mark_label.set_padding (5,0);
451 range_mark_label.hide();
452 range_mark_label.set_no_show_all();
454 transport_mark_label.set_name ("EditorTimeButton");
455 transport_mark_label.set_size_request (-1, (int)timebar_height);
456 transport_mark_label.set_alignment (1.0, 0.5);
457 transport_mark_label.set_padding (5,0);
458 transport_mark_label.hide();
459 transport_mark_label.set_no_show_all();
461 initialize_rulers ();
462 initialize_canvas ();
464 _summary = new EditorSummary (this);
466 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
467 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
469 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
471 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
472 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
474 edit_controls_vbox.set_spacing (0);
475 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
476 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
478 HBox* h = manage (new HBox);
479 _group_tabs = new EditorGroupTabs (this);
480 h->pack_start (*_group_tabs, PACK_SHRINK);
481 h->pack_start (edit_controls_vbox);
482 controls_layout.add (*h);
484 controls_layout.set_name ("EditControlsBase");
485 controls_layout.add_events (Gdk::SCROLL_MASK);
486 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
488 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
489 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
491 _cursors = new MouseCursors;
493 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
494 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
495 0.0, 1.0, 100.0, 1.0));
497 pad_line_1->property_color_rgba() = 0xFF0000FF;
502 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
503 time_canvas_vbox.set_size_request (-1, -1);
505 ruler_label_event_box.add (ruler_label_vbox);
506 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
507 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
509 time_button_event_box.add (time_button_vbox);
510 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
511 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
513 /* these enable us to have a dedicated window (for cursor setting, etc.)
514 for the canvas areas.
517 track_canvas_event_box.add (*track_canvas);
519 time_canvas_event_box.add (time_canvas_vbox);
520 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
522 edit_packer.set_col_spacings (0);
523 edit_packer.set_row_spacings (0);
524 edit_packer.set_homogeneous (false);
525 edit_packer.set_border_width (0);
526 edit_packer.set_name ("EditorWindow");
528 /* labels for the rulers */
529 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
530 /* labels for the marker "tracks" */
531 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
533 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
535 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
537 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
539 bottom_hbox.set_border_width (2);
540 bottom_hbox.set_spacing (3);
542 _route_groups = new EditorRouteGroups (this);
543 _routes = new EditorRoutes (this);
544 _regions = new EditorRegions (this);
545 _snapshots = new EditorSnapshots (this);
546 _locations = new EditorLocations (this);
548 add_notebook_page (_("Regions"), _regions->widget ());
549 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
550 add_notebook_page (_("Snapshots"), _snapshots->widget ());
551 add_notebook_page (_("Route Groups"), _route_groups->widget ());
552 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
554 _the_notebook.set_show_tabs (true);
555 _the_notebook.set_scrollable (true);
556 _the_notebook.popup_disable ();
557 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
558 _the_notebook.show_all ();
560 post_maximal_editor_width = 0;
561 post_maximal_horizontal_pane_position = 0;
562 post_maximal_editor_height = 0;
563 post_maximal_vertical_pane_position = 0;
564 _notebook_shrunk = false;
566 editor_summary_pane.pack1(edit_packer);
568 Button* summary_arrows_left_left = manage (new Button);
569 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
570 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
571 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
573 Button* summary_arrows_left_right = manage (new Button);
574 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
575 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
576 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 VBox* summary_arrows_left = manage (new VBox);
579 summary_arrows_left->pack_start (*summary_arrows_left_left);
580 summary_arrows_left->pack_start (*summary_arrows_left_right);
582 Button* summary_arrows_right_up = manage (new Button);
583 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
584 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
585 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
587 Button* summary_arrows_right_down = manage (new Button);
588 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
589 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
590 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
592 VBox* summary_arrows_right = manage (new VBox);
593 summary_arrows_right->pack_start (*summary_arrows_right_up);
594 summary_arrows_right->pack_start (*summary_arrows_right_down);
596 Frame* summary_frame = manage (new Frame);
597 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
599 summary_frame->add (*_summary);
600 summary_frame->show ();
602 _summary_hbox.pack_start (*summary_arrows_left, false, false);
603 _summary_hbox.pack_start (*summary_frame, true, true);
604 _summary_hbox.pack_start (*summary_arrows_right, false, false);
606 editor_summary_pane.pack2 (_summary_hbox);
608 edit_pane.pack1 (editor_summary_pane, true, true);
609 edit_pane.pack2 (_the_notebook, false, true);
611 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
613 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
615 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
617 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
618 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
620 top_hbox.pack_start (toolbar_frame);
622 HBox *hbox = manage (new HBox);
623 hbox->pack_start (edit_pane, true, true);
625 global_vpacker.pack_start (top_hbox, false, false);
626 global_vpacker.pack_start (*hbox, true, true);
628 global_hpacker.pack_start (global_vpacker, true, true);
630 set_name ("EditorWindow");
631 add_accel_group (ActionManager::ui_manager->get_accel_group());
633 status_bar_hpacker.show ();
635 vpacker.pack_end (status_bar_hpacker, false, false);
636 vpacker.pack_end (global_hpacker, true, true);
638 /* register actions now so that set_state() can find them and set toggles/checks etc */
643 setup_midi_toolbar ();
645 _snap_type = SnapToBeat;
646 set_snap_to (_snap_type);
647 _snap_mode = SnapOff;
648 set_snap_mode (_snap_mode);
649 set_mouse_mode (MouseObject, true);
650 pre_internal_mouse_mode = MouseObject;
651 set_edit_point_preference (EditAtMouse, true);
653 _playlist_selector = new PlaylistSelector();
654 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
656 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
660 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
661 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
663 nudge_forward_button.set_name ("TransportButton");
664 nudge_backward_button.set_name ("TransportButton");
666 fade_context_menu.set_name ("ArdourContextMenu");
668 /* icons, titles, WM stuff */
670 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
671 Glib::RefPtr<Gdk::Pixbuf> icon;
673 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
683 window_icons.push_back (icon);
685 if (!window_icons.empty()) {
686 // set_icon_list (window_icons);
687 set_default_icon_list (window_icons);
690 WindowTitle title(Glib::get_application_name());
691 title += _("Editor");
692 set_title (title.get_string());
693 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
696 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
698 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
699 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
701 /* allow external control surfaces/protocols to do various things */
703 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
704 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
705 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
706 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
707 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
709 /* problematic: has to return a value and thus cannot be x-thread */
711 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
713 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
715 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
717 _ignore_region_action = false;
718 _last_region_menu_was_main = false;
719 _popup_region_menu_item = 0;
721 _show_marker_lines = false;
722 _over_region_trim_target = false;
724 /* Button bindings */
726 button_bindings = new Bindings;
728 XMLNode* node = button_settings();
730 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
731 button_bindings->load (**i);
738 setup_fade_images ();
744 if(image_socket_listener) {
745 if(image_socket_listener->is_connected())
747 image_socket_listener->close_connection() ;
750 delete image_socket_listener ;
751 image_socket_listener = 0 ;
755 delete button_bindings;
757 delete _route_groups;
763 Editor::button_settings () const
765 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
766 XMLNode* node = find_named_node (*settings, X_("Buttons"));
769 cerr << "new empty Button node\n";
770 node = new XMLNode (X_("Buttons"));
777 Editor::add_toplevel_controls (Container& cont)
779 vpacker.pack_start (cont, false, false);
784 Editor::catch_vanishing_regionview (RegionView *rv)
786 /* note: the selection will take care of the vanishing
787 audioregionview by itself.
790 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
794 if (clicked_regionview == rv) {
795 clicked_regionview = 0;
798 if (entered_regionview == rv) {
799 set_entered_regionview (0);
802 if (!_all_region_actions_sensitized) {
803 sensitize_all_region_actions (true);
806 _over_region_trim_target = false;
810 Editor::set_entered_regionview (RegionView* rv)
812 if (rv == entered_regionview) {
816 if (entered_regionview) {
817 entered_regionview->exited ();
820 if ((entered_regionview = rv) != 0) {
821 entered_regionview->entered (internal_editing ());
824 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
825 /* This RegionView entry might have changed what region actions
826 are allowed, so sensitize them all in case a key is pressed.
828 sensitize_all_region_actions (true);
833 Editor::set_entered_track (TimeAxisView* tav)
836 entered_track->exited ();
839 if ((entered_track = tav) != 0) {
840 entered_track->entered ();
845 Editor::show_window ()
847 if (!is_visible ()) {
850 /* XXX: this is a bit unfortunate; it would probably
851 be nicer if we could just call show () above rather
852 than needing the show_all ()
855 /* re-hide stuff if necessary */
856 editor_list_button_toggled ();
857 parameter_changed ("show-summary");
858 parameter_changed ("show-group-tabs");
859 parameter_changed ("show-zoom-tools");
861 /* now reset all audio_time_axis heights, because widgets might need
867 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
868 tv = (static_cast<TimeAxisView*>(*i));
872 if (current_mixer_strip) {
873 current_mixer_strip->hide_things ();
881 Editor::instant_save ()
883 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
888 _session->add_instant_xml(get_state());
890 Config->add_instant_xml(get_state());
895 Editor::zoom_adjustment_changed ()
901 double fpu = zoom_range_clock.current_duration() / _canvas_width;
905 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
906 } else if (fpu > _session->current_end_frame() / _canvas_width) {
907 fpu = _session->current_end_frame() / _canvas_width;
908 zoom_range_clock.set ((framepos_t) floor (fpu * _canvas_width));
915 Editor::control_scroll (float fraction)
917 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
923 double step = fraction * current_page_frames();
926 _control_scroll_target is an optional<T>
928 it acts like a pointer to an framepos_t, with
929 a operator conversion to boolean to check
930 that it has a value could possibly use
931 playhead_cursor->current_frame to store the
932 value and a boolean in the class to know
933 when it's out of date
936 if (!_control_scroll_target) {
937 _control_scroll_target = _session->transport_frame();
938 _dragging_playhead = true;
941 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
942 *_control_scroll_target = 0;
943 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
944 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
946 *_control_scroll_target += (framepos_t) floor (step);
949 /* move visuals, we'll catch up with it later */
951 playhead_cursor->set_position (*_control_scroll_target);
952 UpdateAllTransportClocks (*_control_scroll_target);
954 if (*_control_scroll_target > (current_page_frames() / 2)) {
955 /* try to center PH in window */
956 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
962 Now we do a timeout to actually bring the session to the right place
963 according to the playhead. This is to avoid reading disk buffers on every
964 call to control_scroll, which is driven by ScrollTimeline and therefore
965 probably by a control surface wheel which can generate lots of events.
967 /* cancel the existing timeout */
969 control_scroll_connection.disconnect ();
971 /* add the next timeout */
973 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
977 Editor::deferred_control_scroll (framepos_t /*target*/)
979 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
980 // reset for next stream
981 _control_scroll_target = boost::none;
982 _dragging_playhead = false;
987 Editor::access_action (std::string action_group, std::string action_item)
993 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
996 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1004 Editor::on_realize ()
1006 Window::on_realize ();
1011 Editor::map_position_change (framepos_t frame)
1013 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1015 if (_session == 0) {
1019 if (_follow_playhead) {
1020 center_screen (frame);
1023 playhead_cursor->set_position (frame);
1027 Editor::center_screen (framepos_t frame)
1029 double page = _canvas_width * frames_per_unit;
1031 /* if we're off the page, then scroll.
1034 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1035 center_screen_internal (frame, page);
1040 Editor::center_screen_internal (framepos_t frame, float page)
1045 frame -= (framepos_t) page;
1050 reset_x_origin (frame);
1055 Editor::update_title ()
1057 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1060 bool dirty = _session->dirty();
1062 string session_name;
1064 if (_session->snap_name() != _session->name()) {
1065 session_name = _session->snap_name();
1067 session_name = _session->name();
1071 session_name = "*" + session_name;
1074 WindowTitle title(session_name);
1075 title += Glib::get_application_name();
1076 set_title (title.get_string());
1081 Editor::set_session (Session *t)
1083 SessionHandlePtr::set_session (t);
1089 zoom_range_clock.set_session (_session);
1090 _playlist_selector->set_session (_session);
1091 nudge_clock.set_session (_session);
1092 _summary->set_session (_session);
1093 _group_tabs->set_session (_session);
1094 _route_groups->set_session (_session);
1095 _regions->set_session (_session);
1096 _snapshots->set_session (_session);
1097 _routes->set_session (_session);
1098 _locations->set_session (_session);
1100 if (rhythm_ferret) {
1101 rhythm_ferret->set_session (_session);
1104 if (analysis_window) {
1105 analysis_window->set_session (_session);
1109 sfbrowser->set_session (_session);
1112 compute_fixed_ruler_scale ();
1114 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1115 set_state (*node, Stateful::loading_state_version);
1117 /* catch up with the playhead */
1119 _session->request_locate (playhead_cursor->current_frame);
1120 _pending_initial_locate = true;
1124 /* These signals can all be emitted by a non-GUI thread. Therefore the
1125 handlers for them must not attempt to directly interact with the GUI,
1126 but use Gtkmm2ext::UI::instance()->call_slot();
1129 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1130 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1131 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1132 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1133 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1134 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1135 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1136 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1137 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1138 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1139 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1140 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1141 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display_s, this, _1), gui_context());
1142 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1144 if (Profile->get_sae()) {
1145 Timecode::BBT_Time bbt;
1149 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1150 nudge_clock.set_mode(AudioClock::BBT);
1151 nudge_clock.set (pos, true, 0, AudioClock::BBT);
1154 nudge_clock.set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1157 playhead_cursor->canvas_item.show ();
1159 Location* loc = _session->locations()->auto_loop_location();
1161 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1163 if (loc->start() == loc->end()) {
1164 loc->set_end (loc->start() + 1);
1167 _session->locations()->add (loc, false);
1168 _session->set_auto_loop_location (loc);
1171 loc->set_name (_("Loop"));
1174 loc = _session->locations()->auto_punch_location();
1177 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1179 if (loc->start() == loc->end()) {
1180 loc->set_end (loc->start() + 1);
1183 _session->locations()->add (loc, false);
1184 _session->set_auto_punch_location (loc);
1187 loc->set_name (_("Punch"));
1190 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1191 Config->map_parameters (pc);
1192 _session->config.map_parameters (pc);
1194 refresh_location_display ();
1196 restore_ruler_visibility ();
1197 //tempo_map_changed (PropertyChange (0));
1198 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1200 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1201 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1204 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1205 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1208 switch (_snap_type) {
1209 case SnapToRegionStart:
1210 case SnapToRegionEnd:
1211 case SnapToRegionSync:
1212 case SnapToRegionBoundary:
1213 build_region_boundary_cache ();
1220 /* register for undo history */
1221 _session->register_with_memento_command_factory(_id, this);
1223 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1225 start_updating_meters ();
1229 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1231 if (a->get_name() == "RegionMenu") {
1232 /* When the main menu's region menu is opened, we setup the actions so that they look right
1233 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1234 so we resensitize all region actions when the entered regionview or the region selection
1235 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1236 happens after the region context menu is opened. So we set a flag here, too.
1240 sensitize_the_right_region_actions ();
1241 _last_region_menu_was_main = true;
1245 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1247 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1249 using namespace Menu_Helpers;
1250 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1253 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1257 MenuList& items (fade_context_menu.items());
1261 switch (item_type) {
1263 case FadeInHandleItem:
1264 if (arv->audio_region()->fade_in_active()) {
1265 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1267 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1270 items.push_back (SeparatorElem());
1272 if (Profile->get_sae()) {
1274 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1275 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1282 *_fade_in_images[FadeLinear],
1283 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1287 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1292 *_fade_in_images[FadeFast],
1293 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1296 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1301 *_fade_in_images[FadeLogB],
1302 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1305 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1310 *_fade_in_images[FadeLogA],
1311 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1314 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1319 *_fade_in_images[FadeSlow],
1320 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1323 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1329 case FadeOutHandleItem:
1330 if (arv->audio_region()->fade_out_active()) {
1331 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1333 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1336 items.push_back (SeparatorElem());
1338 if (Profile->get_sae()) {
1339 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1340 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1346 *_fade_out_images[FadeLinear],
1347 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1351 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1356 *_fade_out_images[FadeFast],
1357 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1360 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1365 *_fade_out_images[FadeLogB],
1366 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1369 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1374 *_fade_out_images[FadeLogA],
1375 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1378 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1383 *_fade_out_images[FadeSlow],
1384 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1387 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1393 fatal << _("programming error: ")
1394 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1399 fade_context_menu.popup (button, time);
1403 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1405 using namespace Menu_Helpers;
1406 Menu* (Editor::*build_menu_function)();
1409 switch (item_type) {
1411 case RegionViewName:
1412 case RegionViewNameHighlight:
1413 case LeftFrameHandle:
1414 case RightFrameHandle:
1415 if (with_selection) {
1416 build_menu_function = &Editor::build_track_selection_context_menu;
1418 build_menu_function = &Editor::build_track_region_context_menu;
1423 if (with_selection) {
1424 build_menu_function = &Editor::build_track_selection_context_menu;
1426 build_menu_function = &Editor::build_track_context_menu;
1430 case CrossfadeViewItem:
1431 build_menu_function = &Editor::build_track_crossfade_context_menu;
1435 if (clicked_routeview->track()) {
1436 build_menu_function = &Editor::build_track_context_menu;
1438 build_menu_function = &Editor::build_track_bus_context_menu;
1443 /* probably shouldn't happen but if it does, we don't care */
1447 menu = (this->*build_menu_function)();
1448 menu->set_name ("ArdourContextMenu");
1450 /* now handle specific situations */
1452 switch (item_type) {
1454 case RegionViewName:
1455 case RegionViewNameHighlight:
1456 case LeftFrameHandle:
1457 case RightFrameHandle:
1458 if (!with_selection) {
1459 if (region_edit_menu_split_item) {
1460 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1461 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1463 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1466 if (region_edit_menu_split_multichannel_item) {
1467 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1468 region_edit_menu_split_multichannel_item->set_sensitive (true);
1470 region_edit_menu_split_multichannel_item->set_sensitive (false);
1479 case CrossfadeViewItem:
1486 /* probably shouldn't happen but if it does, we don't care */
1490 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1492 /* Bounce to disk */
1494 using namespace Menu_Helpers;
1495 MenuList& edit_items = menu->items();
1497 edit_items.push_back (SeparatorElem());
1499 switch (clicked_routeview->audio_track()->freeze_state()) {
1500 case AudioTrack::NoFreeze:
1501 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1504 case AudioTrack::Frozen:
1505 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1508 case AudioTrack::UnFrozen:
1509 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1515 if (item_type == StreamItem && clicked_routeview) {
1516 clicked_routeview->build_underlay_menu(menu);
1519 /* When the region menu is opened, we setup the actions so that they look right
1522 sensitize_the_right_region_actions ();
1523 _last_region_menu_was_main = false;
1525 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1526 menu->popup (button, time);
1530 Editor::build_track_context_menu ()
1532 using namespace Menu_Helpers;
1534 MenuList& edit_items = track_context_menu.items();
1537 add_dstream_context_items (edit_items);
1538 return &track_context_menu;
1542 Editor::build_track_bus_context_menu ()
1544 using namespace Menu_Helpers;
1546 MenuList& edit_items = track_context_menu.items();
1549 add_bus_context_items (edit_items);
1550 return &track_context_menu;
1554 Editor::build_track_region_context_menu ()
1556 using namespace Menu_Helpers;
1557 MenuList& edit_items = track_region_context_menu.items();
1560 /* we've just cleared the track region context menu, so the menu that these
1561 two items were on will have disappeared; stop them dangling.
1563 region_edit_menu_split_item = 0;
1564 region_edit_menu_split_multichannel_item = 0;
1566 /* we might try to use items that are currently attached to a crossfade menu,
1569 track_crossfade_context_menu.items().clear ();
1571 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1574 boost::shared_ptr<Track> tr;
1575 boost::shared_ptr<Playlist> pl;
1577 if ((tr = rtv->track())) {
1578 add_region_context_items (edit_items, tr);
1582 add_dstream_context_items (edit_items);
1584 return &track_region_context_menu;
1588 Editor::build_track_crossfade_context_menu ()
1590 using namespace Menu_Helpers;
1591 MenuList& edit_items = track_crossfade_context_menu.items();
1592 edit_items.clear ();
1594 /* we might try to use items that are currently attached to a crossfade menu,
1597 track_region_context_menu.items().clear ();
1599 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1602 boost::shared_ptr<Track> tr;
1603 boost::shared_ptr<Playlist> pl;
1604 boost::shared_ptr<AudioPlaylist> apl;
1606 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1608 AudioPlaylist::Crossfades xfades;
1612 /* The xfade menu is a bit of a special case, as we always use the mouse position
1613 to decide whether or not to display it (rather than the edit point). No particularly
1614 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1617 mouse_frame (where, ignored);
1618 apl->crossfades_at (where, xfades);
1620 bool const many = xfades.size() > 1;
1622 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1623 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1626 add_region_context_items (edit_items, tr);
1630 add_dstream_context_items (edit_items);
1632 return &track_crossfade_context_menu;
1636 Editor::analyze_region_selection ()
1638 if (analysis_window == 0) {
1639 analysis_window = new AnalysisWindow();
1642 analysis_window->set_session(_session);
1644 analysis_window->show_all();
1647 analysis_window->set_regionmode();
1648 analysis_window->analyze();
1650 analysis_window->present();
1654 Editor::analyze_range_selection()
1656 if (analysis_window == 0) {
1657 analysis_window = new AnalysisWindow();
1660 analysis_window->set_session(_session);
1662 analysis_window->show_all();
1665 analysis_window->set_rangemode();
1666 analysis_window->analyze();
1668 analysis_window->present();
1672 Editor::build_track_selection_context_menu ()
1674 using namespace Menu_Helpers;
1675 MenuList& edit_items = track_selection_context_menu.items();
1676 edit_items.clear ();
1678 add_selection_context_items (edit_items);
1679 // edit_items.push_back (SeparatorElem());
1680 // add_dstream_context_items (edit_items);
1682 return &track_selection_context_menu;
1685 /** Add context menu items relevant to crossfades.
1686 * @param edit_items List to add the items to.
1689 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1691 using namespace Menu_Helpers;
1692 Menu *xfade_menu = manage (new Menu);
1693 MenuList& items = xfade_menu->items();
1694 xfade_menu->set_name ("ArdourContextMenu");
1697 if (xfade->active()) {
1703 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1704 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1706 if (xfade->can_follow_overlap()) {
1708 if (xfade->following_overlap()) {
1709 str = _("Convert to Short");
1711 str = _("Convert to Full");
1714 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1718 str = xfade->out()->name();
1720 str += xfade->in()->name();
1722 str = _("Crossfade");
1725 edit_items.push_back (MenuElem (str, *xfade_menu));
1726 edit_items.push_back (SeparatorElem());
1730 Editor::xfade_edit_left_region ()
1732 if (clicked_crossfadeview) {
1733 clicked_crossfadeview->left_view.show_region_editor ();
1738 Editor::xfade_edit_right_region ()
1740 if (clicked_crossfadeview) {
1741 clicked_crossfadeview->right_view.show_region_editor ();
1746 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1748 using namespace Menu_Helpers;
1750 /* OK, stick the region submenu at the top of the list, and then add
1754 RegionSelection rs = get_regions_from_selection_and_entered ();
1756 string::size_type pos = 0;
1757 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1759 /* we have to hack up the region name because "_" has a special
1760 meaning for menu titles.
1763 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1764 menu_item_name.replace (pos, 1, "__");
1768 if (_popup_region_menu_item == 0) {
1769 _popup_region_menu_item = new MenuItem (menu_item_name);
1770 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1771 _popup_region_menu_item->show ();
1773 _popup_region_menu_item->set_label (menu_item_name);
1776 /* Use the mouse position rather than the edit point to decide whether to show the `choose top region'
1777 dialogue. If we use the edit point it gets a bit messy because the user still has to click over
1778 *some* region in order to get the region context menu stuff to be displayed at all.
1783 mouse_frame (mouse, ignored);
1785 edit_items.push_back (*_popup_region_menu_item);
1786 if (track->playlist()->count_regions_at (mouse) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1787 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1789 edit_items.push_back (SeparatorElem());
1792 /** Add context menu items relevant to selection ranges.
1793 * @param edit_items List to add the items to.
1796 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1798 using namespace Menu_Helpers;
1800 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1801 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1803 edit_items.push_back (SeparatorElem());
1804 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1806 if (!selection->regions.empty()) {
1807 edit_items.push_back (SeparatorElem());
1808 edit_items.push_back (MenuElem (_("Extend Range to End of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_end_of_region), false)));
1809 edit_items.push_back (MenuElem (_("Extend Range to Start of Region"), sigc::bind (sigc::mem_fun(*this, &Editor::extend_selection_to_start_of_region), false)));
1812 edit_items.push_back (SeparatorElem());
1813 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1814 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1816 edit_items.push_back (SeparatorElem());
1817 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1819 edit_items.push_back (SeparatorElem());
1820 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1821 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1823 edit_items.push_back (SeparatorElem());
1824 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1826 edit_items.push_back (SeparatorElem());
1827 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1828 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1829 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1831 edit_items.push_back (SeparatorElem());
1832 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1833 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1834 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1835 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1836 edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1841 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1843 using namespace Menu_Helpers;
1847 Menu *play_menu = manage (new Menu);
1848 MenuList& play_items = play_menu->items();
1849 play_menu->set_name ("ArdourContextMenu");
1851 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1852 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1853 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1854 play_items.push_back (SeparatorElem());
1855 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1857 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1861 Menu *select_menu = manage (new Menu);
1862 MenuList& select_items = select_menu->items();
1863 select_menu->set_name ("ArdourContextMenu");
1865 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1866 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1867 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1868 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1869 select_items.push_back (SeparatorElem());
1870 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1871 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1872 select_items.push_back (SeparatorElem());
1873 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1874 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1875 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1876 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1877 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1878 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1879 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1881 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1885 Menu *cutnpaste_menu = manage (new Menu);
1886 MenuList& cutnpaste_items = cutnpaste_menu->items();
1887 cutnpaste_menu->set_name ("ArdourContextMenu");
1889 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1890 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1891 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1893 cutnpaste_items.push_back (SeparatorElem());
1895 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1896 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1898 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1900 /* Adding new material */
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1904 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1908 Menu *nudge_menu = manage (new Menu());
1909 MenuList& nudge_items = nudge_menu->items();
1910 nudge_menu->set_name ("ArdourContextMenu");
1912 edit_items.push_back (SeparatorElem());
1913 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1914 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1915 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1916 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1918 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1922 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1924 using namespace Menu_Helpers;
1928 Menu *play_menu = manage (new Menu);
1929 MenuList& play_items = play_menu->items();
1930 play_menu->set_name ("ArdourContextMenu");
1932 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1933 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1934 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1938 Menu *select_menu = manage (new Menu);
1939 MenuList& select_items = select_menu->items();
1940 select_menu->set_name ("ArdourContextMenu");
1942 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1943 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1944 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1945 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1946 select_items.push_back (SeparatorElem());
1947 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1948 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1949 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1950 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1952 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1956 Menu *cutnpaste_menu = manage (new Menu);
1957 MenuList& cutnpaste_items = cutnpaste_menu->items();
1958 cutnpaste_menu->set_name ("ArdourContextMenu");
1960 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1961 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1962 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1964 Menu *nudge_menu = manage (new Menu());
1965 MenuList& nudge_items = nudge_menu->items();
1966 nudge_menu->set_name ("ArdourContextMenu");
1968 edit_items.push_back (SeparatorElem());
1969 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1970 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1971 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1972 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1974 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1978 Editor::snap_type() const
1984 Editor::snap_mode() const
1990 Editor::set_snap_to (SnapType st)
1992 unsigned int snap_ind = (unsigned int)st;
1996 if (snap_ind > snap_type_strings.size() - 1) {
1998 _snap_type = (SnapType)snap_ind;
2001 string str = snap_type_strings[snap_ind];
2003 if (str != snap_type_selector.get_active_text()) {
2004 snap_type_selector.set_active_text (str);
2009 switch (_snap_type) {
2010 case SnapToBeatDiv32:
2011 case SnapToBeatDiv28:
2012 case SnapToBeatDiv24:
2013 case SnapToBeatDiv20:
2014 case SnapToBeatDiv16:
2015 case SnapToBeatDiv14:
2016 case SnapToBeatDiv12:
2017 case SnapToBeatDiv10:
2018 case SnapToBeatDiv8:
2019 case SnapToBeatDiv7:
2020 case SnapToBeatDiv6:
2021 case SnapToBeatDiv5:
2022 case SnapToBeatDiv4:
2023 case SnapToBeatDiv3:
2024 case SnapToBeatDiv2:
2025 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2026 update_tempo_based_rulers ();
2029 case SnapToRegionStart:
2030 case SnapToRegionEnd:
2031 case SnapToRegionSync:
2032 case SnapToRegionBoundary:
2033 build_region_boundary_cache ();
2041 SnapChanged (); /* EMIT SIGNAL */
2045 Editor::set_snap_mode (SnapMode mode)
2048 string str = snap_mode_strings[(int)mode];
2050 if (str != snap_mode_selector.get_active_text ()) {
2051 snap_mode_selector.set_active_text (str);
2057 Editor::set_edit_point_preference (EditPoint ep, bool force)
2059 bool changed = (_edit_point != ep);
2062 string str = edit_point_strings[(int)ep];
2064 if (str != edit_point_selector.get_active_text ()) {
2065 edit_point_selector.set_active_text (str);
2068 set_canvas_cursor ();
2070 if (!force && !changed) {
2074 const char* action=NULL;
2076 switch (_edit_point) {
2077 case EditAtPlayhead:
2078 action = "edit-at-playhead";
2080 case EditAtSelectedMarker:
2081 action = "edit-at-marker";
2084 action = "edit-at-mouse";
2088 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2090 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2094 bool in_track_canvas;
2096 if (!mouse_frame (foo, in_track_canvas)) {
2097 in_track_canvas = false;
2100 reset_canvas_action_sensitivity (in_track_canvas);
2106 Editor::set_state (const XMLNode& node, int /*version*/)
2108 const XMLProperty* prop;
2110 int x, y, xoff, yoff;
2113 if ((prop = node.property ("id")) != 0) {
2114 _id = prop->value ();
2117 g.base_width = default_width;
2118 g.base_height = default_height;
2124 if ((geometry = find_named_node (node, "geometry")) != 0) {
2128 if ((prop = geometry->property("x_size")) == 0) {
2129 prop = geometry->property ("x-size");
2132 g.base_width = atoi(prop->value());
2134 if ((prop = geometry->property("y_size")) == 0) {
2135 prop = geometry->property ("y-size");
2138 g.base_height = atoi(prop->value());
2141 if ((prop = geometry->property ("x_pos")) == 0) {
2142 prop = geometry->property ("x-pos");
2145 x = atoi (prop->value());
2148 if ((prop = geometry->property ("y_pos")) == 0) {
2149 prop = geometry->property ("y-pos");
2152 y = atoi (prop->value());
2155 if ((prop = geometry->property ("x_off")) == 0) {
2156 prop = geometry->property ("x-off");
2159 xoff = atoi (prop->value());
2161 if ((prop = geometry->property ("y_off")) == 0) {
2162 prop = geometry->property ("y-off");
2165 yoff = atoi (prop->value());
2169 set_default_size (g.base_width, g.base_height);
2172 if (_session && (prop = node.property ("playhead"))) {
2174 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2175 playhead_cursor->set_position (pos);
2177 playhead_cursor->set_position (0);
2180 if ((prop = node.property ("mixer-width"))) {
2181 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2184 if ((prop = node.property ("zoom-focus"))) {
2185 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2188 if ((prop = node.property ("zoom"))) {
2189 reset_zoom (PBD::atof (prop->value()));
2191 reset_zoom (frames_per_unit);
2194 if ((prop = node.property ("snap-to"))) {
2195 set_snap_to ((SnapType) atoi (prop->value()));
2198 if ((prop = node.property ("snap-mode"))) {
2199 set_snap_mode ((SnapMode) atoi (prop->value()));
2202 if ((prop = node.property ("mouse-mode"))) {
2203 MouseMode m = str2mousemode(prop->value());
2204 set_mouse_mode (m, true);
2206 set_mouse_mode (MouseObject, true);
2209 if ((prop = node.property ("left-frame")) != 0) {
2211 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2212 reset_x_origin (pos);
2216 if ((prop = node.property ("y-origin")) != 0) {
2217 reset_y_origin (atof (prop->value ()));
2220 if ((prop = node.property ("internal-edit"))) {
2221 bool yn = string_is_affirmative (prop->value());
2222 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2224 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2225 tact->set_active (!yn);
2226 tact->set_active (yn);
2230 if ((prop = node.property ("join-object-range"))) {
2231 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2234 if ((prop = node.property ("edit-point"))) {
2235 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2238 if ((prop = node.property ("show-measures"))) {
2239 bool yn = string_is_affirmative (prop->value());
2240 _show_measures = yn;
2241 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2243 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2244 /* do it twice to force the change */
2245 tact->set_active (!yn);
2246 tact->set_active (yn);
2250 if ((prop = node.property ("follow-playhead"))) {
2251 bool yn = string_is_affirmative (prop->value());
2252 set_follow_playhead (yn);
2253 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2255 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2256 if (tact->get_active() != yn) {
2257 tact->set_active (yn);
2262 if ((prop = node.property ("stationary-playhead"))) {
2263 bool yn = (prop->value() == "yes");
2264 set_stationary_playhead (yn);
2265 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2267 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2268 if (tact->get_active() != yn) {
2269 tact->set_active (yn);
2274 if ((prop = node.property ("region-list-sort-type"))) {
2275 RegionListSortType st;
2276 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2279 if ((prop = node.property ("xfades-visible"))) {
2280 bool yn = string_is_affirmative (prop->value());
2281 _xfade_visibility = !yn;
2282 // set_xfade_visibility (yn);
2285 if ((prop = node.property ("show-editor-mixer"))) {
2287 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2290 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2291 bool yn = string_is_affirmative (prop->value());
2293 /* do it twice to force the change */
2295 tact->set_active (!yn);
2296 tact->set_active (yn);
2299 if ((prop = node.property ("show-editor-list"))) {
2301 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2304 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2305 bool yn = string_is_affirmative (prop->value());
2307 /* do it twice to force the change */
2309 tact->set_active (!yn);
2310 tact->set_active (yn);
2313 if ((prop = node.property (X_("editor-list-page")))) {
2314 _the_notebook.set_current_page (atoi (prop->value ()));
2317 if ((prop = node.property (X_("show-marker-lines")))) {
2318 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2320 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2321 bool yn = string_is_affirmative (prop->value ());
2323 tact->set_active (!yn);
2324 tact->set_active (yn);
2327 XMLNodeList children = node.children ();
2328 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2329 selection->set_state (**i, Stateful::current_state_version);
2330 _regions->set_state (**i);
2337 Editor::get_state ()
2339 XMLNode* node = new XMLNode ("Editor");
2342 _id.print (buf, sizeof (buf));
2343 node->add_property ("id", buf);
2345 if (is_realized()) {
2346 Glib::RefPtr<Gdk::Window> win = get_window();
2348 int x, y, xoff, yoff, width, height;
2349 win->get_root_origin(x, y);
2350 win->get_position(xoff, yoff);
2351 win->get_size(width, height);
2353 XMLNode* geometry = new XMLNode ("geometry");
2355 snprintf(buf, sizeof(buf), "%d", width);
2356 geometry->add_property("x-size", string(buf));
2357 snprintf(buf, sizeof(buf), "%d", height);
2358 geometry->add_property("y-size", string(buf));
2359 snprintf(buf, sizeof(buf), "%d", x);
2360 geometry->add_property("x-pos", string(buf));
2361 snprintf(buf, sizeof(buf), "%d", y);
2362 geometry->add_property("y-pos", string(buf));
2363 snprintf(buf, sizeof(buf), "%d", xoff);
2364 geometry->add_property("x-off", string(buf));
2365 snprintf(buf, sizeof(buf), "%d", yoff);
2366 geometry->add_property("y-off", string(buf));
2367 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2368 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2369 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2370 snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position);
2371 geometry->add_property("pre-maximal-horizontal-pane-position", string(buf));
2372 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2373 geometry->add_property("edit-vertical-pane-pos", string(buf));
2375 node->add_child_nocopy (*geometry);
2378 maybe_add_mixer_strip_width (*node);
2380 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2381 node->add_property ("zoom-focus", buf);
2382 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2383 node->add_property ("zoom", buf);
2384 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2385 node->add_property ("snap-to", buf);
2386 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2387 node->add_property ("snap-mode", buf);
2389 node->add_property ("edit-point", enum_2_string (_edit_point));
2391 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2392 node->add_property ("playhead", buf);
2393 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2394 node->add_property ("left-frame", buf);
2395 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2396 node->add_property ("y-origin", buf);
2398 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2399 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2400 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2401 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2402 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2403 node->add_property ("mouse-mode", enum2str(mouse_mode));
2404 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2405 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2407 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2409 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2410 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2413 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2415 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2416 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2419 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2420 node->add_property (X_("editor-list-page"), buf);
2422 if (button_bindings) {
2423 XMLNode* bb = new XMLNode (X_("Buttons"));
2424 button_bindings->save (*bb);
2425 node->add_child_nocopy (*bb);
2428 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2430 node->add_child_nocopy (selection->get_state ());
2431 node->add_child_nocopy (_regions->get_state ());
2438 /** @param y y offset from the top of all trackviews.
2439 * @return pair: TimeAxisView that y is over, layer index.
2440 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2441 * in stacked region display mode, otherwise 0.
2443 std::pair<TimeAxisView *, layer_t>
2444 Editor::trackview_by_y_position (double y)
2446 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2448 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2454 return std::make_pair ( (TimeAxisView *) 0, 0);
2457 /** Snap a position to the grid, if appropriate, taking into account current
2458 * grid settings and also the state of any snap modifier keys that may be pressed.
2459 * @param start Position to snap.
2460 * @param event Event to get current key modifier information from, or 0.
2463 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2465 if (!_session || !event) {
2469 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2470 if (_snap_mode == SnapOff) {
2471 snap_to_internal (start, direction, for_mark);
2474 if (_snap_mode != SnapOff) {
2475 snap_to_internal (start, direction, for_mark);
2481 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2483 if (!_session || _snap_mode == SnapOff) {
2487 snap_to_internal (start, direction, for_mark);
2491 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2493 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2494 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2496 switch (_snap_type) {
2497 case SnapToTimecodeFrame:
2498 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2499 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2501 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2505 case SnapToTimecodeSeconds:
2506 if (_session->config.get_timecode_offset_negative()) {
2507 start += _session->config.get_timecode_offset ();
2509 start -= _session->config.get_timecode_offset ();
2511 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2512 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2514 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2517 if (_session->config.get_timecode_offset_negative()) {
2518 start -= _session->config.get_timecode_offset ();
2520 start += _session->config.get_timecode_offset ();
2524 case SnapToTimecodeMinutes:
2525 if (_session->config.get_timecode_offset_negative()) {
2526 start += _session->config.get_timecode_offset ();
2528 start -= _session->config.get_timecode_offset ();
2530 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2531 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2533 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2535 if (_session->config.get_timecode_offset_negative()) {
2536 start -= _session->config.get_timecode_offset ();
2538 start += _session->config.get_timecode_offset ();
2542 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2548 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2550 const framepos_t one_second = _session->frame_rate();
2551 const framepos_t one_minute = _session->frame_rate() * 60;
2552 framepos_t presnap = start;
2556 switch (_snap_type) {
2557 case SnapToTimecodeFrame:
2558 case SnapToTimecodeSeconds:
2559 case SnapToTimecodeMinutes:
2560 return timecode_snap_to_internal (start, direction, for_mark);
2563 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2564 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2566 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2571 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2572 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2574 start = (framepos_t) floor ((double) start / one_second) * one_second;
2579 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2580 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2582 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2587 start = _session->tempo_map().round_to_bar (start, direction);
2591 start = _session->tempo_map().round_to_beat (start, direction);
2594 case SnapToBeatDiv32:
2595 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2597 case SnapToBeatDiv28:
2598 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2600 case SnapToBeatDiv24:
2601 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2603 case SnapToBeatDiv20:
2604 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2606 case SnapToBeatDiv16:
2607 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2609 case SnapToBeatDiv14:
2610 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2612 case SnapToBeatDiv12:
2613 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2615 case SnapToBeatDiv10:
2616 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2618 case SnapToBeatDiv8:
2619 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2621 case SnapToBeatDiv7:
2622 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2624 case SnapToBeatDiv6:
2625 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2627 case SnapToBeatDiv5:
2628 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2630 case SnapToBeatDiv4:
2631 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2633 case SnapToBeatDiv3:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2636 case SnapToBeatDiv2:
2637 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2645 _session->locations()->marks_either_side (start, before, after);
2647 if (before == max_framepos) {
2649 } else if (after == max_framepos) {
2651 } else if (before != max_framepos && after != max_framepos) {
2652 /* have before and after */
2653 if ((start - before) < (after - start)) {
2662 case SnapToRegionStart:
2663 case SnapToRegionEnd:
2664 case SnapToRegionSync:
2665 case SnapToRegionBoundary:
2666 if (!region_boundary_cache.empty()) {
2668 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2669 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2671 if (direction > 0) {
2672 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2674 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2677 if (next != region_boundary_cache.begin ()) {
2682 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2683 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2685 if (start > (p + n) / 2) {
2694 switch (_snap_mode) {
2700 if (presnap > start) {
2701 if (presnap > (start + unit_to_frame(snap_threshold))) {
2705 } else if (presnap < start) {
2706 if (presnap < (start - unit_to_frame(snap_threshold))) {
2712 /* handled at entry */
2720 Editor::setup_toolbar ()
2724 /* Mode Buttons (tool selection) */
2726 mouse_move_button.set_relief(Gtk::RELIEF_NONE);
2727 mouse_select_button.set_relief(Gtk::RELIEF_NONE);
2728 mouse_gain_button.set_relief(Gtk::RELIEF_NONE);
2729 mouse_zoom_button.set_relief(Gtk::RELIEF_NONE);
2730 mouse_timefx_button.set_relief(Gtk::RELIEF_NONE);
2731 mouse_audition_button.set_relief(Gtk::RELIEF_NONE);
2732 // internal_edit_button.set_relief(Gtk::RELIEF_NONE);
2733 join_object_range_button.set_relief(Gtk::RELIEF_NONE);
2735 HBox* mode_box = manage(new HBox);
2736 mode_box->set_border_width (2);
2737 mode_box->set_spacing(4);
2739 /* table containing mode buttons */
2741 HBox* mouse_mode_button_box = manage (new HBox ());
2743 if (Profile->get_sae()) {
2744 mouse_mode_button_box->pack_start (mouse_move_button);
2746 mouse_mode_button_box->pack_start (mouse_move_button);
2747 mouse_mode_button_box->pack_start (join_object_range_button);
2748 mouse_mode_button_box->pack_start (mouse_select_button);
2751 mouse_mode_button_box->pack_start (mouse_zoom_button);
2753 if (!Profile->get_sae()) {
2754 mouse_mode_button_box->pack_start (mouse_gain_button);
2757 mouse_mode_button_box->pack_start (mouse_timefx_button);
2758 mouse_mode_button_box->pack_start (mouse_audition_button);
2759 mouse_mode_button_box->pack_start (internal_edit_button);
2761 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2762 if (!Profile->get_sae()) {
2763 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2765 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2767 edit_mode_selector.set_name ("EditModeSelector");
2768 set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2769 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2771 mode_box->pack_start (edit_mode_selector);
2772 mode_box->pack_start (*mouse_mode_button_box);
2774 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2775 _mouse_mode_tearoff->set_name ("MouseModeBase");
2776 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2778 if (Profile->get_sae()) {
2779 _mouse_mode_tearoff->set_can_be_torn_off (false);
2782 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2783 &_mouse_mode_tearoff->tearoff_window()));
2784 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2785 &_mouse_mode_tearoff->tearoff_window(), 1));
2786 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2787 &_mouse_mode_tearoff->tearoff_window()));
2788 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2789 &_mouse_mode_tearoff->tearoff_window(), 1));
2791 mouse_move_button.set_mode (false);
2792 mouse_select_button.set_mode (false);
2793 mouse_gain_button.set_mode (false);
2794 mouse_zoom_button.set_mode (false);
2795 mouse_timefx_button.set_mode (false);
2796 mouse_audition_button.set_mode (false);
2797 join_object_range_button.set_mode (false);
2799 mouse_move_button.set_name ("MouseModeButton");
2800 mouse_select_button.set_name ("MouseModeButton");
2801 mouse_gain_button.set_name ("MouseModeButton");
2802 mouse_zoom_button.set_name ("MouseModeButton");
2803 mouse_timefx_button.set_name ("MouseModeButton");
2804 mouse_audition_button.set_name ("MouseModeButton");
2805 internal_edit_button.set_name ("MouseModeButton");
2806 join_object_range_button.set_name ("MouseModeButton");
2808 mouse_move_button.unset_flags (CAN_FOCUS);
2809 mouse_select_button.unset_flags (CAN_FOCUS);
2810 mouse_gain_button.unset_flags (CAN_FOCUS);
2811 mouse_zoom_button.unset_flags (CAN_FOCUS);
2812 mouse_timefx_button.unset_flags (CAN_FOCUS);
2813 mouse_audition_button.unset_flags (CAN_FOCUS);
2814 internal_edit_button.unset_flags (CAN_FOCUS);
2815 join_object_range_button.unset_flags (CAN_FOCUS);
2819 _zoom_box.set_spacing (1);
2820 _zoom_box.set_border_width (0);
2822 zoom_in_button.set_name ("EditorTimeButton");
2823 zoom_in_button.set_image (*(manage (new Image (::get_icon ("zoom_in")))));
2824 zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2826 zoom_out_button.set_name ("EditorTimeButton");
2827 zoom_out_button.set_image (*(manage (new Image (::get_icon ("zoom_out")))));
2828 zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2830 zoom_out_full_button.set_name ("EditorTimeButton");
2831 zoom_out_full_button.set_image (*(manage (new Image (::get_icon ("zoom_full")))));
2832 zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2834 zoom_focus_selector.set_name ("ZoomFocusSelector");
2835 set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2836 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2838 _zoom_box.pack_start (zoom_out_button, false, false);
2839 _zoom_box.pack_start (zoom_in_button, false, false);
2840 _zoom_box.pack_start (zoom_out_full_button, false, false);
2842 _zoom_box.pack_start (zoom_focus_selector);
2844 /* Track zoom buttons */
2845 tav_expand_button.set_name ("TrackHeightButton");
2846 tav_expand_button.set_size_request (-1, 20);
2847 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2848 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2849 act->connect_proxy (tav_expand_button);
2851 tav_shrink_button.set_name ("TrackHeightButton");
2852 tav_shrink_button.set_size_request (-1, 20);
2853 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2854 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2855 act->connect_proxy (tav_shrink_button);
2857 _zoom_box.pack_start (tav_shrink_button);
2858 _zoom_box.pack_start (tav_expand_button);
2860 _zoom_tearoff = manage (new TearOff (_zoom_box));
2862 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2863 &_zoom_tearoff->tearoff_window()));
2864 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2865 &_zoom_tearoff->tearoff_window(), 0));
2866 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2867 &_zoom_tearoff->tearoff_window()));
2868 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2869 &_zoom_tearoff->tearoff_window(), 0));
2871 snap_box.set_spacing (1);
2872 snap_box.set_border_width (2);
2874 snap_type_selector.set_name ("SnapTypeSelector");
2875 set_popdown_strings (snap_type_selector, snap_type_strings, true);
2876 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2878 snap_mode_selector.set_name ("SnapModeSelector");
2879 set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2880 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2882 edit_point_selector.set_name ("EditPointSelector");
2883 set_popdown_strings (edit_point_selector, edit_point_strings, true);
2884 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2886 snap_box.pack_start (snap_mode_selector, false, false);
2887 snap_box.pack_start (snap_type_selector, false, false);
2888 snap_box.pack_start (edit_point_selector, false, false);
2892 HBox *nudge_box = manage (new HBox);
2893 nudge_box->set_spacing(1);
2894 nudge_box->set_border_width (2);
2896 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2897 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2899 nudge_box->pack_start (nudge_backward_button, false, false);
2900 nudge_box->pack_start (nudge_forward_button, false, false);
2901 nudge_box->pack_start (nudge_clock, false, false);
2904 /* Pack everything in... */
2906 HBox* hbox = manage (new HBox);
2907 hbox->set_spacing(10);
2909 _tools_tearoff = manage (new TearOff (*hbox));
2910 _tools_tearoff->set_name ("MouseModeBase");
2911 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2913 if (Profile->get_sae()) {
2914 _tools_tearoff->set_can_be_torn_off (false);
2917 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2918 &_tools_tearoff->tearoff_window()));
2919 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2920 &_tools_tearoff->tearoff_window(), 0));
2921 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2922 &_tools_tearoff->tearoff_window()));
2923 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2924 &_tools_tearoff->tearoff_window(), 0));
2926 toolbar_hbox.set_spacing (10);
2927 toolbar_hbox.set_border_width (1);
2929 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2930 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2931 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2933 hbox->pack_start (snap_box, false, false);
2934 if (!Profile->get_small_screen()) {
2935 hbox->pack_start (*nudge_box, false, false);
2937 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2939 hbox->pack_start (panic_box, false, false);
2943 toolbar_base.set_name ("ToolBarBase");
2944 toolbar_base.add (toolbar_hbox);
2946 _toolbar_viewport.add (toolbar_base);
2947 /* stick to the required height but allow width to vary if there's not enough room */
2948 _toolbar_viewport.set_size_request (1, -1);
2950 toolbar_frame.set_shadow_type (SHADOW_OUT);
2951 toolbar_frame.set_name ("BaseFrame");
2952 toolbar_frame.add (_toolbar_viewport);
2954 DPIReset.connect (sigc::mem_fun (*this, &Editor::resize_text_widgets));
2958 Editor::setup_tooltips ()
2960 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2961 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2962 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2963 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2964 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2965 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2966 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2967 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2968 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2969 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2970 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2971 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2972 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2973 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2974 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2975 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2976 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2977 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2978 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2979 ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
2980 ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
2981 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
2985 Editor::midi_panic ()
2987 cerr << "MIDI panic\n";
2990 _session->midi_panic();
2995 Editor::setup_midi_toolbar ()
2999 /* Midi sound notes */
3000 midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
3001 midi_sound_notes.set_relief(Gtk::RELIEF_NONE);
3002 midi_sound_notes.unset_flags (CAN_FOCUS);
3006 act = ActionManager::get_action (X_("MIDI"), X_("panic"));
3007 midi_panic_button.set_name("MidiPanicButton");
3008 act->connect_proxy (midi_panic_button);
3010 panic_box.pack_start (midi_sound_notes , true, true);
3011 panic_box.pack_start (midi_panic_button, true, true);
3015 Editor::convert_drop_to_paths (
3016 vector<string>& paths,
3017 const RefPtr<Gdk::DragContext>& /*context*/,
3020 const SelectionData& data,
3024 if (_session == 0) {
3028 vector<string> uris = data.get_uris();
3032 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3033 are actually URI lists. So do it by hand.
3036 if (data.get_target() != "text/plain") {
3040 /* Parse the "uri-list" format that Nautilus provides,
3041 where each pathname is delimited by \r\n.
3043 THERE MAY BE NO NULL TERMINATING CHAR!!!
3046 string txt = data.get_text();
3050 p = (const char *) malloc (txt.length() + 1);
3051 txt.copy ((char *) p, txt.length(), 0);
3052 ((char*)p)[txt.length()] = '\0';
3058 while (g_ascii_isspace (*p))
3062 while (*q && (*q != '\n') && (*q != '\r')) {
3069 while (q > p && g_ascii_isspace (*q))
3074 uris.push_back (string (p, q - p + 1));
3078 p = strchr (p, '\n');
3090 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3092 if ((*i).substr (0,7) == "file://") {
3095 PBD::url_decode (p);
3097 // scan forward past three slashes
3099 string::size_type slashcnt = 0;
3100 string::size_type n = 0;
3101 string::iterator x = p.begin();
3103 while (slashcnt < 3 && x != p.end()) {
3106 } else if (slashcnt == 3) {
3113 if (slashcnt != 3 || x == p.end()) {
3114 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3118 paths.push_back (p.substr (n - 1));
3126 Editor::new_tempo_section ()
3132 Editor::map_transport_state ()
3134 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3136 if (_session && _session->transport_stopped()) {
3137 have_pending_keyboard_selection = false;
3140 update_loop_range_view (true);
3145 Editor::State::State (PublicEditor const * e)
3147 selection = new Selection (e);
3150 Editor::State::~State ()
3156 Editor::begin_reversible_command (string name)
3159 _session->begin_reversible_command (name);
3164 Editor::begin_reversible_command (GQuark q)
3167 _session->begin_reversible_command (q);
3172 Editor::commit_reversible_command ()
3175 _session->commit_reversible_command ();
3180 Editor::history_changed ()
3184 if (undo_action && _session) {
3185 if (_session->undo_depth() == 0) {
3188 label = string_compose(_("Undo (%1)"), _session->next_undo());
3190 undo_action->property_label() = label;
3193 if (redo_action && _session) {
3194 if (_session->redo_depth() == 0) {
3197 label = string_compose(_("Redo (%1)"), _session->next_redo());
3199 redo_action->property_label() = label;
3204 Editor::duplicate_dialog (bool with_dialog)
3208 if (mouse_mode == MouseRange) {
3209 if (selection->time.length() == 0) {
3214 RegionSelection rs = get_regions_from_selection_and_entered ();
3216 if (mouse_mode != MouseRange && rs.empty()) {
3222 ArdourDialog win (_("Duplicate"));
3223 Label label (_("Number of duplications:"));
3224 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3225 SpinButton spinner (adjustment, 0.0, 1);
3228 win.get_vbox()->set_spacing (12);
3229 win.get_vbox()->pack_start (hbox);
3230 hbox.set_border_width (6);
3231 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3233 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3234 place, visually. so do this by hand.
3237 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3238 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3239 spinner.grab_focus();
3245 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3246 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3247 win.set_default_response (RESPONSE_ACCEPT);
3249 win.set_position (WIN_POS_MOUSE);
3251 spinner.grab_focus ();
3253 switch (win.run ()) {
3254 case RESPONSE_ACCEPT:
3260 times = adjustment.get_value();
3263 if (mouse_mode == MouseRange) {
3264 duplicate_selection (times);
3266 duplicate_some_regions (rs, times);
3271 Editor::show_verbose_canvas_cursor ()
3273 verbose_canvas_cursor->raise_to_top();
3274 verbose_canvas_cursor->show();
3275 verbose_cursor_visible = true;
3279 Editor::hide_verbose_canvas_cursor ()
3281 verbose_canvas_cursor->hide();
3282 verbose_cursor_visible = false;
3286 Editor::clamp_verbose_cursor_x (double x)
3291 x = min (_canvas_width - 200.0, x);
3297 Editor::clamp_verbose_cursor_y (double y)
3299 if (y < canvas_timebars_vsize) {
3300 y = canvas_timebars_vsize;
3302 y = min (_canvas_height - 50, y);
3308 Editor::show_verbose_canvas_cursor_with (const string & txt, int32_t xoffset, int32_t yoffset)
3310 verbose_canvas_cursor->property_text() = txt.c_str();
3315 track_canvas->get_pointer (x, y);
3316 track_canvas->window_to_world (x, y, wx, wy);
3321 /* don't get too close to the edge */
3322 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (wx);
3323 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (wy);
3325 show_verbose_canvas_cursor ();
3329 Editor::set_verbose_canvas_cursor (const string & txt, double x, double y)
3331 verbose_canvas_cursor->property_text() = txt.c_str();
3332 /* don't get too close to the edge */
3333 verbose_canvas_cursor->property_x() = clamp_verbose_cursor_x (x);
3334 verbose_canvas_cursor->property_y() = clamp_verbose_cursor_y (y);
3338 Editor::set_verbose_canvas_cursor_text (const string & txt)
3340 verbose_canvas_cursor->property_text() = txt.c_str();
3344 Editor::set_edit_mode (EditMode m)
3346 Config->set_edit_mode (m);
3350 Editor::cycle_edit_mode ()
3352 switch (Config->get_edit_mode()) {
3354 if (Profile->get_sae()) {
3355 Config->set_edit_mode (Lock);
3357 Config->set_edit_mode (Splice);
3361 Config->set_edit_mode (Lock);
3364 Config->set_edit_mode (Slide);
3370 Editor::edit_mode_selection_done ()
3372 string s = edit_mode_selector.get_active_text ();
3375 Config->set_edit_mode (string_to_edit_mode (s));
3380 Editor::snap_type_selection_done ()
3382 string choice = snap_type_selector.get_active_text();
3383 SnapType snaptype = SnapToBeat;
3385 if (choice == _("Beats/2")) {
3386 snaptype = SnapToBeatDiv2;
3387 } else if (choice == _("Beats/3")) {
3388 snaptype = SnapToBeatDiv3;
3389 } else if (choice == _("Beats/4")) {
3390 snaptype = SnapToBeatDiv4;
3391 } else if (choice == _("Beats/5")) {
3392 snaptype = SnapToBeatDiv5;
3393 } else if (choice == _("Beats/6")) {
3394 snaptype = SnapToBeatDiv6;
3395 } else if (choice == _("Beats/7")) {
3396 snaptype = SnapToBeatDiv7;
3397 } else if (choice == _("Beats/8")) {
3398 snaptype = SnapToBeatDiv8;
3399 } else if (choice == _("Beats/10")) {
3400 snaptype = SnapToBeatDiv10;
3401 } else if (choice == _("Beats/12")) {
3402 snaptype = SnapToBeatDiv12;
3403 } else if (choice == _("Beats/14")) {
3404 snaptype = SnapToBeatDiv14;
3405 } else if (choice == _("Beats/16")) {
3406 snaptype = SnapToBeatDiv16;
3407 } else if (choice == _("Beats/20")) {
3408 snaptype = SnapToBeatDiv20;
3409 } else if (choice == _("Beats/24")) {
3410 snaptype = SnapToBeatDiv24;
3411 } else if (choice == _("Beats/28")) {
3412 snaptype = SnapToBeatDiv28;
3413 } else if (choice == _("Beats/32")) {
3414 snaptype = SnapToBeatDiv32;
3415 } else if (choice == _("Beats")) {
3416 snaptype = SnapToBeat;
3417 } else if (choice == _("Bars")) {
3418 snaptype = SnapToBar;
3419 } else if (choice == _("Marks")) {
3420 snaptype = SnapToMark;
3421 } else if (choice == _("Region starts")) {
3422 snaptype = SnapToRegionStart;
3423 } else if (choice == _("Region ends")) {
3424 snaptype = SnapToRegionEnd;
3425 } else if (choice == _("Region bounds")) {
3426 snaptype = SnapToRegionBoundary;
3427 } else if (choice == _("Region syncs")) {
3428 snaptype = SnapToRegionSync;
3429 } else if (choice == _("CD Frames")) {
3430 snaptype = SnapToCDFrame;
3431 } else if (choice == _("Timecode Frames")) {
3432 snaptype = SnapToTimecodeFrame;
3433 } else if (choice == _("Timecode Seconds")) {
3434 snaptype = SnapToTimecodeSeconds;
3435 } else if (choice == _("Timecode Minutes")) {
3436 snaptype = SnapToTimecodeMinutes;
3437 } else if (choice == _("Seconds")) {
3438 snaptype = SnapToSeconds;
3439 } else if (choice == _("Minutes")) {
3440 snaptype = SnapToMinutes;
3443 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3445 ract->set_active ();
3450 Editor::snap_mode_selection_done ()
3452 string choice = snap_mode_selector.get_active_text();
3453 SnapMode mode = SnapNormal;
3455 if (choice == _("No Grid")) {
3457 } else if (choice == _("Grid")) {
3459 } else if (choice == _("Magnetic")) {
3460 mode = SnapMagnetic;
3463 RefPtr<RadioAction> ract = snap_mode_action (mode);
3466 ract->set_active (true);
3471 Editor::cycle_edit_point (bool with_marker)
3473 switch (_edit_point) {
3475 set_edit_point_preference (EditAtPlayhead);
3477 case EditAtPlayhead:
3479 set_edit_point_preference (EditAtSelectedMarker);
3481 set_edit_point_preference (EditAtMouse);
3484 case EditAtSelectedMarker:
3485 set_edit_point_preference (EditAtMouse);
3491 Editor::edit_point_selection_done ()
3493 string choice = edit_point_selector.get_active_text();
3494 EditPoint ep = EditAtSelectedMarker;
3496 if (choice == _("Marker")) {
3497 set_edit_point_preference (EditAtSelectedMarker);
3498 } else if (choice == _("Playhead")) {
3499 set_edit_point_preference (EditAtPlayhead);
3501 set_edit_point_preference (EditAtMouse);
3504 RefPtr<RadioAction> ract = edit_point_action (ep);
3507 ract->set_active (true);
3512 Editor::zoom_focus_selection_done ()
3514 string choice = zoom_focus_selector.get_active_text();
3515 ZoomFocus focus_type = ZoomFocusLeft;
3517 if (choice == _("Left")) {
3518 focus_type = ZoomFocusLeft;
3519 } else if (choice == _("Right")) {
3520 focus_type = ZoomFocusRight;
3521 } else if (choice == _("Center")) {
3522 focus_type = ZoomFocusCenter;
3523 } else if (choice == _("Playhead")) {
3524 focus_type = ZoomFocusPlayhead;
3525 } else if (choice == _("Mouse")) {
3526 focus_type = ZoomFocusMouse;
3527 } else if (choice == _("Edit point")) {
3528 focus_type = ZoomFocusEdit;
3531 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3534 ract->set_active ();
3539 Editor::edit_controls_button_release (GdkEventButton* ev)
3541 if (Keyboard::is_context_menu_event (ev)) {
3542 ARDOUR_UI::instance()->add_route (this);
3548 Editor::mouse_select_button_release (GdkEventButton* ev)
3550 /* this handles just right-clicks */
3552 if (ev->button != 3) {
3560 Editor::set_zoom_focus (ZoomFocus f)
3562 string str = zoom_focus_strings[(int)f];
3564 if (str != zoom_focus_selector.get_active_text()) {
3565 zoom_focus_selector.set_active_text (str);
3568 if (zoom_focus != f) {
3571 ZoomFocusChanged (); /* EMIT_SIGNAL */
3578 Editor::ensure_float (Window& win)
3580 win.set_transient_for (*this);
3584 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3586 /* recover or initialize pane positions. do this here rather than earlier because
3587 we don't want the positions to change the child allocations, which they seem to do.
3593 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3605 width = default_width;
3606 height = default_height;
3608 if ((geometry = find_named_node (*node, "geometry")) != 0) {
3610 prop = geometry->property ("x-size");
3612 width = atoi (prop->value());
3614 prop = geometry->property ("y-size");
3616 height = atoi (prop->value());
3620 if (which == static_cast<Paned*> (&edit_pane)) {
3622 if (done & Horizontal) {
3626 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3627 _notebook_shrunk = string_is_affirmative (prop->value ());
3630 if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) {
3631 pre_maximal_horizontal_pane_position = atoi (prop->value ());
3634 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3635 /* initial allocation is 90% to canvas, 10% to notebook */
3636 pos = (int) floor (alloc.get_width() * 0.90f);
3637 snprintf (buf, sizeof(buf), "%d", pos);
3639 pos = atoi (prop->value());
3642 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3643 edit_pane.set_position (pos);
3644 if (pre_maximal_horizontal_pane_position == 0) {
3645 pre_maximal_horizontal_pane_position = pos;
3649 done = (Pane) (done | Horizontal);
3651 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3653 if (done & Vertical) {
3657 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3658 /* initial allocation is 90% to canvas, 10% to summary */
3659 pos = (int) floor (alloc.get_height() * 0.90f);
3660 snprintf (buf, sizeof(buf), "%d", pos);
3662 pos = atoi (prop->value());
3665 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3666 editor_summary_pane.set_position (pos);
3667 pre_maximal_vertical_pane_position = pos;
3670 done = (Pane) (done | Vertical);
3675 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3677 if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3678 top_hbox.remove (toolbar_frame);
3683 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3685 if (toolbar_frame.get_parent() == 0) {
3686 top_hbox.pack_end (toolbar_frame);
3691 Editor::set_show_measures (bool yn)
3693 if (_show_measures != yn) {
3696 if ((_show_measures = yn) == true) {
3698 tempo_lines->show();
3706 Editor::toggle_follow_playhead ()
3708 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3710 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3711 set_follow_playhead (tact->get_active());
3715 /** @param yn true to follow playhead, otherwise false.
3716 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3719 Editor::set_follow_playhead (bool yn, bool catch_up)
3721 if (_follow_playhead != yn) {
3722 if ((_follow_playhead = yn) == true && catch_up) {
3724 reset_x_origin_to_follow_playhead ();
3731 Editor::toggle_stationary_playhead ()
3733 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3735 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3736 set_stationary_playhead (tact->get_active());
3741 Editor::set_stationary_playhead (bool yn)
3743 if (_stationary_playhead != yn) {
3744 if ((_stationary_playhead = yn) == true) {
3746 // FIXME need a 3.0 equivalent of this 2.X call
3747 // update_current_screen ();
3754 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3756 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3758 xfade->set_active (!xfade->active());
3763 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3765 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3767 xfade->set_follow_overlap (!xfade->following_overlap());
3772 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3774 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3780 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3784 switch (cew.run ()) {
3785 case RESPONSE_ACCEPT:
3792 PropertyChange all_crossfade_properties;
3793 all_crossfade_properties.add (ARDOUR::Properties::active);
3794 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3795 xfade->PropertyChanged (all_crossfade_properties);
3799 Editor::playlist_selector () const
3801 return *_playlist_selector;
3805 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3809 switch (_snap_type) {
3814 case SnapToBeatDiv32:
3817 case SnapToBeatDiv28:
3820 case SnapToBeatDiv24:
3823 case SnapToBeatDiv20:
3826 case SnapToBeatDiv16:
3829 case SnapToBeatDiv14:
3832 case SnapToBeatDiv12:
3835 case SnapToBeatDiv10:
3838 case SnapToBeatDiv8:
3841 case SnapToBeatDiv7:
3844 case SnapToBeatDiv6:
3847 case SnapToBeatDiv5:
3850 case SnapToBeatDiv4:
3853 case SnapToBeatDiv3:
3856 case SnapToBeatDiv2:
3862 return _session->tempo_map().meter_at (position).beats_per_bar();
3867 case SnapToTimecodeFrame:
3868 case SnapToTimecodeSeconds:
3869 case SnapToTimecodeMinutes:
3872 case SnapToRegionStart:
3873 case SnapToRegionEnd:
3874 case SnapToRegionSync:
3875 case SnapToRegionBoundary:
3885 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3889 ret = nudge_clock.current_duration (pos);
3890 next = ret + 1; /* XXXX fix me */
3896 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3898 ArdourDialog dialog (_("Playlist Deletion"));
3899 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3900 "If left alone, no audio files used by it will be cleaned.\n"
3901 "If deleted, audio files used by it alone by will cleaned."),
3904 dialog.set_position (WIN_POS_CENTER);
3905 dialog.get_vbox()->pack_start (label);
3909 dialog.add_button (_("Delete playlist"), RESPONSE_ACCEPT);
3910 dialog.add_button (_("Keep playlist"), RESPONSE_REJECT);
3911 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3913 switch (dialog.run ()) {
3914 case RESPONSE_ACCEPT:
3915 /* delete the playlist */
3919 case RESPONSE_REJECT:
3920 /* keep the playlist */
3932 Editor::audio_region_selection_covers (framepos_t where)
3934 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3935 if ((*a)->region()->covers (where)) {
3944 Editor::prepare_for_cleanup ()
3946 cut_buffer->clear_regions ();
3947 cut_buffer->clear_playlists ();
3949 selection->clear_regions ();
3950 selection->clear_playlists ();
3952 _regions->suspend_redisplay ();
3956 Editor::finish_cleanup ()
3958 _regions->resume_redisplay ();
3962 Editor::transport_loop_location()
3965 return _session->locations()->auto_loop_location();
3972 Editor::transport_punch_location()
3975 return _session->locations()->auto_punch_location();
3982 Editor::control_layout_scroll (GdkEventScroll* ev)
3984 if (Keyboard::some_magic_widget_has_focus()) {
3988 switch (ev->direction) {
3990 scroll_tracks_up_line ();
3994 case GDK_SCROLL_DOWN:
3995 scroll_tracks_down_line ();
3999 /* no left/right handling yet */
4007 Editor::session_state_saved (string)
4010 _snapshots->redisplay ();
4014 Editor::maximise_editing_space ()
4016 _mouse_mode_tearoff->set_visible (false);
4017 _tools_tearoff->set_visible (false);
4018 _zoom_tearoff->set_visible (false);
4020 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
4021 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
4022 pre_maximal_editor_width = this->get_width ();
4023 pre_maximal_editor_height = this->get_height ();
4025 if (post_maximal_horizontal_pane_position == 0) {
4026 post_maximal_horizontal_pane_position = edit_pane.get_width();
4029 if (post_maximal_vertical_pane_position == 0) {
4030 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
4035 if (post_maximal_editor_width) {
4036 edit_pane.set_position (post_maximal_horizontal_pane_position -
4037 abs(post_maximal_editor_width - pre_maximal_editor_width));
4039 edit_pane.set_position (post_maximal_horizontal_pane_position);
4042 if (post_maximal_editor_height) {
4043 editor_summary_pane.set_position (post_maximal_vertical_pane_position -
4044 abs(post_maximal_editor_height - pre_maximal_editor_height));
4046 editor_summary_pane.set_position (post_maximal_vertical_pane_position);
4049 if (Config->get_keep_tearoffs()) {
4050 _mouse_mode_tearoff->set_visible (true);
4051 _tools_tearoff->set_visible (true);
4052 if (Config->get_show_zoom_tools ()) {
4053 _zoom_tearoff->set_visible (true);
4060 Editor::restore_editing_space ()
4062 // user changed width/height of panes during fullscreen
4064 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
4065 post_maximal_horizontal_pane_position = edit_pane.get_position();
4068 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
4069 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
4074 _mouse_mode_tearoff->set_visible (true);
4075 _tools_tearoff->set_visible (true);
4076 if (Config->get_show_zoom_tools ()) {
4077 _zoom_tearoff->set_visible (true);
4079 post_maximal_editor_width = this->get_width();
4080 post_maximal_editor_height = this->get_height();
4082 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
4083 editor_summary_pane.set_position (pre_maximal_vertical_pane_position + abs(this->get_height() - pre_maximal_editor_height));
4087 * Make new playlists for a given track and also any others that belong
4088 * to the same active route group with the `edit' property.
4093 Editor::new_playlists (TimeAxisView* v)
4095 begin_reversible_command (_("new playlists"));
4096 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4097 _session->playlists->get (playlists);
4098 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4099 commit_reversible_command ();
4103 * Use a copy of the current playlist for a given track and also any others that belong
4104 * to the same active route group with the `edit' property.
4109 Editor::copy_playlists (TimeAxisView* v)
4111 begin_reversible_command (_("copy playlists"));
4112 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4113 _session->playlists->get (playlists);
4114 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4115 commit_reversible_command ();
4118 /** Clear the current playlist for a given track and also any others that belong
4119 * to the same active route group with the `edit' property.
4124 Editor::clear_playlists (TimeAxisView* v)
4126 begin_reversible_command (_("clear playlists"));
4127 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4128 _session->playlists->get (playlists);
4129 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4130 commit_reversible_command ();
4134 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4136 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4140 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4142 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4146 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4148 atv.clear_playlist ();
4152 Editor::on_key_press_event (GdkEventKey* ev)
4154 return key_press_focus_accelerator_handler (*this, ev);
4158 Editor::on_key_release_event (GdkEventKey* ev)
4160 return Gtk::Window::on_key_release_event (ev);
4161 // return key_press_focus_accelerator_handler (*this, ev);
4164 /** Queue up a change to the viewport x origin.
4165 * @param frame New x origin.
4168 Editor::reset_x_origin (framepos_t frame)
4170 queue_visual_change (frame);
4174 Editor::reset_y_origin (double y)
4176 queue_visual_change_y (y);
4180 Editor::reset_zoom (double fpu)
4182 queue_visual_change (fpu);
4186 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4188 reset_x_origin (frame);
4191 if (!no_save_visual) {
4192 undo_visual_stack.push_back (current_visual_state(false));
4196 Editor::VisualState*
4197 Editor::current_visual_state (bool with_tracks)
4199 VisualState* vs = new VisualState;
4200 vs->y_position = vertical_adjustment.get_value();
4201 vs->frames_per_unit = frames_per_unit;
4202 vs->leftmost_frame = leftmost_frame;
4203 vs->zoom_focus = zoom_focus;
4206 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4207 vs->track_states.push_back (TAVState ((*i), &(*i)->get_state()));
4215 Editor::undo_visual_state ()
4217 if (undo_visual_stack.empty()) {
4221 redo_visual_stack.push_back (current_visual_state());
4223 VisualState* vs = undo_visual_stack.back();
4224 undo_visual_stack.pop_back();
4225 use_visual_state (*vs);
4229 Editor::redo_visual_state ()
4231 if (redo_visual_stack.empty()) {
4235 undo_visual_stack.push_back (current_visual_state());
4237 VisualState* vs = redo_visual_stack.back();
4238 redo_visual_stack.pop_back();
4239 use_visual_state (*vs);
4243 Editor::swap_visual_state ()
4245 if (undo_visual_stack.empty()) {
4246 redo_visual_state ();
4248 undo_visual_state ();
4253 Editor::use_visual_state (VisualState& vs)
4255 no_save_visual = true;
4257 _routes->suspend_redisplay ();
4259 vertical_adjustment.set_value (vs.y_position);
4261 set_zoom_focus (vs.zoom_focus);
4262 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4264 for (list<TAVState>::iterator i = vs.track_states.begin(); i != vs.track_states.end(); ++i) {
4265 TrackViewList::iterator t;
4267 /* check if the track still exists - it could have been deleted */
4269 if ((t = find (track_views.begin(), track_views.end(), i->first)) != track_views.end()) {
4270 (*t)->set_state (*(i->second), Stateful::loading_state_version);
4275 if (!vs.track_states.empty()) {
4276 _routes->update_visibility ();
4279 _routes->resume_redisplay ();
4281 no_save_visual = false;
4285 Editor::set_frames_per_unit (double fpu)
4287 /* this is the core function that controls the zoom level of the canvas. it is called
4288 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4291 if (fpu == frames_per_unit) {
4300 /* don't allow zooms that fit more than the maximum number
4301 of frames into an 800 pixel wide space.
4304 if (max_framepos / fpu < 800.0) {
4309 tempo_lines->tempo_map_changed();
4311 frames_per_unit = fpu;
4316 Editor::post_zoom ()
4318 // convert fpu to frame count
4320 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4322 if (frames_per_unit != zoom_range_clock.current_duration()) {
4323 zoom_range_clock.set (frames);
4326 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4327 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4328 (*i)->reshow_selection (selection->time);
4332 ZoomChanged (); /* EMIT_SIGNAL */
4334 //reset_scrolling_region ();
4336 if (playhead_cursor) {
4337 playhead_cursor->set_position (playhead_cursor->current_frame);
4340 refresh_location_display();
4341 _summary->set_overlays_dirty ();
4343 update_marker_labels ();
4349 Editor::queue_visual_change (framepos_t where)
4351 pending_visual_change.add (VisualChange::TimeOrigin);
4352 pending_visual_change.time_origin = where;
4353 ensure_visual_change_idle_handler ();
4357 Editor::queue_visual_change (double fpu)
4359 pending_visual_change.add (VisualChange::ZoomLevel);
4360 pending_visual_change.frames_per_unit = fpu;
4362 ensure_visual_change_idle_handler ();
4366 Editor::queue_visual_change_y (double y)
4368 pending_visual_change.add (VisualChange::YOrigin);
4369 pending_visual_change.y_origin = y;
4371 ensure_visual_change_idle_handler ();
4375 Editor::ensure_visual_change_idle_handler ()
4377 if (pending_visual_change.idle_handler_id < 0) {
4378 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4383 Editor::_idle_visual_changer (void* arg)
4385 return static_cast<Editor*>(arg)->idle_visual_changer ();
4389 Editor::idle_visual_changer ()
4391 VisualChange::Type p = pending_visual_change.pending;
4392 pending_visual_change.pending = (VisualChange::Type) 0;
4394 double const last_time_origin = horizontal_position ();
4396 if (p & VisualChange::TimeOrigin) {
4397 /* This is a bit of a hack, but set_frames_per_unit
4398 below will (if called) end up with the
4399 CrossfadeViews looking at Editor::leftmost_frame,
4400 and if we're changing origin and zoom in the same
4401 operation it will be the wrong value unless we
4405 leftmost_frame = pending_visual_change.time_origin;
4408 if (p & VisualChange::ZoomLevel) {
4409 set_frames_per_unit (pending_visual_change.frames_per_unit);
4411 compute_fixed_ruler_scale ();
4412 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4413 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4414 update_tempo_based_rulers ();
4416 if (p & VisualChange::TimeOrigin) {
4417 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4419 if (p & VisualChange::YOrigin) {
4420 vertical_adjustment.set_value (pending_visual_change.y_origin);
4423 if (last_time_origin == horizontal_position ()) {
4424 /* changed signal not emitted */
4425 update_fixed_rulers ();
4426 redisplay_tempo (true);
4429 _summary->set_overlays_dirty ();
4431 pending_visual_change.idle_handler_id = -1;
4432 return 0; /* this is always a one-shot call */
4435 struct EditorOrderTimeAxisSorter {
4436 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4437 return a->order () < b->order ();
4442 Editor::sort_track_selection (TrackViewList* sel)
4444 EditorOrderTimeAxisSorter cmp;
4449 selection->tracks.sort (cmp);
4454 Editor::get_preferred_edit_position (bool ignore_playhead)
4457 framepos_t where = 0;
4458 EditPoint ep = _edit_point;
4460 if (entered_marker) {
4461 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4462 return entered_marker->position();
4465 if (ignore_playhead && ep == EditAtPlayhead) {
4466 ep = EditAtSelectedMarker;
4470 case EditAtPlayhead:
4471 where = _session->audible_frame();
4472 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4475 case EditAtSelectedMarker:
4476 if (!selection->markers.empty()) {
4478 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4481 where = loc->start();
4485 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4493 if (!mouse_frame (where, ignored)) {
4494 /* XXX not right but what can we do ? */
4498 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4506 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4508 if (!_session) return;
4510 begin_reversible_command (cmd);
4514 if ((tll = transport_loop_location()) == 0) {
4515 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4516 XMLNode &before = _session->locations()->get_state();
4517 _session->locations()->add (loc, true);
4518 _session->set_auto_loop_location (loc);
4519 XMLNode &after = _session->locations()->get_state();
4520 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4522 XMLNode &before = tll->get_state();
4523 tll->set_hidden (false, this);
4524 tll->set (start, end);
4525 XMLNode &after = tll->get_state();
4526 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4529 commit_reversible_command ();
4533 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4535 if (!_session) return;
4537 begin_reversible_command (cmd);
4541 if ((tpl = transport_punch_location()) == 0) {
4542 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4543 XMLNode &before = _session->locations()->get_state();
4544 _session->locations()->add (loc, true);
4545 _session->set_auto_loop_location (loc);
4546 XMLNode &after = _session->locations()->get_state();
4547 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4550 XMLNode &before = tpl->get_state();
4551 tpl->set_hidden (false, this);
4552 tpl->set (start, end);
4553 XMLNode &after = tpl->get_state();
4554 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4557 commit_reversible_command ();
4560 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4561 * @param rs List to which found regions are added.
4562 * @param where Time to look at.
4563 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4566 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4568 const TrackViewList* tracks;
4571 tracks = &track_views;
4576 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4578 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4581 boost::shared_ptr<Track> tr;
4582 boost::shared_ptr<Playlist> pl;
4584 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4586 Playlist::RegionList* regions = pl->regions_at (
4587 (framepos_t) floor ( (double) where * tr->speed()));
4589 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4590 RegionView* rv = rtv->view()->find_view (*i);
4603 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4605 const TrackViewList* tracks;
4608 tracks = &track_views;
4613 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4614 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4616 boost::shared_ptr<Track> tr;
4617 boost::shared_ptr<Playlist> pl;
4619 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4621 Playlist::RegionList* regions = pl->regions_touched (
4622 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4624 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4626 RegionView* rv = rtv->view()->find_view (*i);
4639 /** Start with regions that are selected. Then add equivalent regions
4640 * on tracks in the same active edit-enabled route group as any of
4641 * the regions that we started with.
4645 Editor::get_regions_from_selection ()
4647 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4650 /** Get regions using the following method:
4652 * Make an initial region list using the selected regions, unless
4653 * the edit point is `mouse' and the mouse is over an unselected
4654 * region. In this case, start with just that region.
4656 * Then, make an initial track list of the tracks that these
4657 * regions are on, and if the edit point is not `mouse', add the
4660 * Look at this track list and add any other tracks that are on the
4661 * same active edit-enabled route group as one of the initial tracks.
4663 * Finally take the initial region list and add any regions that are
4664 * under the edit point on one of the tracks on the track list to get
4665 * the returned region list.
4667 * The rationale here is that the mouse edit point is special in that
4668 * its position describes both a time and a track; the other edit
4669 * modes only describe a time. Hence if the edit point is `mouse' we
4670 * ignore selected tracks, as we assume the user means something by
4671 * pointing at a particular track. Also in this case we take note of
4672 * the region directly under the edit point, as there is always just one
4673 * (rather than possibly several with non-mouse edit points).
4677 Editor::get_regions_from_selection_and_edit_point ()
4679 RegionSelection regions;
4681 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4682 regions.add (entered_regionview);
4684 regions = selection->regions;
4687 TrackViewList tracks;
4689 if (_edit_point != EditAtMouse) {
4690 tracks = selection->tracks;
4693 /* Add any other tracks that have regions that are in the same
4694 edit-activated route group as one of our regions.
4696 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4698 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4700 if (g && g->is_active() && g->is_edit()) {
4701 tracks.add (axis_views_from_routes (g->route_list()));
4705 if (!tracks.empty()) {
4706 /* now find regions that are at the edit position on those tracks */
4707 framepos_t const where = get_preferred_edit_position ();
4708 get_regions_at (regions, where, tracks);
4714 /** Start with regions that are selected, or the entered regionview if none are selected.
4715 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4716 * of the regions that we started with.
4720 Editor::get_regions_from_selection_and_entered ()
4722 RegionSelection regions = selection->regions;
4724 if (regions.empty() && entered_regionview) {
4725 regions.add (entered_regionview);
4728 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4732 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4734 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4736 RouteTimeAxisView* tatv;
4738 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4740 boost::shared_ptr<Playlist> pl;
4741 vector<boost::shared_ptr<Region> > results;
4743 boost::shared_ptr<Track> tr;
4745 if ((tr = tatv->track()) == 0) {
4750 if ((pl = (tr->playlist())) != 0) {
4751 pl->get_region_list_equivalent_regions (region, results);
4754 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4755 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4756 regions.push_back (marv);
4765 Editor::show_rhythm_ferret ()
4767 if (rhythm_ferret == 0) {
4768 rhythm_ferret = new RhythmFerret(*this);
4771 rhythm_ferret->set_session (_session);
4772 rhythm_ferret->show ();
4773 rhythm_ferret->present ();
4777 Editor::first_idle ()
4779 MessageDialog* dialog = 0;
4781 if (track_views.size() > 1) {
4782 dialog = new MessageDialog (*this,
4783 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4788 ARDOUR_UI::instance()->flush_pending ();
4791 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4795 // first idle adds route children (automation tracks), so we need to redisplay here
4796 _routes->redisplay ();
4804 Editor::_idle_resize (gpointer arg)
4806 return ((Editor*)arg)->idle_resize ();
4810 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4812 if (resize_idle_id < 0) {
4813 resize_idle_id = g_idle_add (_idle_resize, this);
4814 _pending_resize_amount = 0;
4817 /* make a note of the smallest resulting height, so that we can clamp the
4818 lower limit at TimeAxisView::hSmall */
4820 int32_t min_resulting = INT32_MAX;
4822 _pending_resize_amount += h;
4823 _pending_resize_view = view;
4825 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4827 if (selection->tracks.contains (_pending_resize_view)) {
4828 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4829 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4833 if (min_resulting < 0) {
4838 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4839 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4843 /** Handle pending resizing of tracks */
4845 Editor::idle_resize ()
4847 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4849 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4850 selection->tracks.contains (_pending_resize_view)) {
4852 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4853 if (*i != _pending_resize_view) {
4854 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4859 _pending_resize_amount = 0;
4861 _group_tabs->set_dirty ();
4862 resize_idle_id = -1;
4870 ENSURE_GUI_THREAD (*this, &Editor::located);
4872 playhead_cursor->set_position (_session->audible_frame ());
4873 if (_follow_playhead && !_pending_initial_locate) {
4874 reset_x_origin_to_follow_playhead ();
4877 _pending_locate_request = false;
4878 _pending_initial_locate = false;
4882 Editor::region_view_added (RegionView *)
4884 _summary->set_dirty ();
4888 Editor::region_view_removed ()
4890 _summary->set_dirty ();
4894 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4896 TrackViewList::const_iterator j = track_views.begin ();
4897 while (j != track_views.end()) {
4898 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4899 if (rtv && rtv->route() == r) {
4910 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4914 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4915 TimeAxisView* tv = axis_view_from_route (*i);
4926 Editor::handle_new_route (RouteList& routes)
4928 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4930 RouteTimeAxisView *rtv;
4931 list<RouteTimeAxisView*> new_views;
4933 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4934 boost::shared_ptr<Route> route = (*x);
4936 if (route->is_hidden() || route->is_monitor()) {
4940 DataType dt = route->input()->default_type();
4942 if (dt == ARDOUR::DataType::AUDIO) {
4943 rtv = new AudioTimeAxisView (*this, _session, route, *track_canvas);
4944 } else if (dt == ARDOUR::DataType::MIDI) {
4945 rtv = new MidiTimeAxisView (*this, _session, route, *track_canvas);
4947 throw unknown_type();
4950 new_views.push_back (rtv);
4951 track_views.push_back (rtv);
4953 rtv->effective_gain_display ();
4955 if (internal_editing()) {
4956 rtv->enter_internal_edit_mode ();
4958 rtv->leave_internal_edit_mode ();
4961 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4962 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4965 _routes->routes_added (new_views);
4966 _summary->routes_added (new_views);
4968 if (show_editor_mixer_when_tracks_arrive) {
4969 show_editor_mixer (true);
4972 editor_list_button.set_sensitive (true);
4976 Editor::timeaxisview_deleted (TimeAxisView *tv)
4978 if (_session && _session->deletion_in_progress()) {
4979 /* the situation is under control */
4983 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4985 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4987 _routes->route_removed (tv);
4989 if (tv == entered_track) {
4993 TimeAxisView::Children c = tv->get_child_list ();
4994 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4995 if (entered_track == i->get()) {
5000 /* remove it from the list of track views */
5002 TrackViewList::iterator i;
5004 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
5005 i = track_views.erase (i);
5008 /* update whatever the current mixer strip is displaying, if revelant */
5010 boost::shared_ptr<Route> route;
5013 route = rtav->route ();
5016 if (current_mixer_strip && current_mixer_strip->route() == route) {
5018 TimeAxisView* next_tv;
5020 if (track_views.empty()) {
5022 } else if (i == track_views.end()) {
5023 next_tv = track_views.front();
5030 set_selected_mixer_strip (*next_tv);
5032 /* make the editor mixer strip go away setting the
5033 * button to inactive (which also unticks the menu option)
5036 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
5042 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
5044 if (apply_to_selection) {
5045 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
5047 TrackSelection::iterator j = i;
5050 hide_track_in_display (*i, false);
5055 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5057 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5058 // this will hide the mixer strip
5059 set_selected_mixer_strip (*tv);
5062 _routes->hide_track_in_display (*tv);
5067 Editor::sync_track_view_list_and_routes ()
5069 track_views = TrackViewList (_routes->views ());
5071 _summary->set_dirty ();
5072 _group_tabs->set_dirty ();
5074 return false; // do not call again (until needed)
5078 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5080 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5085 /** Find a RouteTimeAxisView by the ID of its route */
5087 Editor::get_route_view_by_route_id (PBD::ID& id) const
5089 RouteTimeAxisView* v;
5091 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5092 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5093 if(v->route()->id() == id) {
5103 Editor::fit_route_group (RouteGroup *g)
5105 TrackViewList ts = axis_views_from_routes (g->route_list ());
5110 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5112 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5115 _session->cancel_audition ();
5119 if (_session->is_auditioning()) {
5120 _session->cancel_audition ();
5121 if (r == last_audition_region) {
5126 _session->audition_region (r);
5127 last_audition_region = r;
5132 Editor::hide_a_region (boost::shared_ptr<Region> r)
5134 r->set_hidden (true);
5138 Editor::show_a_region (boost::shared_ptr<Region> r)
5140 r->set_hidden (false);
5144 Editor::audition_region_from_region_list ()
5146 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5150 Editor::hide_region_from_region_list ()
5152 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5156 Editor::show_region_in_region_list ()
5158 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5162 Editor::step_edit_status_change (bool yn)
5165 start_step_editing ();
5167 stop_step_editing ();
5172 Editor::start_step_editing ()
5174 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5178 Editor::stop_step_editing ()
5180 step_edit_connection.disconnect ();
5184 Editor::check_step_edit ()
5186 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5187 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5189 mtv->check_step_edit ();
5193 return true; // do it again, till we stop
5197 Editor::scroll_press (Direction dir)
5199 ++_scroll_callbacks;
5201 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5202 /* delay the first auto-repeat */
5208 scroll_backward (1);
5216 scroll_tracks_up_line ();
5220 scroll_tracks_down_line ();
5224 /* do hacky auto-repeat */
5225 if (!_scroll_connection.connected ()) {
5227 _scroll_connection = Glib::signal_timeout().connect (
5228 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5231 _scroll_callbacks = 0;
5238 Editor::scroll_release ()
5240 _scroll_connection.disconnect ();
5243 /** Queue a change for the Editor viewport x origin to follow the playhead */
5245 Editor::reset_x_origin_to_follow_playhead ()
5247 framepos_t const frame = playhead_cursor->current_frame;
5249 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5251 if (_session->transport_speed() < 0) {
5253 if (frame > (current_page_frames() / 2)) {
5254 center_screen (frame-(current_page_frames()/2));
5256 center_screen (current_page_frames()/2);
5261 if (frame < leftmost_frame) {
5264 if (_session->transport_rolling()) {
5265 /* rolling; end up with the playhead at the right of the page */
5266 l = frame - current_page_frames ();
5268 /* not rolling: end up with the playhead 3/4 of the way along the page */
5269 l = frame - (3 * current_page_frames() / 4);
5276 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5279 if (_session->transport_rolling()) {
5280 /* rolling: end up with the playhead on the left of the page */
5281 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5283 /* not rolling: end up with the playhead 1/4 of the way along the page */
5284 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5292 Editor::super_rapid_screen_update ()
5294 if (!_session || !_session->engine().running()) {
5298 /* METERING / MIXER STRIPS */
5300 /* update track meters, if required */
5301 if (is_mapped() && meters_running) {
5302 RouteTimeAxisView* rtv;
5303 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5304 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5305 rtv->fast_update ();
5310 /* and any current mixer strip */
5311 if (current_mixer_strip) {
5312 current_mixer_strip->fast_update ();
5315 /* PLAYHEAD AND VIEWPORT */
5317 framepos_t const frame = _session->audible_frame();
5319 /* There are a few reasons why we might not update the playhead / viewport stuff:
5321 * 1. we don't update things when there's a pending locate request, otherwise
5322 * when the editor requests a locate there is a chance that this method
5323 * will move the playhead before the locate request is processed, causing
5325 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5326 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5329 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5331 last_update_frame = frame;
5333 if (!_dragging_playhead) {
5334 playhead_cursor->set_position (frame);
5337 if (!_stationary_playhead) {
5339 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5340 reset_x_origin_to_follow_playhead ();
5345 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5349 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5350 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5351 if (target <= 0.0) {
5354 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5355 target = (target * 0.15) + (current * 0.85);
5361 set_horizontal_position (current);
5370 Editor::session_going_away ()
5372 _have_idled = false;
5374 _session_connections.drop_connections ();
5376 super_rapid_screen_update_connection.disconnect ();
5378 selection->clear ();
5379 cut_buffer->clear ();
5381 clicked_regionview = 0;
5382 clicked_axisview = 0;
5383 clicked_routeview = 0;
5384 clicked_crossfadeview = 0;
5385 entered_regionview = 0;
5387 last_update_frame = 0;
5390 playhead_cursor->canvas_item.hide ();
5392 /* rip everything out of the list displays */
5396 _route_groups->clear ();
5398 /* do this first so that deleting a track doesn't reset cms to null
5399 and thus cause a leak.
5402 if (current_mixer_strip) {
5403 if (current_mixer_strip->get_parent() != 0) {
5404 global_hpacker.remove (*current_mixer_strip);
5406 delete current_mixer_strip;
5407 current_mixer_strip = 0;
5410 /* delete all trackviews */
5412 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5415 track_views.clear ();
5417 zoom_range_clock.set_session (0);
5418 nudge_clock.set_session (0);
5420 editor_list_button.set_active(false);
5421 editor_list_button.set_sensitive(false);
5423 /* clear tempo/meter rulers */
5424 remove_metric_marks ();
5426 clear_marker_display ();
5428 delete current_bbt_points;
5429 current_bbt_points = 0;
5431 /* get rid of any existing editor mixer strip */
5433 WindowTitle title(Glib::get_application_name());
5434 title += _("Editor");
5436 set_title (title.get_string());
5438 SessionHandlePtr::session_going_away ();
5443 Editor::show_editor_list (bool yn)
5446 _the_notebook.show ();
5448 _the_notebook.hide ();
5453 Editor::change_region_layering_order ()
5455 framepos_t const position = get_preferred_edit_position ();
5457 if (!clicked_routeview) {
5458 if (layering_order_editor) {
5459 layering_order_editor->hide ();
5464 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5470 boost::shared_ptr<Playlist> pl = track->playlist();
5476 if (layering_order_editor == 0) {
5477 layering_order_editor = new RegionLayeringOrderEditor(*this);
5480 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5481 layering_order_editor->maybe_present ();
5485 Editor::update_region_layering_order_editor ()
5487 if (layering_order_editor && layering_order_editor->is_visible ()) {
5488 change_region_layering_order ();
5493 Editor::setup_fade_images ()
5495 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5496 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5497 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5498 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5499 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5501 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5502 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5503 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5504 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5505 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5509 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5511 Editor::action_menu_item (std::string const & name)
5513 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5516 return *manage (a->create_menu_item ());
5520 Editor::resize_text_widgets ()
5522 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_FUDGE+10, 15);
5523 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_FUDGE+10, 15);
5524 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_FUDGE+10, 15);
5525 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_FUDGE+10, 15);
5526 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_FUDGE+10, 15);
5530 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5532 EventBox* b = manage (new EventBox);
5533 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5534 Label* l = manage (new Label (name));
5538 _the_notebook.append_page (widget, *b);
5542 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5544 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5545 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5548 if (ev->type == GDK_2BUTTON_PRESS) {
5550 /* double-click on a notebook tab shrinks or expands the notebook */
5552 if (_notebook_shrunk) {
5553 edit_pane.set_position (pre_maximal_horizontal_pane_position);
5554 _notebook_shrunk = false;
5556 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
5557 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5558 _notebook_shrunk = true;