2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
48 #include <glibmm/miscutils.h>
49 #include <gtkmm/image.h>
50 #include <gdkmm/color.h>
51 #include <gdkmm/bitmap.h>
53 #include "gtkmm2ext/bindings.h"
54 #include "gtkmm2ext/grouped_buttons.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/tearoff.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/window_title.h"
59 #include "gtkmm2ext/choice.h"
60 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioengine.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/profile.h"
67 #include "ardour/route_group.h"
68 #include "ardour/session_playlists.h"
69 #include "ardour/tempo.h"
70 #include "ardour/utils.h"
72 #include "control_protocol/control_protocol.h"
76 #include "analysis_window.h"
77 #include "audio_clock.h"
78 #include "audio_region_view.h"
79 #include "audio_streamview.h"
80 #include "audio_time_axis.h"
81 #include "automation_time_axis.h"
82 #include "bundle_manager.h"
83 #include "canvas-noevent-text.h"
84 #include "canvas_impl.h"
85 #include "crossfade_edit.h"
89 #include "editor_cursors.h"
90 #include "editor_drag.h"
91 #include "editor_group_tabs.h"
92 #include "editor_locations.h"
93 #include "editor_regions.h"
94 #include "editor_route_groups.h"
95 #include "editor_routes.h"
96 #include "editor_snapshots.h"
97 #include "editor_summary.h"
98 #include "global_port_matrix.h"
99 #include "gui_object.h"
100 #include "gui_thread.h"
101 #include "keyboard.h"
103 #include "midi_time_axis.h"
104 #include "mixer_strip.h"
105 #include "mixer_ui.h"
106 #include "mouse_cursors.h"
107 #include "playlist_selector.h"
108 #include "public_editor.h"
109 #include "region_layering_order_editor.h"
110 #include "rgb_macros.h"
111 #include "rhythm_ferret.h"
112 #include "selection.h"
114 #include "simpleline.h"
115 #include "tempo_lines.h"
116 #include "time_axis_view.h"
122 #include "imageframe_socket_handler.h"
126 using namespace ARDOUR;
129 using namespace Glib;
130 using namespace Gtkmm2ext;
131 using namespace Editing;
133 using PBD::internationalize;
135 using Gtkmm2ext::Keyboard;
137 const double Editor::timebar_height = 15.0;
139 static const gchar *_snap_type_strings[] = {
141 N_("Timecode Frames"),
142 N_("Timecode Seconds"),
143 N_("Timecode Minutes"),
173 static const gchar *_snap_mode_strings[] = {
180 static const gchar *_edit_point_strings[] = {
187 static const gchar *_zoom_focus_strings[] = {
197 #ifdef USE_RUBBERBAND
198 static const gchar *_rb_opt_strings[] = {
201 N_("Balanced multitimbral mixture"),
202 N_("Unpitched percussion with stable notes"),
203 N_("Crisp monophonic instrumental"),
204 N_("Unpitched solo percussion"),
205 N_("Resample without preserving pitch"),
211 pane_size_watcher (Paned* pane)
213 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
217 Quartz: impossible to access
219 so stop that by preventing it from ever getting too narrow. 35
220 pixels is basically a rough guess at the tab width.
225 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
227 gint pos = pane->get_position ();
229 if (pos > max_width_of_lhs) {
230 pane->set_position (max_width_of_lhs);
235 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
237 /* time display buttons */
238 , minsec_label (_("Mins:Secs"))
239 , bbt_label (_("Bars:Beats"))
240 , timecode_label (_("Timecode"))
241 , samples_label (_("Samples"))
242 , tempo_label (_("Tempo"))
243 , meter_label (_("Meter"))
244 , mark_label (_("Location Markers"))
245 , range_mark_label (_("Range Markers"))
246 , transport_mark_label (_("Loop/Punch Ranges"))
247 , cd_mark_label (_("CD Markers"))
248 , edit_packer (4, 4, true)
250 /* the values here don't matter: layout widgets
251 reset them as needed.
254 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
256 /* tool bar related */
258 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
260 , toolbar_selection_clock_table (2,3)
262 , automation_mode_button (_("mode"))
264 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
267 , image_socket_listener(0)
272 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
273 , meters_running(false)
274 , _pending_locate_request (false)
275 , _pending_initial_locate (false)
276 , _last_cut_copy_source_track (0)
278 , _region_selection_change_updates_region_list (true)
279 , _following_mixer_selection (false)
280 , _control_point_toggled_on_press (false)
281 , _stepping_axis_view (0)
285 /* we are a singleton */
287 PublicEditor::_instance = this;
291 selection = new Selection (this);
292 cut_buffer = new Selection (this);
294 clicked_regionview = 0;
295 clicked_axisview = 0;
296 clicked_routeview = 0;
297 clicked_control_point = 0;
298 last_update_frame = 0;
299 pre_press_cursor = 0;
300 _drags = new DragManager (this);
301 current_mixer_strip = 0;
304 snap_type_strings = I18N (_snap_type_strings);
305 snap_mode_strings = I18N (_snap_mode_strings);
306 zoom_focus_strings = I18N (_zoom_focus_strings);
307 edit_point_strings = I18N (_edit_point_strings);
308 #ifdef USE_RUBBERBAND
309 rb_opt_strings = I18N (_rb_opt_strings);
313 snap_threshold = 5.0;
314 bbt_beat_subdivision = 4;
317 last_autoscroll_x = 0;
318 last_autoscroll_y = 0;
319 autoscroll_active = false;
320 autoscroll_timeout_tag = -1;
325 current_interthread_info = 0;
326 _show_measures = true;
328 show_gain_after_trim = false;
330 have_pending_keyboard_selection = false;
331 _follow_playhead = true;
332 _stationary_playhead = false;
333 editor_ruler_menu = 0;
334 no_ruler_shown_update = false;
336 range_marker_menu = 0;
337 marker_menu_item = 0;
338 tempo_or_meter_marker_menu = 0;
339 transport_marker_menu = 0;
340 new_transport_marker_menu = 0;
341 editor_mixer_strip_width = Wide;
342 show_editor_mixer_when_tracks_arrive = false;
343 region_edit_menu_split_multichannel_item = 0;
344 region_edit_menu_split_item = 0;
347 current_stepping_trackview = 0;
349 entered_regionview = 0;
351 clear_entered_track = false;
354 button_release_can_deselect = true;
355 _dragging_playhead = false;
356 _dragging_edit_point = false;
357 select_new_marker = false;
359 layering_order_editor = 0;
360 no_save_visual = false;
362 within_track_canvas = false;
364 scrubbing_direction = 0;
368 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
369 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
370 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
371 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
372 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
374 _edit_point = EditAtMouse;
375 _internal_editing = false;
376 current_canvas_cursor = 0;
378 frames_per_unit = 2048; /* too early to use reset_zoom () */
380 _scroll_callbacks = 0;
382 zoom_focus = ZoomFocusLeft;
383 set_zoom_focus (ZoomFocusLeft);
384 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
386 bbt_label.set_name ("EditorTimeButton");
387 bbt_label.set_size_request (-1, (int)timebar_height);
388 bbt_label.set_alignment (1.0, 0.5);
389 bbt_label.set_padding (5,0);
391 bbt_label.set_no_show_all();
392 minsec_label.set_name ("EditorTimeButton");
393 minsec_label.set_size_request (-1, (int)timebar_height);
394 minsec_label.set_alignment (1.0, 0.5);
395 minsec_label.set_padding (5,0);
396 minsec_label.hide ();
397 minsec_label.set_no_show_all();
398 timecode_label.set_name ("EditorTimeButton");
399 timecode_label.set_size_request (-1, (int)timebar_height);
400 timecode_label.set_alignment (1.0, 0.5);
401 timecode_label.set_padding (5,0);
402 timecode_label.hide ();
403 timecode_label.set_no_show_all();
404 samples_label.set_name ("EditorTimeButton");
405 samples_label.set_size_request (-1, (int)timebar_height);
406 samples_label.set_alignment (1.0, 0.5);
407 samples_label.set_padding (5,0);
408 samples_label.hide ();
409 samples_label.set_no_show_all();
411 tempo_label.set_name ("EditorTimeButton");
412 tempo_label.set_size_request (-1, (int)timebar_height);
413 tempo_label.set_alignment (1.0, 0.5);
414 tempo_label.set_padding (5,0);
416 tempo_label.set_no_show_all();
418 meter_label.set_name ("EditorTimeButton");
419 meter_label.set_size_request (-1, (int)timebar_height);
420 meter_label.set_alignment (1.0, 0.5);
421 meter_label.set_padding (5,0);
423 meter_label.set_no_show_all();
425 mark_label.set_name ("EditorTimeButton");
426 mark_label.set_size_request (-1, (int)timebar_height);
427 mark_label.set_alignment (1.0, 0.5);
428 mark_label.set_padding (5,0);
430 mark_label.set_no_show_all();
432 cd_mark_label.set_name ("EditorTimeButton");
433 cd_mark_label.set_size_request (-1, (int)timebar_height);
434 cd_mark_label.set_alignment (1.0, 0.5);
435 cd_mark_label.set_padding (5,0);
436 cd_mark_label.hide();
437 cd_mark_label.set_no_show_all();
439 range_mark_label.set_name ("EditorTimeButton");
440 range_mark_label.set_size_request (-1, (int)timebar_height);
441 range_mark_label.set_alignment (1.0, 0.5);
442 range_mark_label.set_padding (5,0);
443 range_mark_label.hide();
444 range_mark_label.set_no_show_all();
446 transport_mark_label.set_name ("EditorTimeButton");
447 transport_mark_label.set_size_request (-1, (int)timebar_height);
448 transport_mark_label.set_alignment (1.0, 0.5);
449 transport_mark_label.set_padding (5,0);
450 transport_mark_label.hide();
451 transport_mark_label.set_no_show_all();
453 initialize_rulers ();
454 initialize_canvas ();
456 _summary = new EditorSummary (this);
458 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
459 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
461 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
463 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
464 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
466 edit_controls_vbox.set_spacing (0);
467 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
468 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
470 HBox* h = manage (new HBox);
471 _group_tabs = new EditorGroupTabs (this);
472 h->pack_start (*_group_tabs, PACK_SHRINK);
473 h->pack_start (edit_controls_vbox);
474 controls_layout.add (*h);
476 controls_layout.set_name ("EditControlsBase");
477 controls_layout.add_events (Gdk::SCROLL_MASK);
478 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
480 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
481 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
483 _cursors = new MouseCursors;
485 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
486 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
487 0.0, 1.0, 100.0, 1.0));
489 pad_line_1->property_color_rgba() = 0xFF0000FF;
494 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
495 time_canvas_vbox.set_size_request (-1, -1);
497 ruler_label_event_box.add (ruler_label_vbox);
498 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
499 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
501 time_button_event_box.add (time_button_vbox);
502 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
503 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
505 /* these enable us to have a dedicated window (for cursor setting, etc.)
506 for the canvas areas.
509 track_canvas_event_box.add (*track_canvas);
511 time_canvas_event_box.add (time_canvas_vbox);
512 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
514 edit_packer.set_col_spacings (0);
515 edit_packer.set_row_spacings (0);
516 edit_packer.set_homogeneous (false);
517 edit_packer.set_border_width (0);
518 edit_packer.set_name ("EditorWindow");
520 /* labels for the rulers */
521 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
522 /* labels for the marker "tracks" */
523 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
525 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
527 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
529 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
531 bottom_hbox.set_border_width (2);
532 bottom_hbox.set_spacing (3);
534 _route_groups = new EditorRouteGroups (this);
535 _routes = new EditorRoutes (this);
536 _regions = new EditorRegions (this);
537 _snapshots = new EditorSnapshots (this);
538 _locations = new EditorLocations (this);
540 add_notebook_page (_("Regions"), _regions->widget ());
541 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
542 add_notebook_page (_("Snapshots"), _snapshots->widget ());
543 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
544 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
546 _the_notebook.set_show_tabs (true);
547 _the_notebook.set_scrollable (true);
548 _the_notebook.popup_disable ();
549 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
550 _the_notebook.show_all ();
552 _notebook_shrunk = false;
554 editor_summary_pane.pack1(edit_packer);
556 Button* summary_arrows_left_left = manage (new Button);
557 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
558 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
559 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
561 Button* summary_arrows_left_right = manage (new Button);
562 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
563 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
564 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
566 VBox* summary_arrows_left = manage (new VBox);
567 summary_arrows_left->pack_start (*summary_arrows_left_left);
568 summary_arrows_left->pack_start (*summary_arrows_left_right);
570 Button* summary_arrows_right_up = manage (new Button);
571 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
572 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
573 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
575 Button* summary_arrows_right_down = manage (new Button);
576 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
577 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
578 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
580 VBox* summary_arrows_right = manage (new VBox);
581 summary_arrows_right->pack_start (*summary_arrows_right_up);
582 summary_arrows_right->pack_start (*summary_arrows_right_down);
584 Frame* summary_frame = manage (new Frame);
585 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
587 summary_frame->add (*_summary);
588 summary_frame->show ();
590 _summary_hbox.pack_start (*summary_arrows_left, false, false);
591 _summary_hbox.pack_start (*summary_frame, true, true);
592 _summary_hbox.pack_start (*summary_arrows_right, false, false);
594 editor_summary_pane.pack2 (_summary_hbox);
596 edit_pane.pack1 (editor_summary_pane, true, true);
597 edit_pane.pack2 (_the_notebook, false, true);
599 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
601 /* XXX: editor_summary_pane might need similar to the edit_pane */
603 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
605 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
606 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
608 top_hbox.pack_start (toolbar_frame);
610 HBox *hbox = manage (new HBox);
611 hbox->pack_start (edit_pane, true, true);
613 global_vpacker.pack_start (top_hbox, false, false);
614 global_vpacker.pack_start (*hbox, true, true);
616 global_hpacker.pack_start (global_vpacker, true, true);
618 set_name ("EditorWindow");
619 add_accel_group (ActionManager::ui_manager->get_accel_group());
621 status_bar_hpacker.show ();
623 vpacker.pack_end (status_bar_hpacker, false, false);
624 vpacker.pack_end (global_hpacker, true, true);
626 /* register actions now so that set_state() can find them and set toggles/checks etc */
629 /* when we start using our own keybinding system for the editor, this
630 * will be uncommented
636 _snap_type = SnapToBeat;
637 set_snap_to (_snap_type);
638 _snap_mode = SnapOff;
639 set_snap_mode (_snap_mode);
640 set_mouse_mode (MouseObject, true);
641 pre_internal_mouse_mode = MouseObject;
642 pre_internal_snap_type = _snap_type;
643 pre_internal_snap_mode = _snap_mode;
644 internal_snap_type = _snap_type;
645 internal_snap_mode = _snap_mode;
646 set_edit_point_preference (EditAtMouse, true);
648 _playlist_selector = new PlaylistSelector();
649 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
651 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
655 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
656 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
658 nudge_forward_button.set_name ("TransportButton");
659 nudge_backward_button.set_name ("TransportButton");
661 fade_context_menu.set_name ("ArdourContextMenu");
663 /* icons, titles, WM stuff */
665 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
666 Glib::RefPtr<Gdk::Pixbuf> icon;
668 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
669 window_icons.push_back (icon);
671 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
672 window_icons.push_back (icon);
674 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
678 window_icons.push_back (icon);
680 if (!window_icons.empty()) {
681 // set_icon_list (window_icons);
682 set_default_icon_list (window_icons);
685 WindowTitle title(Glib::get_application_name());
686 title += _("Editor");
687 set_title (title.get_string());
688 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
691 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
693 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
694 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
696 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
698 /* allow external control surfaces/protocols to do various things */
700 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
701 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
702 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
703 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
704 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
705 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
706 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
707 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
708 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
709 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
710 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
711 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
712 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
713 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
715 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
716 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
717 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
718 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
719 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
721 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
723 /* problematic: has to return a value and thus cannot be x-thread */
725 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
727 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
729 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
731 _ignore_region_action = false;
732 _last_region_menu_was_main = false;
733 _popup_region_menu_item = 0;
735 _show_marker_lines = false;
736 _over_region_trim_target = false;
738 /* Button bindings */
740 button_bindings = new Bindings;
742 XMLNode* node = button_settings();
744 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
745 button_bindings->load (**i);
752 setup_fade_images ();
758 if(image_socket_listener) {
759 if(image_socket_listener->is_connected())
761 image_socket_listener->close_connection() ;
764 delete image_socket_listener ;
765 image_socket_listener = 0 ;
769 delete button_bindings;
771 delete _route_groups;
777 Editor::button_settings () const
779 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
780 XMLNode* node = find_named_node (*settings, X_("Buttons"));
783 node = new XMLNode (X_("Buttons"));
790 Editor::add_toplevel_controls (Container& cont)
792 vpacker.pack_start (cont, false, false);
797 Editor::get_smart_mode () const
799 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
803 Editor::catch_vanishing_regionview (RegionView *rv)
805 /* note: the selection will take care of the vanishing
806 audioregionview by itself.
809 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
813 if (clicked_regionview == rv) {
814 clicked_regionview = 0;
817 if (entered_regionview == rv) {
818 set_entered_regionview (0);
821 if (!_all_region_actions_sensitized) {
822 sensitize_all_region_actions (true);
825 _over_region_trim_target = false;
829 Editor::set_entered_regionview (RegionView* rv)
831 if (rv == entered_regionview) {
835 if (entered_regionview) {
836 entered_regionview->exited ();
839 if ((entered_regionview = rv) != 0) {
840 entered_regionview->entered (internal_editing ());
843 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
844 /* This RegionView entry might have changed what region actions
845 are allowed, so sensitize them all in case a key is pressed.
847 sensitize_all_region_actions (true);
852 Editor::set_entered_track (TimeAxisView* tav)
855 entered_track->exited ();
858 if ((entered_track = tav) != 0) {
859 entered_track->entered ();
864 Editor::show_window ()
866 if (!is_visible ()) {
869 /* XXX: this is a bit unfortunate; it would probably
870 be nicer if we could just call show () above rather
871 than needing the show_all ()
874 /* re-hide stuff if necessary */
875 editor_list_button_toggled ();
876 parameter_changed ("show-summary");
877 parameter_changed ("show-group-tabs");
878 parameter_changed ("show-zoom-tools");
880 /* now reset all audio_time_axis heights, because widgets might need
886 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
887 tv = (static_cast<TimeAxisView*>(*i));
891 if (current_mixer_strip) {
892 current_mixer_strip->hide_things ();
893 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
901 Editor::instant_save ()
903 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
908 _session->add_instant_xml(get_state());
910 Config->add_instant_xml(get_state());
915 Editor::zoom_adjustment_changed ()
921 double fpu = zoom_range_clock->current_duration() / _canvas_width;
922 bool clamped = clamp_frames_per_unit (fpu);
925 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
932 Editor::control_vertical_zoom_in_all ()
934 tav_zoom_smooth (false, true);
938 Editor::control_vertical_zoom_out_all ()
940 tav_zoom_smooth (true, true);
944 Editor::control_vertical_zoom_in_selected ()
946 tav_zoom_smooth (false, false);
950 Editor::control_vertical_zoom_out_selected ()
952 tav_zoom_smooth (true, false);
956 Editor::control_view (uint32_t view)
958 goto_visual_state (view);
962 Editor::control_unselect ()
964 selection->clear_tracks ();
968 Editor::control_select (uint32_t rid, Selection::Operation op)
970 /* handles the (static) signal from the ControlProtocol class that
971 * requests setting the selected track to a given RID
978 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
984 TimeAxisView* tav = axis_view_from_route (r);
989 selection->add (tav);
991 case Selection::Toggle:
992 selection->toggle (tav);
994 case Selection::Extend:
997 selection->set (tav);
1001 selection->clear_tracks ();
1006 Editor::control_step_tracks_up ()
1008 scroll_tracks_up_line ();
1012 Editor::control_step_tracks_down ()
1014 scroll_tracks_down_line ();
1018 Editor::control_scroll (float fraction)
1020 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1026 double step = fraction * current_page_frames();
1029 _control_scroll_target is an optional<T>
1031 it acts like a pointer to an framepos_t, with
1032 a operator conversion to boolean to check
1033 that it has a value could possibly use
1034 playhead_cursor->current_frame to store the
1035 value and a boolean in the class to know
1036 when it's out of date
1039 if (!_control_scroll_target) {
1040 _control_scroll_target = _session->transport_frame();
1041 _dragging_playhead = true;
1044 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1045 *_control_scroll_target = 0;
1046 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1047 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1049 *_control_scroll_target += (framepos_t) floor (step);
1052 /* move visuals, we'll catch up with it later */
1054 playhead_cursor->set_position (*_control_scroll_target);
1055 UpdateAllTransportClocks (*_control_scroll_target);
1057 if (*_control_scroll_target > (current_page_frames() / 2)) {
1058 /* try to center PH in window */
1059 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1065 Now we do a timeout to actually bring the session to the right place
1066 according to the playhead. This is to avoid reading disk buffers on every
1067 call to control_scroll, which is driven by ScrollTimeline and therefore
1068 probably by a control surface wheel which can generate lots of events.
1070 /* cancel the existing timeout */
1072 control_scroll_connection.disconnect ();
1074 /* add the next timeout */
1076 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1080 Editor::deferred_control_scroll (framepos_t /*target*/)
1082 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1083 // reset for next stream
1084 _control_scroll_target = boost::none;
1085 _dragging_playhead = false;
1090 Editor::access_action (std::string action_group, std::string action_item)
1096 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1099 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1107 Editor::on_realize ()
1109 Window::on_realize ();
1114 Editor::map_position_change (framepos_t frame)
1116 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1118 if (_session == 0) {
1122 if (_follow_playhead) {
1123 center_screen (frame);
1126 playhead_cursor->set_position (frame);
1130 Editor::center_screen (framepos_t frame)
1132 double page = _canvas_width * frames_per_unit;
1134 /* if we're off the page, then scroll.
1137 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1138 center_screen_internal (frame, page);
1143 Editor::center_screen_internal (framepos_t frame, float page)
1148 frame -= (framepos_t) page;
1153 reset_x_origin (frame);
1158 Editor::update_title ()
1160 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1163 bool dirty = _session->dirty();
1165 string session_name;
1167 if (_session->snap_name() != _session->name()) {
1168 session_name = _session->snap_name();
1170 session_name = _session->name();
1174 session_name = "*" + session_name;
1177 WindowTitle title(session_name);
1178 title += Glib::get_application_name();
1179 set_title (title.get_string());
1181 /* ::session_going_away() will have taken care of it */
1186 Editor::set_session (Session *t)
1188 SessionHandlePtr::set_session (t);
1194 zoom_range_clock->set_session (_session);
1195 _playlist_selector->set_session (_session);
1196 nudge_clock->set_session (_session);
1197 _summary->set_session (_session);
1198 _group_tabs->set_session (_session);
1199 _route_groups->set_session (_session);
1200 _regions->set_session (_session);
1201 _snapshots->set_session (_session);
1202 _routes->set_session (_session);
1203 _locations->set_session (_session);
1205 if (rhythm_ferret) {
1206 rhythm_ferret->set_session (_session);
1209 if (analysis_window) {
1210 analysis_window->set_session (_session);
1214 sfbrowser->set_session (_session);
1217 compute_fixed_ruler_scale ();
1219 /* Make sure we have auto loop and auto punch ranges */
1221 Location* loc = _session->locations()->auto_loop_location();
1223 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1225 if (loc->start() == loc->end()) {
1226 loc->set_end (loc->start() + 1);
1229 _session->locations()->add (loc, false);
1230 _session->set_auto_loop_location (loc);
1233 loc->set_name (_("Loop"));
1236 loc = _session->locations()->auto_punch_location();
1239 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1241 if (loc->start() == loc->end()) {
1242 loc->set_end (loc->start() + 1);
1245 _session->locations()->add (loc, false);
1246 _session->set_auto_punch_location (loc);
1249 loc->set_name (_("Punch"));
1252 refresh_location_display ();
1254 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1255 the selected Marker; this needs the LocationMarker list to be available.
1257 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1258 set_state (*node, Stateful::loading_state_version);
1260 /* catch up with the playhead */
1262 _session->request_locate (playhead_cursor->current_frame);
1263 _pending_initial_locate = true;
1267 /* These signals can all be emitted by a non-GUI thread. Therefore the
1268 handlers for them must not attempt to directly interact with the GUI,
1269 but use Gtkmm2ext::UI::instance()->call_slot();
1272 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1273 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1274 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1275 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1276 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1277 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1278 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1279 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1280 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1281 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1282 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1283 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1284 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1285 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1287 playhead_cursor->canvas_item.show ();
1289 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1290 Config->map_parameters (pc);
1291 _session->config.map_parameters (pc);
1293 restore_ruler_visibility ();
1294 //tempo_map_changed (PropertyChange (0));
1295 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1297 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1298 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1301 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1302 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1305 switch (_snap_type) {
1306 case SnapToRegionStart:
1307 case SnapToRegionEnd:
1308 case SnapToRegionSync:
1309 case SnapToRegionBoundary:
1310 build_region_boundary_cache ();
1317 /* register for undo history */
1318 _session->register_with_memento_command_factory(id(), this);
1320 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1322 start_updating_meters ();
1326 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1328 if (a->get_name() == "RegionMenu") {
1329 /* When the main menu's region menu is opened, we setup the actions so that they look right
1330 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1331 so we resensitize all region actions when the entered regionview or the region selection
1332 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1333 happens after the region context menu is opened. So we set a flag here, too.
1337 sensitize_the_right_region_actions ();
1338 _last_region_menu_was_main = true;
1343 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1345 using namespace Menu_Helpers;
1347 void (Editor::*emf)(FadeShape);
1348 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1351 images = &_xfade_in_images;
1352 emf = &Editor::set_fade_in_shape;
1354 images = &_xfade_out_images;
1355 emf = &Editor::set_fade_out_shape;
1360 _("Linear (for highly correlated material)"),
1361 *(*images)[FadeLinear],
1362 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1366 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1371 *(*images)[FadeConstantPower],
1372 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1375 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1380 *(*images)[FadeSymmetric],
1381 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1385 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1390 *(*images)[FadeSlow],
1391 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1394 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1399 *(*images)[FadeFast],
1400 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1403 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1406 /** Pop up a context menu for when the user clicks on a start crossfade */
1408 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1410 using namespace Menu_Helpers;
1412 MenuList& items (xfade_in_context_menu.items());
1414 if (items.empty()) {
1415 fill_xfade_menu (items, true);
1418 xfade_in_context_menu.popup (button, time);
1421 /** Pop up a context menu for when the user clicks on an end crossfade */
1423 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1425 using namespace Menu_Helpers;
1427 MenuList& items (xfade_out_context_menu.items());
1429 if (items.empty()) {
1430 fill_xfade_menu (items, false);
1433 xfade_out_context_menu.popup (button, time);
1437 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1439 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1441 using namespace Menu_Helpers;
1442 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1445 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1449 MenuList& items (fade_context_menu.items());
1452 switch (item_type) {
1454 case FadeInHandleItem:
1455 if (arv->audio_region()->fade_in_active()) {
1456 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1458 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1461 items.push_back (SeparatorElem());
1463 if (Profile->get_sae()) {
1465 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1466 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1473 *_fade_in_images[FadeLinear],
1474 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1478 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1483 *_fade_in_images[FadeSlow],
1484 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1487 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1492 *_fade_in_images[FadeFast],
1493 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1496 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1501 *_fade_in_images[FadeSymmetric],
1502 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1507 _("Constant Power"),
1508 *_fade_in_images[FadeConstantPower],
1509 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1512 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1518 case FadeOutHandleItem:
1519 if (arv->audio_region()->fade_out_active()) {
1520 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1522 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1525 items.push_back (SeparatorElem());
1527 if (Profile->get_sae()) {
1528 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1529 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1535 *_fade_out_images[FadeLinear],
1536 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1540 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1545 *_fade_out_images[FadeSlow],
1546 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1549 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1554 *_fade_out_images[FadeFast],
1555 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1558 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1563 *_fade_out_images[FadeSymmetric],
1564 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1569 _("Constant Power"),
1570 *_fade_out_images[FadeConstantPower],
1571 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1574 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1580 fatal << _("programming error: ")
1581 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1586 fade_context_menu.popup (button, time);
1590 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1592 using namespace Menu_Helpers;
1593 Menu* (Editor::*build_menu_function)();
1596 switch (item_type) {
1598 case RegionViewName:
1599 case RegionViewNameHighlight:
1600 case LeftFrameHandle:
1601 case RightFrameHandle:
1602 if (with_selection) {
1603 build_menu_function = &Editor::build_track_selection_context_menu;
1605 build_menu_function = &Editor::build_track_region_context_menu;
1610 if (with_selection) {
1611 build_menu_function = &Editor::build_track_selection_context_menu;
1613 build_menu_function = &Editor::build_track_context_menu;
1618 if (clicked_routeview->track()) {
1619 build_menu_function = &Editor::build_track_context_menu;
1621 build_menu_function = &Editor::build_track_bus_context_menu;
1626 /* probably shouldn't happen but if it does, we don't care */
1630 menu = (this->*build_menu_function)();
1631 menu->set_name ("ArdourContextMenu");
1633 /* now handle specific situations */
1635 switch (item_type) {
1637 case RegionViewName:
1638 case RegionViewNameHighlight:
1639 case LeftFrameHandle:
1640 case RightFrameHandle:
1641 if (!with_selection) {
1642 if (region_edit_menu_split_item) {
1643 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1644 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1646 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1649 if (region_edit_menu_split_multichannel_item) {
1650 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1651 region_edit_menu_split_multichannel_item->set_sensitive (true);
1653 region_edit_menu_split_multichannel_item->set_sensitive (false);
1666 /* probably shouldn't happen but if it does, we don't care */
1670 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1672 /* Bounce to disk */
1674 using namespace Menu_Helpers;
1675 MenuList& edit_items = menu->items();
1677 edit_items.push_back (SeparatorElem());
1679 switch (clicked_routeview->audio_track()->freeze_state()) {
1680 case AudioTrack::NoFreeze:
1681 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1684 case AudioTrack::Frozen:
1685 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1688 case AudioTrack::UnFrozen:
1689 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1695 if (item_type == StreamItem && clicked_routeview) {
1696 clicked_routeview->build_underlay_menu(menu);
1699 /* When the region menu is opened, we setup the actions so that they look right
1702 sensitize_the_right_region_actions ();
1703 _last_region_menu_was_main = false;
1705 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1706 menu->popup (button, time);
1710 Editor::build_track_context_menu ()
1712 using namespace Menu_Helpers;
1714 MenuList& edit_items = track_context_menu.items();
1717 add_dstream_context_items (edit_items);
1718 return &track_context_menu;
1722 Editor::build_track_bus_context_menu ()
1724 using namespace Menu_Helpers;
1726 MenuList& edit_items = track_context_menu.items();
1729 add_bus_context_items (edit_items);
1730 return &track_context_menu;
1734 Editor::build_track_region_context_menu ()
1736 using namespace Menu_Helpers;
1737 MenuList& edit_items = track_region_context_menu.items();
1740 /* we've just cleared the track region context menu, so the menu that these
1741 two items were on will have disappeared; stop them dangling.
1743 region_edit_menu_split_item = 0;
1744 region_edit_menu_split_multichannel_item = 0;
1746 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1749 boost::shared_ptr<Track> tr;
1750 boost::shared_ptr<Playlist> pl;
1752 if ((tr = rtv->track())) {
1753 add_region_context_items (edit_items, tr);
1757 add_dstream_context_items (edit_items);
1759 return &track_region_context_menu;
1763 Editor::analyze_region_selection ()
1765 if (analysis_window == 0) {
1766 analysis_window = new AnalysisWindow();
1769 analysis_window->set_session(_session);
1771 analysis_window->show_all();
1774 analysis_window->set_regionmode();
1775 analysis_window->analyze();
1777 analysis_window->present();
1781 Editor::analyze_range_selection()
1783 if (analysis_window == 0) {
1784 analysis_window = new AnalysisWindow();
1787 analysis_window->set_session(_session);
1789 analysis_window->show_all();
1792 analysis_window->set_rangemode();
1793 analysis_window->analyze();
1795 analysis_window->present();
1799 Editor::build_track_selection_context_menu ()
1801 using namespace Menu_Helpers;
1802 MenuList& edit_items = track_selection_context_menu.items();
1803 edit_items.clear ();
1805 add_selection_context_items (edit_items);
1806 // edit_items.push_back (SeparatorElem());
1807 // add_dstream_context_items (edit_items);
1809 return &track_selection_context_menu;
1813 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1815 using namespace Menu_Helpers;
1817 /* OK, stick the region submenu at the top of the list, and then add
1821 RegionSelection rs = get_regions_from_selection_and_entered ();
1823 string::size_type pos = 0;
1824 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1826 /* we have to hack up the region name because "_" has a special
1827 meaning for menu titles.
1830 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1831 menu_item_name.replace (pos, 1, "__");
1835 if (_popup_region_menu_item == 0) {
1836 _popup_region_menu_item = new MenuItem (menu_item_name);
1837 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1838 _popup_region_menu_item->show ();
1840 _popup_region_menu_item->set_label (menu_item_name);
1843 const framepos_t position = get_preferred_edit_position (false, true);
1845 edit_items.push_back (*_popup_region_menu_item);
1846 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1847 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1849 edit_items.push_back (SeparatorElem());
1852 /** Add context menu items relevant to selection ranges.
1853 * @param edit_items List to add the items to.
1856 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1858 using namespace Menu_Helpers;
1860 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1861 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1863 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1866 edit_items.push_back (SeparatorElem());
1868 edit_items.push_back (
1870 _("Move Range Start to Previous Region Boundary"),
1871 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1875 edit_items.push_back (
1877 _("Move Range Start to Next Region Boundary"),
1878 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1882 edit_items.push_back (
1884 _("Move Range End to Previous Region Boundary"),
1885 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1889 edit_items.push_back (
1891 _("Move Range End to Next Region Boundary"),
1892 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1898 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1900 edit_items.push_back (SeparatorElem());
1901 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1905 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1907 edit_items.push_back (SeparatorElem());
1908 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1910 edit_items.push_back (SeparatorElem());
1911 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1912 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1913 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1915 edit_items.push_back (SeparatorElem());
1916 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1917 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1918 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1919 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1920 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1925 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1927 using namespace Menu_Helpers;
1931 Menu *play_menu = manage (new Menu);
1932 MenuList& play_items = play_menu->items();
1933 play_menu->set_name ("ArdourContextMenu");
1935 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1936 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1937 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1938 play_items.push_back (SeparatorElem());
1939 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1941 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1945 Menu *select_menu = manage (new Menu);
1946 MenuList& select_items = select_menu->items();
1947 select_menu->set_name ("ArdourContextMenu");
1949 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1950 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1951 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1952 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1953 select_items.push_back (SeparatorElem());
1954 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1955 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1956 select_items.push_back (SeparatorElem());
1957 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1958 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1959 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1960 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1961 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1962 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1963 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1965 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1969 Menu *cutnpaste_menu = manage (new Menu);
1970 MenuList& cutnpaste_items = cutnpaste_menu->items();
1971 cutnpaste_menu->set_name ("ArdourContextMenu");
1973 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1974 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1975 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1977 cutnpaste_items.push_back (SeparatorElem());
1979 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1980 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1982 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1984 /* Adding new material */
1986 edit_items.push_back (SeparatorElem());
1987 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1988 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1992 Menu *nudge_menu = manage (new Menu());
1993 MenuList& nudge_items = nudge_menu->items();
1994 nudge_menu->set_name ("ArdourContextMenu");
1996 edit_items.push_back (SeparatorElem());
1997 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1998 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1999 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2000 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2002 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2006 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2008 using namespace Menu_Helpers;
2012 Menu *play_menu = manage (new Menu);
2013 MenuList& play_items = play_menu->items();
2014 play_menu->set_name ("ArdourContextMenu");
2016 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2017 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2018 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2022 Menu *select_menu = manage (new Menu);
2023 MenuList& select_items = select_menu->items();
2024 select_menu->set_name ("ArdourContextMenu");
2026 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2027 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2028 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2029 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2030 select_items.push_back (SeparatorElem());
2031 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2032 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2033 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2034 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2036 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2040 Menu *cutnpaste_menu = manage (new Menu);
2041 MenuList& cutnpaste_items = cutnpaste_menu->items();
2042 cutnpaste_menu->set_name ("ArdourContextMenu");
2044 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2045 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2046 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2048 Menu *nudge_menu = manage (new Menu());
2049 MenuList& nudge_items = nudge_menu->items();
2050 nudge_menu->set_name ("ArdourContextMenu");
2052 edit_items.push_back (SeparatorElem());
2053 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2054 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2055 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2056 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2058 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2062 Editor::snap_type() const
2068 Editor::snap_mode() const
2074 Editor::set_snap_to (SnapType st)
2076 unsigned int snap_ind = (unsigned int)st;
2080 if (snap_ind > snap_type_strings.size() - 1) {
2082 _snap_type = (SnapType)snap_ind;
2085 string str = snap_type_strings[snap_ind];
2087 if (str != snap_type_selector.get_active_text()) {
2088 snap_type_selector.set_active_text (str);
2093 switch (_snap_type) {
2094 case SnapToBeatDiv128:
2095 case SnapToBeatDiv64:
2096 case SnapToBeatDiv32:
2097 case SnapToBeatDiv28:
2098 case SnapToBeatDiv24:
2099 case SnapToBeatDiv20:
2100 case SnapToBeatDiv16:
2101 case SnapToBeatDiv14:
2102 case SnapToBeatDiv12:
2103 case SnapToBeatDiv10:
2104 case SnapToBeatDiv8:
2105 case SnapToBeatDiv7:
2106 case SnapToBeatDiv6:
2107 case SnapToBeatDiv5:
2108 case SnapToBeatDiv4:
2109 case SnapToBeatDiv3:
2110 case SnapToBeatDiv2:
2111 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2112 update_tempo_based_rulers ();
2115 case SnapToRegionStart:
2116 case SnapToRegionEnd:
2117 case SnapToRegionSync:
2118 case SnapToRegionBoundary:
2119 build_region_boundary_cache ();
2127 SnapChanged (); /* EMIT SIGNAL */
2131 Editor::set_snap_mode (SnapMode mode)
2134 string str = snap_mode_strings[(int)mode];
2136 if (str != snap_mode_selector.get_active_text ()) {
2137 snap_mode_selector.set_active_text (str);
2143 Editor::set_edit_point_preference (EditPoint ep, bool force)
2145 bool changed = (_edit_point != ep);
2148 string str = edit_point_strings[(int)ep];
2150 if (str != edit_point_selector.get_active_text ()) {
2151 edit_point_selector.set_active_text (str);
2154 set_canvas_cursor ();
2156 if (!force && !changed) {
2160 const char* action=NULL;
2162 switch (_edit_point) {
2163 case EditAtPlayhead:
2164 action = "edit-at-playhead";
2166 case EditAtSelectedMarker:
2167 action = "edit-at-marker";
2170 action = "edit-at-mouse";
2174 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2176 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2180 bool in_track_canvas;
2182 if (!mouse_frame (foo, in_track_canvas)) {
2183 in_track_canvas = false;
2186 reset_canvas_action_sensitivity (in_track_canvas);
2192 Editor::set_state (const XMLNode& node, int /*version*/)
2194 const XMLProperty* prop;
2201 g.base_width = default_width;
2202 g.base_height = default_height;
2206 if ((geometry = find_named_node (node, "geometry")) != 0) {
2210 if ((prop = geometry->property("x_size")) == 0) {
2211 prop = geometry->property ("x-size");
2214 g.base_width = atoi(prop->value());
2216 if ((prop = geometry->property("y_size")) == 0) {
2217 prop = geometry->property ("y-size");
2220 g.base_height = atoi(prop->value());
2223 if ((prop = geometry->property ("x_pos")) == 0) {
2224 prop = geometry->property ("x-pos");
2227 x = atoi (prop->value());
2230 if ((prop = geometry->property ("y_pos")) == 0) {
2231 prop = geometry->property ("y-pos");
2234 y = atoi (prop->value());
2238 set_default_size (g.base_width, g.base_height);
2241 if (_session && (prop = node.property ("playhead"))) {
2243 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2244 playhead_cursor->set_position (pos);
2246 playhead_cursor->set_position (0);
2249 if ((prop = node.property ("mixer-width"))) {
2250 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2253 if ((prop = node.property ("zoom-focus"))) {
2254 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2257 if ((prop = node.property ("zoom"))) {
2258 reset_zoom (PBD::atof (prop->value()));
2260 reset_zoom (frames_per_unit);
2263 if ((prop = node.property ("snap-to"))) {
2264 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2267 if ((prop = node.property ("snap-mode"))) {
2268 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2271 if ((prop = node.property ("internal-snap-to"))) {
2272 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2275 if ((prop = node.property ("internal-snap-mode"))) {
2276 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2279 if ((prop = node.property ("pre-internal-snap-to"))) {
2280 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2283 if ((prop = node.property ("pre-internal-snap-mode"))) {
2284 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2287 if ((prop = node.property ("mouse-mode"))) {
2288 MouseMode m = str2mousemode(prop->value());
2289 set_mouse_mode (m, true);
2291 set_mouse_mode (MouseObject, true);
2294 if ((prop = node.property ("left-frame")) != 0) {
2296 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2300 reset_x_origin (pos);
2304 if ((prop = node.property ("y-origin")) != 0) {
2305 reset_y_origin (atof (prop->value ()));
2308 if ((prop = node.property ("internal-edit"))) {
2309 bool yn = string_is_affirmative (prop->value());
2310 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2312 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2313 tact->set_active (!yn);
2314 tact->set_active (yn);
2318 if ((prop = node.property ("join-object-range"))) {
2319 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2321 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2322 tact->set_active (!yn);
2323 tact->set_active (yn);
2325 set_mouse_mode(mouse_mode, true);
2328 if ((prop = node.property ("edit-point"))) {
2329 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2332 if ((prop = node.property ("show-measures"))) {
2333 bool yn = string_is_affirmative (prop->value());
2334 _show_measures = yn;
2335 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2337 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2338 /* do it twice to force the change */
2339 tact->set_active (!yn);
2340 tact->set_active (yn);
2344 if ((prop = node.property ("follow-playhead"))) {
2345 bool yn = string_is_affirmative (prop->value());
2346 set_follow_playhead (yn);
2347 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2349 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2350 if (tact->get_active() != yn) {
2351 tact->set_active (yn);
2356 if ((prop = node.property ("stationary-playhead"))) {
2357 bool yn = string_is_affirmative (prop->value());
2358 set_stationary_playhead (yn);
2359 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2361 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2362 if (tact->get_active() != yn) {
2363 tact->set_active (yn);
2368 if ((prop = node.property ("region-list-sort-type"))) {
2369 RegionListSortType st;
2370 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2373 if ((prop = node.property ("show-editor-mixer"))) {
2375 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2378 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2379 bool yn = string_is_affirmative (prop->value());
2381 /* do it twice to force the change */
2383 tact->set_active (!yn);
2384 tact->set_active (yn);
2387 if ((prop = node.property ("show-editor-list"))) {
2389 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2392 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2393 bool yn = string_is_affirmative (prop->value());
2395 /* do it twice to force the change */
2397 tact->set_active (!yn);
2398 tact->set_active (yn);
2401 if ((prop = node.property (X_("editor-list-page")))) {
2402 _the_notebook.set_current_page (atoi (prop->value ()));
2405 if ((prop = node.property (X_("show-marker-lines")))) {
2406 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2408 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2409 bool yn = string_is_affirmative (prop->value ());
2411 tact->set_active (!yn);
2412 tact->set_active (yn);
2415 XMLNodeList children = node.children ();
2416 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2417 selection->set_state (**i, Stateful::current_state_version);
2418 _regions->set_state (**i);
2421 if ((prop = node.property ("maximised"))) {
2422 bool yn = string_is_affirmative (prop->value());
2424 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2428 if ((prop = node.property ("nudge-clock-value"))) {
2430 sscanf (prop->value().c_str(), "%" PRId64, &f);
2431 nudge_clock->set (f);
2433 nudge_clock->set_mode (AudioClock::Timecode);
2434 nudge_clock->set (_session->frame_rate() * 5, true);
2441 Editor::get_state ()
2443 XMLNode* node = new XMLNode ("Editor");
2446 id().print (buf, sizeof (buf));
2447 node->add_property ("id", buf);
2449 if (is_realized()) {
2450 Glib::RefPtr<Gdk::Window> win = get_window();
2452 int x, y, width, height;
2453 win->get_root_origin(x, y);
2454 win->get_size(width, height);
2456 XMLNode* geometry = new XMLNode ("geometry");
2458 snprintf(buf, sizeof(buf), "%d", width);
2459 geometry->add_property("x-size", string(buf));
2460 snprintf(buf, sizeof(buf), "%d", height);
2461 geometry->add_property("y-size", string(buf));
2462 snprintf(buf, sizeof(buf), "%d", x);
2463 geometry->add_property("x-pos", string(buf));
2464 snprintf(buf, sizeof(buf), "%d", y);
2465 geometry->add_property("y-pos", string(buf));
2466 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2467 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2468 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2469 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2470 geometry->add_property("edit-vertical-pane-pos", string(buf));
2472 node->add_child_nocopy (*geometry);
2475 maybe_add_mixer_strip_width (*node);
2477 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2478 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2479 node->add_property ("zoom", buf);
2480 node->add_property ("snap-to", enum_2_string (_snap_type));
2481 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2482 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2483 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2484 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2485 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2486 node->add_property ("edit-point", enum_2_string (_edit_point));
2488 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2489 node->add_property ("playhead", buf);
2490 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2491 node->add_property ("left-frame", buf);
2492 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2493 node->add_property ("y-origin", buf);
2495 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2496 node->add_property ("maximised", _maximised ? "yes" : "no");
2497 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2498 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2499 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2500 node->add_property ("mouse-mode", enum2str(mouse_mode));
2501 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2502 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2504 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2506 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2507 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2510 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2512 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2513 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2516 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2517 node->add_property (X_("editor-list-page"), buf);
2519 if (button_bindings) {
2520 XMLNode* bb = new XMLNode (X_("Buttons"));
2521 button_bindings->save (*bb);
2522 node->add_child_nocopy (*bb);
2525 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2527 node->add_child_nocopy (selection->get_state ());
2528 node->add_child_nocopy (_regions->get_state ());
2530 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2531 node->add_property ("nudge-clock-value", buf);
2538 /** @param y y offset from the top of all trackviews.
2539 * @return pair: TimeAxisView that y is over, layer index.
2540 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2541 * in stacked or expanded region display mode, otherwise 0.
2543 std::pair<TimeAxisView *, double>
2544 Editor::trackview_by_y_position (double y)
2546 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2548 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2554 return std::make_pair ( (TimeAxisView *) 0, 0);
2557 /** Snap a position to the grid, if appropriate, taking into account current
2558 * grid settings and also the state of any snap modifier keys that may be pressed.
2559 * @param start Position to snap.
2560 * @param event Event to get current key modifier information from, or 0.
2563 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2565 if (!_session || !event) {
2569 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2570 if (_snap_mode == SnapOff) {
2571 snap_to_internal (start, direction, for_mark);
2574 if (_snap_mode != SnapOff) {
2575 snap_to_internal (start, direction, for_mark);
2581 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2583 if (!_session || _snap_mode == SnapOff) {
2587 snap_to_internal (start, direction, for_mark);
2591 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2593 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2594 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2596 switch (_snap_type) {
2597 case SnapToTimecodeFrame:
2598 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2599 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2601 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2605 case SnapToTimecodeSeconds:
2606 if (_session->config.get_timecode_offset_negative()) {
2607 start += _session->config.get_timecode_offset ();
2609 start -= _session->config.get_timecode_offset ();
2611 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2612 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2614 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2617 if (_session->config.get_timecode_offset_negative()) {
2618 start -= _session->config.get_timecode_offset ();
2620 start += _session->config.get_timecode_offset ();
2624 case SnapToTimecodeMinutes:
2625 if (_session->config.get_timecode_offset_negative()) {
2626 start += _session->config.get_timecode_offset ();
2628 start -= _session->config.get_timecode_offset ();
2630 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2631 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2633 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2635 if (_session->config.get_timecode_offset_negative()) {
2636 start -= _session->config.get_timecode_offset ();
2638 start += _session->config.get_timecode_offset ();
2642 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2648 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2650 const framepos_t one_second = _session->frame_rate();
2651 const framepos_t one_minute = _session->frame_rate() * 60;
2652 framepos_t presnap = start;
2656 switch (_snap_type) {
2657 case SnapToTimecodeFrame:
2658 case SnapToTimecodeSeconds:
2659 case SnapToTimecodeMinutes:
2660 return timecode_snap_to_internal (start, direction, for_mark);
2663 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2664 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2666 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2671 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2672 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2674 start = (framepos_t) floor ((double) start / one_second) * one_second;
2679 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2680 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2682 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2687 start = _session->tempo_map().round_to_bar (start, direction);
2691 start = _session->tempo_map().round_to_beat (start, direction);
2694 case SnapToBeatDiv128:
2695 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2697 case SnapToBeatDiv64:
2698 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2700 case SnapToBeatDiv32:
2701 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2703 case SnapToBeatDiv28:
2704 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2706 case SnapToBeatDiv24:
2707 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2709 case SnapToBeatDiv20:
2710 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2712 case SnapToBeatDiv16:
2713 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2715 case SnapToBeatDiv14:
2716 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2718 case SnapToBeatDiv12:
2719 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2721 case SnapToBeatDiv10:
2722 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2724 case SnapToBeatDiv8:
2725 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2727 case SnapToBeatDiv7:
2728 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2730 case SnapToBeatDiv6:
2731 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2733 case SnapToBeatDiv5:
2734 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2736 case SnapToBeatDiv4:
2737 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2739 case SnapToBeatDiv3:
2740 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2742 case SnapToBeatDiv2:
2743 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2751 _session->locations()->marks_either_side (start, before, after);
2753 if (before == max_framepos && after == max_framepos) {
2754 /* No marks to snap to, so just don't snap */
2756 } else if (before == max_framepos) {
2758 } else if (after == max_framepos) {
2760 } else if (before != max_framepos && after != max_framepos) {
2761 /* have before and after */
2762 if ((start - before) < (after - start)) {
2771 case SnapToRegionStart:
2772 case SnapToRegionEnd:
2773 case SnapToRegionSync:
2774 case SnapToRegionBoundary:
2775 if (!region_boundary_cache.empty()) {
2777 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2778 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2780 if (direction > 0) {
2781 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2783 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2786 if (next != region_boundary_cache.begin ()) {
2791 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2792 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2794 if (start > (p + n) / 2) {
2803 switch (_snap_mode) {
2809 if (presnap > start) {
2810 if (presnap > (start + unit_to_frame(snap_threshold))) {
2814 } else if (presnap < start) {
2815 if (presnap < (start - unit_to_frame(snap_threshold))) {
2821 /* handled at entry */
2829 Editor::setup_toolbar ()
2831 HBox* mode_box = manage(new HBox);
2832 mode_box->set_border_width (2);
2833 mode_box->set_spacing(4);
2835 HBox* mouse_mode_box = manage (new HBox);
2836 HBox* mouse_mode_hbox = manage (new HBox);
2837 VBox* mouse_mode_vbox = manage (new VBox);
2838 Alignment* mouse_mode_align = manage (new Alignment);
2840 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2841 // mouse_mode_size_group->add_widget (smart_mode_button);
2842 mouse_mode_size_group->add_widget (mouse_move_button);
2843 mouse_mode_size_group->add_widget (mouse_select_button);
2844 mouse_mode_size_group->add_widget (mouse_zoom_button);
2845 mouse_mode_size_group->add_widget (mouse_gain_button);
2846 mouse_mode_size_group->add_widget (mouse_timefx_button);
2847 mouse_mode_size_group->add_widget (mouse_audition_button);
2848 mouse_mode_size_group->add_widget (mouse_draw_button);
2849 mouse_mode_size_group->add_widget (internal_edit_button);
2851 /* make them just a bit bigger */
2852 mouse_move_button.set_size_request (-1, 25);
2854 mouse_mode_hbox->set_spacing (2);
2856 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2857 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2858 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2859 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2860 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2861 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2862 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2863 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2864 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2866 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2868 mouse_mode_align->add (*mouse_mode_vbox);
2869 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2871 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2873 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2874 if (!Profile->get_sae()) {
2875 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2877 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2879 edit_mode_selector.set_name ("EditModeSelector");
2880 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2881 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2883 mode_box->pack_start (edit_mode_selector, false, false);
2884 mode_box->pack_start (*mouse_mode_box, false, false);
2886 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2887 _mouse_mode_tearoff->set_name ("MouseModeBase");
2888 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2890 if (Profile->get_sae()) {
2891 _mouse_mode_tearoff->set_can_be_torn_off (false);
2894 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2895 &_mouse_mode_tearoff->tearoff_window()));
2896 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2897 &_mouse_mode_tearoff->tearoff_window(), 1));
2898 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2899 &_mouse_mode_tearoff->tearoff_window()));
2900 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2901 &_mouse_mode_tearoff->tearoff_window(), 1));
2905 _zoom_box.set_spacing (2);
2906 _zoom_box.set_border_width (2);
2910 zoom_in_button.set_name ("zoom button");
2911 zoom_in_button.add (*(manage (new Image (::get_icon ("zoom_in")))));
2912 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2913 act->connect_proxy (zoom_in_button);
2915 zoom_out_button.set_name ("zoom button");
2916 zoom_out_button.add (*(manage (new Image (::get_icon ("zoom_out")))));
2917 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2918 act->connect_proxy (zoom_out_button);
2920 zoom_out_full_button.set_name ("zoom button");
2921 zoom_out_full_button.add (*(manage (new Image (::get_icon ("zoom_full")))));
2922 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2923 act->connect_proxy (zoom_out_full_button);
2925 zoom_focus_selector.set_name ("ZoomFocusSelector");
2926 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2927 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2929 _zoom_box.pack_start (zoom_out_button, false, false);
2930 _zoom_box.pack_start (zoom_in_button, false, false);
2931 _zoom_box.pack_start (zoom_out_full_button, false, false);
2933 _zoom_box.pack_start (zoom_focus_selector, false, false);
2935 /* Track zoom buttons */
2936 tav_expand_button.set_name ("TrackHeightButton");
2937 tav_expand_button.set_size_request (-1, 20);
2938 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2939 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2940 act->connect_proxy (tav_expand_button);
2942 tav_shrink_button.set_name ("TrackHeightButton");
2943 tav_shrink_button.set_size_request (-1, 20);
2944 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2945 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2946 act->connect_proxy (tav_shrink_button);
2948 _zoom_box.pack_start (tav_shrink_button);
2949 _zoom_box.pack_start (tav_expand_button);
2951 _zoom_tearoff = manage (new TearOff (_zoom_box));
2953 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2954 &_zoom_tearoff->tearoff_window()));
2955 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2956 &_zoom_tearoff->tearoff_window(), 0));
2957 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2958 &_zoom_tearoff->tearoff_window()));
2959 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2960 &_zoom_tearoff->tearoff_window(), 0));
2962 snap_box.set_spacing (1);
2963 snap_box.set_border_width (2);
2965 snap_type_selector.set_name ("SnapTypeSelector");
2966 set_popdown_strings (snap_type_selector, snap_type_strings);
2967 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2969 snap_mode_selector.set_name ("SnapModeSelector");
2970 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2971 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2973 edit_point_selector.set_name ("EditPointSelector");
2974 set_popdown_strings (edit_point_selector, edit_point_strings);
2975 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2977 snap_box.pack_start (snap_mode_selector, false, false);
2978 snap_box.pack_start (snap_type_selector, false, false);
2979 snap_box.pack_start (edit_point_selector, false, false);
2983 HBox *nudge_box = manage (new HBox);
2984 nudge_box->set_spacing (2);
2985 nudge_box->set_border_width (2);
2987 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2988 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2990 nudge_box->pack_start (nudge_backward_button, false, false);
2991 nudge_box->pack_start (nudge_forward_button, false, false);
2992 nudge_box->pack_start (*nudge_clock, false, false);
2995 /* Pack everything in... */
2997 HBox* hbox = manage (new HBox);
2998 hbox->set_spacing(10);
3000 _tools_tearoff = manage (new TearOff (*hbox));
3001 _tools_tearoff->set_name ("MouseModeBase");
3002 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3004 if (Profile->get_sae()) {
3005 _tools_tearoff->set_can_be_torn_off (false);
3008 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3009 &_tools_tearoff->tearoff_window()));
3010 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3011 &_tools_tearoff->tearoff_window(), 0));
3012 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3013 &_tools_tearoff->tearoff_window()));
3014 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3015 &_tools_tearoff->tearoff_window(), 0));
3017 toolbar_hbox.set_spacing (10);
3018 toolbar_hbox.set_border_width (1);
3020 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3021 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3022 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3024 hbox->pack_start (snap_box, false, false);
3025 if (!Profile->get_small_screen()) {
3026 hbox->pack_start (*nudge_box, false, false);
3028 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3030 hbox->pack_start (panic_box, false, false);
3034 toolbar_base.set_name ("ToolBarBase");
3035 toolbar_base.add (toolbar_hbox);
3037 _toolbar_viewport.add (toolbar_base);
3038 /* stick to the required height but allow width to vary if there's not enough room */
3039 _toolbar_viewport.set_size_request (1, -1);
3041 toolbar_frame.set_shadow_type (SHADOW_OUT);
3042 toolbar_frame.set_name ("BaseFrame");
3043 toolbar_frame.add (_toolbar_viewport);
3047 Editor::setup_tooltips ()
3049 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3050 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3051 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3052 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3053 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3054 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3055 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3056 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3057 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3058 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3059 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3060 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3061 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3062 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3063 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3064 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3065 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3066 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3067 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3068 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3069 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3070 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3071 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3075 Editor::convert_drop_to_paths (
3076 vector<string>& paths,
3077 const RefPtr<Gdk::DragContext>& /*context*/,
3080 const SelectionData& data,
3084 if (_session == 0) {
3088 vector<string> uris = data.get_uris();
3092 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3093 are actually URI lists. So do it by hand.
3096 if (data.get_target() != "text/plain") {
3100 /* Parse the "uri-list" format that Nautilus provides,
3101 where each pathname is delimited by \r\n.
3103 THERE MAY BE NO NULL TERMINATING CHAR!!!
3106 string txt = data.get_text();
3110 p = (const char *) malloc (txt.length() + 1);
3111 txt.copy (const_cast<char *> (p), txt.length(), 0);
3112 const_cast<char*>(p)[txt.length()] = '\0';
3118 while (g_ascii_isspace (*p))
3122 while (*q && (*q != '\n') && (*q != '\r')) {
3129 while (q > p && g_ascii_isspace (*q))
3134 uris.push_back (string (p, q - p + 1));
3138 p = strchr (p, '\n');
3150 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3152 if ((*i).substr (0,7) == "file://") {
3154 string const p = PBD::url_decode (*i);
3156 // scan forward past three slashes
3158 string::size_type slashcnt = 0;
3159 string::size_type n = 0;
3160 string::const_iterator x = p.begin();
3162 while (slashcnt < 3 && x != p.end()) {
3165 } else if (slashcnt == 3) {
3172 if (slashcnt != 3 || x == p.end()) {
3173 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3177 paths.push_back (p.substr (n - 1));
3185 Editor::new_tempo_section ()
3191 Editor::map_transport_state ()
3193 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3195 if (_session && _session->transport_stopped()) {
3196 have_pending_keyboard_selection = false;
3199 update_loop_range_view (true);
3205 Editor::begin_reversible_command (string name)
3208 _session->begin_reversible_command (name);
3213 Editor::begin_reversible_command (GQuark q)
3216 _session->begin_reversible_command (q);
3221 Editor::commit_reversible_command ()
3224 _session->commit_reversible_command ();
3229 Editor::history_changed ()
3233 if (undo_action && _session) {
3234 if (_session->undo_depth() == 0) {
3235 label = S_("Command|Undo");
3237 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3239 undo_action->property_label() = label;
3242 if (redo_action && _session) {
3243 if (_session->redo_depth() == 0) {
3246 label = string_compose(_("Redo (%1)"), _session->next_redo());
3248 redo_action->property_label() = label;
3253 Editor::duplicate_range (bool with_dialog)
3257 if (mouse_mode == MouseRange) {
3258 if (selection->time.length() == 0) {
3263 RegionSelection rs = get_regions_from_selection_and_entered ();
3265 if (mouse_mode != MouseRange && rs.empty()) {
3271 ArdourDialog win (_("Duplicate"));
3272 Label label (_("Number of duplications:"));
3273 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3274 SpinButton spinner (adjustment, 0.0, 1);
3277 win.get_vbox()->set_spacing (12);
3278 win.get_vbox()->pack_start (hbox);
3279 hbox.set_border_width (6);
3280 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3282 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3283 place, visually. so do this by hand.
3286 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3287 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3288 spinner.grab_focus();
3294 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3295 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3296 win.set_default_response (RESPONSE_ACCEPT);
3298 win.set_position (WIN_POS_MOUSE);
3300 spinner.grab_focus ();
3302 switch (win.run ()) {
3303 case RESPONSE_ACCEPT:
3309 times = adjustment.get_value();
3312 if (mouse_mode == MouseRange) {
3313 duplicate_selection (times);
3315 duplicate_some_regions (rs, times);
3320 Editor::set_edit_mode (EditMode m)
3322 Config->set_edit_mode (m);
3326 Editor::cycle_edit_mode ()
3328 switch (Config->get_edit_mode()) {
3330 if (Profile->get_sae()) {
3331 Config->set_edit_mode (Lock);
3333 Config->set_edit_mode (Splice);
3337 Config->set_edit_mode (Lock);
3340 Config->set_edit_mode (Slide);
3346 Editor::edit_mode_selection_done ()
3348 string s = edit_mode_selector.get_active_text ();
3351 Config->set_edit_mode (string_to_edit_mode (s));
3356 Editor::snap_type_selection_done ()
3358 string choice = snap_type_selector.get_active_text();
3359 SnapType snaptype = SnapToBeat;
3361 if (choice == _("Beats/2")) {
3362 snaptype = SnapToBeatDiv2;
3363 } else if (choice == _("Beats/3")) {
3364 snaptype = SnapToBeatDiv3;
3365 } else if (choice == _("Beats/4")) {
3366 snaptype = SnapToBeatDiv4;
3367 } else if (choice == _("Beats/5")) {
3368 snaptype = SnapToBeatDiv5;
3369 } else if (choice == _("Beats/6")) {
3370 snaptype = SnapToBeatDiv6;
3371 } else if (choice == _("Beats/7")) {
3372 snaptype = SnapToBeatDiv7;
3373 } else if (choice == _("Beats/8")) {
3374 snaptype = SnapToBeatDiv8;
3375 } else if (choice == _("Beats/10")) {
3376 snaptype = SnapToBeatDiv10;
3377 } else if (choice == _("Beats/12")) {
3378 snaptype = SnapToBeatDiv12;
3379 } else if (choice == _("Beats/14")) {
3380 snaptype = SnapToBeatDiv14;
3381 } else if (choice == _("Beats/16")) {
3382 snaptype = SnapToBeatDiv16;
3383 } else if (choice == _("Beats/20")) {
3384 snaptype = SnapToBeatDiv20;
3385 } else if (choice == _("Beats/24")) {
3386 snaptype = SnapToBeatDiv24;
3387 } else if (choice == _("Beats/28")) {
3388 snaptype = SnapToBeatDiv28;
3389 } else if (choice == _("Beats/32")) {
3390 snaptype = SnapToBeatDiv32;
3391 } else if (choice == _("Beats/64")) {
3392 snaptype = SnapToBeatDiv64;
3393 } else if (choice == _("Beats/128")) {
3394 snaptype = SnapToBeatDiv128;
3395 } else if (choice == _("Beats")) {
3396 snaptype = SnapToBeat;
3397 } else if (choice == _("Bars")) {
3398 snaptype = SnapToBar;
3399 } else if (choice == _("Marks")) {
3400 snaptype = SnapToMark;
3401 } else if (choice == _("Region starts")) {
3402 snaptype = SnapToRegionStart;
3403 } else if (choice == _("Region ends")) {
3404 snaptype = SnapToRegionEnd;
3405 } else if (choice == _("Region bounds")) {
3406 snaptype = SnapToRegionBoundary;
3407 } else if (choice == _("Region syncs")) {
3408 snaptype = SnapToRegionSync;
3409 } else if (choice == _("CD Frames")) {
3410 snaptype = SnapToCDFrame;
3411 } else if (choice == _("Timecode Frames")) {
3412 snaptype = SnapToTimecodeFrame;
3413 } else if (choice == _("Timecode Seconds")) {
3414 snaptype = SnapToTimecodeSeconds;
3415 } else if (choice == _("Timecode Minutes")) {
3416 snaptype = SnapToTimecodeMinutes;
3417 } else if (choice == _("Seconds")) {
3418 snaptype = SnapToSeconds;
3419 } else if (choice == _("Minutes")) {
3420 snaptype = SnapToMinutes;
3423 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3425 ract->set_active ();
3430 Editor::snap_mode_selection_done ()
3432 string choice = snap_mode_selector.get_active_text();
3433 SnapMode mode = SnapNormal;
3435 if (choice == _("No Grid")) {
3437 } else if (choice == _("Grid")) {
3439 } else if (choice == _("Magnetic")) {
3440 mode = SnapMagnetic;
3443 RefPtr<RadioAction> ract = snap_mode_action (mode);
3446 ract->set_active (true);
3451 Editor::cycle_edit_point (bool with_marker)
3453 switch (_edit_point) {
3455 set_edit_point_preference (EditAtPlayhead);
3457 case EditAtPlayhead:
3459 set_edit_point_preference (EditAtSelectedMarker);
3461 set_edit_point_preference (EditAtMouse);
3464 case EditAtSelectedMarker:
3465 set_edit_point_preference (EditAtMouse);
3471 Editor::edit_point_selection_done ()
3473 string choice = edit_point_selector.get_active_text();
3474 EditPoint ep = EditAtSelectedMarker;
3476 if (choice == _("Marker")) {
3477 set_edit_point_preference (EditAtSelectedMarker);
3478 } else if (choice == _("Playhead")) {
3479 set_edit_point_preference (EditAtPlayhead);
3481 set_edit_point_preference (EditAtMouse);
3484 RefPtr<RadioAction> ract = edit_point_action (ep);
3487 ract->set_active (true);
3492 Editor::zoom_focus_selection_done ()
3494 string choice = zoom_focus_selector.get_active_text();
3495 ZoomFocus focus_type = ZoomFocusLeft;
3497 if (choice == _("Left")) {
3498 focus_type = ZoomFocusLeft;
3499 } else if (choice == _("Right")) {
3500 focus_type = ZoomFocusRight;
3501 } else if (choice == _("Center")) {
3502 focus_type = ZoomFocusCenter;
3503 } else if (choice == _("Playhead")) {
3504 focus_type = ZoomFocusPlayhead;
3505 } else if (choice == _("Mouse")) {
3506 focus_type = ZoomFocusMouse;
3507 } else if (choice == _("Edit point")) {
3508 focus_type = ZoomFocusEdit;
3511 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3514 ract->set_active ();
3519 Editor::edit_controls_button_release (GdkEventButton* ev)
3521 if (Keyboard::is_context_menu_event (ev)) {
3522 ARDOUR_UI::instance()->add_route (this);
3523 } else if (ev->button == 1) {
3524 selection->clear_tracks ();
3531 Editor::mouse_select_button_release (GdkEventButton* ev)
3533 /* this handles just right-clicks */
3535 if (ev->button != 3) {
3543 Editor::set_zoom_focus (ZoomFocus f)
3545 string str = zoom_focus_strings[(int)f];
3547 if (str != zoom_focus_selector.get_active_text()) {
3548 zoom_focus_selector.set_active_text (str);
3551 if (zoom_focus != f) {
3558 Editor::ensure_float (Window& win)
3560 win.set_transient_for (*this);
3564 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3566 /* recover or initialize pane positions. do this here rather than earlier because
3567 we don't want the positions to change the child allocations, which they seem to do.
3573 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3582 XMLNode* geometry = find_named_node (*node, "geometry");
3584 if (which == static_cast<Paned*> (&edit_pane)) {
3586 if (done & Horizontal) {
3590 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3591 _notebook_shrunk = string_is_affirmative (prop->value ());
3594 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3595 /* initial allocation is 90% to canvas, 10% to notebook */
3596 pos = (int) floor (alloc.get_width() * 0.90f);
3597 snprintf (buf, sizeof(buf), "%d", pos);
3599 pos = atoi (prop->value());
3602 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3603 edit_pane.set_position (pos);
3606 done = (Pane) (done | Horizontal);
3608 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3610 if (done & Vertical) {
3614 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3615 /* initial allocation is 90% to canvas, 10% to summary */
3616 pos = (int) floor (alloc.get_height() * 0.90f);
3617 snprintf (buf, sizeof(buf), "%d", pos);
3620 pos = atoi (prop->value());
3623 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3624 editor_summary_pane.set_position (pos);
3627 done = (Pane) (done | Vertical);
3632 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3634 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3635 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3636 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3637 top_hbox.remove (toolbar_frame);
3642 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3644 if (toolbar_frame.get_parent() == 0) {
3645 top_hbox.pack_end (toolbar_frame);
3650 Editor::set_show_measures (bool yn)
3652 if (_show_measures != yn) {
3655 if ((_show_measures = yn) == true) {
3657 tempo_lines->show();
3665 Editor::toggle_follow_playhead ()
3667 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3669 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3670 set_follow_playhead (tact->get_active());
3674 /** @param yn true to follow playhead, otherwise false.
3675 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3678 Editor::set_follow_playhead (bool yn, bool catch_up)
3680 if (_follow_playhead != yn) {
3681 if ((_follow_playhead = yn) == true && catch_up) {
3683 reset_x_origin_to_follow_playhead ();
3690 Editor::toggle_stationary_playhead ()
3692 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3694 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3695 set_stationary_playhead (tact->get_active());
3700 Editor::set_stationary_playhead (bool yn)
3702 if (_stationary_playhead != yn) {
3703 if ((_stationary_playhead = yn) == true) {
3705 // FIXME need a 3.0 equivalent of this 2.X call
3706 // update_current_screen ();
3713 Editor::playlist_selector () const
3715 return *_playlist_selector;
3719 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3723 switch (_snap_type) {
3728 case SnapToBeatDiv128:
3731 case SnapToBeatDiv64:
3734 case SnapToBeatDiv32:
3737 case SnapToBeatDiv28:
3740 case SnapToBeatDiv24:
3743 case SnapToBeatDiv20:
3746 case SnapToBeatDiv16:
3749 case SnapToBeatDiv14:
3752 case SnapToBeatDiv12:
3755 case SnapToBeatDiv10:
3758 case SnapToBeatDiv8:
3761 case SnapToBeatDiv7:
3764 case SnapToBeatDiv6:
3767 case SnapToBeatDiv5:
3770 case SnapToBeatDiv4:
3773 case SnapToBeatDiv3:
3776 case SnapToBeatDiv2:
3782 return _session->tempo_map().meter_at (position).divisions_per_bar();
3787 case SnapToTimecodeFrame:
3788 case SnapToTimecodeSeconds:
3789 case SnapToTimecodeMinutes:
3792 case SnapToRegionStart:
3793 case SnapToRegionEnd:
3794 case SnapToRegionSync:
3795 case SnapToRegionBoundary:
3805 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3809 ret = nudge_clock->current_duration (pos);
3810 next = ret + 1; /* XXXX fix me */
3816 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3818 ArdourDialog dialog (_("Playlist Deletion"));
3819 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3820 "If it is kept, its audio files will not be cleaned.\n"
3821 "If it is deleted, audio files used by it alone will be cleaned."),
3824 dialog.set_position (WIN_POS_CENTER);
3825 dialog.get_vbox()->pack_start (label);
3829 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3830 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3831 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3833 switch (dialog.run ()) {
3834 case RESPONSE_ACCEPT:
3835 /* delete the playlist */
3839 case RESPONSE_REJECT:
3840 /* keep the playlist */
3852 Editor::audio_region_selection_covers (framepos_t where)
3854 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3855 if ((*a)->region()->covers (where)) {
3864 Editor::prepare_for_cleanup ()
3866 cut_buffer->clear_regions ();
3867 cut_buffer->clear_playlists ();
3869 selection->clear_regions ();
3870 selection->clear_playlists ();
3872 _regions->suspend_redisplay ();
3876 Editor::finish_cleanup ()
3878 _regions->resume_redisplay ();
3882 Editor::transport_loop_location()
3885 return _session->locations()->auto_loop_location();
3892 Editor::transport_punch_location()
3895 return _session->locations()->auto_punch_location();
3902 Editor::control_layout_scroll (GdkEventScroll* ev)
3904 if (Keyboard::some_magic_widget_has_focus()) {
3908 switch (ev->direction) {
3910 scroll_tracks_up_line ();
3914 case GDK_SCROLL_DOWN:
3915 scroll_tracks_down_line ();
3919 /* no left/right handling yet */
3927 Editor::session_state_saved (string)
3930 _snapshots->redisplay ();
3934 Editor::update_tearoff_visibility()
3936 bool visible = Config->get_keep_tearoffs();
3937 _mouse_mode_tearoff->set_visible (visible);
3938 _tools_tearoff->set_visible (visible);
3939 _zoom_tearoff->set_visible (visible);
3943 Editor::maximise_editing_space ()
3955 Editor::restore_editing_space ()
3967 * Make new playlists for a given track and also any others that belong
3968 * to the same active route group with the `edit' property.
3973 Editor::new_playlists (TimeAxisView* v)
3975 begin_reversible_command (_("new playlists"));
3976 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3977 _session->playlists->get (playlists);
3978 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3979 commit_reversible_command ();
3983 * Use a copy of the current playlist for a given track and also any others that belong
3984 * to the same active route group with the `edit' property.
3989 Editor::copy_playlists (TimeAxisView* v)
3991 begin_reversible_command (_("copy playlists"));
3992 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3993 _session->playlists->get (playlists);
3994 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3995 commit_reversible_command ();
3998 /** Clear the current playlist for a given track and also any others that belong
3999 * to the same active route group with the `edit' property.
4004 Editor::clear_playlists (TimeAxisView* v)
4006 begin_reversible_command (_("clear playlists"));
4007 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4008 _session->playlists->get (playlists);
4009 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4010 commit_reversible_command ();
4014 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4016 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4020 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4022 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4026 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4028 atv.clear_playlist ();
4032 Editor::on_key_press_event (GdkEventKey* ev)
4034 return key_press_focus_accelerator_handler (*this, ev);
4038 Editor::on_key_release_event (GdkEventKey* ev)
4040 return Gtk::Window::on_key_release_event (ev);
4041 // return key_press_focus_accelerator_handler (*this, ev);
4044 /** Queue up a change to the viewport x origin.
4045 * @param frame New x origin.
4048 Editor::reset_x_origin (framepos_t frame)
4050 pending_visual_change.add (VisualChange::TimeOrigin);
4051 pending_visual_change.time_origin = frame;
4052 ensure_visual_change_idle_handler ();
4056 Editor::reset_y_origin (double y)
4058 pending_visual_change.add (VisualChange::YOrigin);
4059 pending_visual_change.y_origin = y;
4060 ensure_visual_change_idle_handler ();
4064 Editor::reset_zoom (double fpu)
4066 clamp_frames_per_unit (fpu);
4068 if (fpu == frames_per_unit) {
4072 pending_visual_change.add (VisualChange::ZoomLevel);
4073 pending_visual_change.frames_per_unit = fpu;
4074 ensure_visual_change_idle_handler ();
4078 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4080 reset_x_origin (frame);
4083 if (!no_save_visual) {
4084 undo_visual_stack.push_back (current_visual_state(false));
4088 Editor::VisualState::VisualState (bool with_tracks)
4089 : gui_state (with_tracks ? new GUIObjectState : 0)
4093 Editor::VisualState::~VisualState ()
4098 Editor::VisualState*
4099 Editor::current_visual_state (bool with_tracks)
4101 VisualState* vs = new VisualState (with_tracks);
4102 vs->y_position = vertical_adjustment.get_value();
4103 vs->frames_per_unit = frames_per_unit;
4104 vs->leftmost_frame = leftmost_frame;
4105 vs->zoom_focus = zoom_focus;
4108 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4115 Editor::undo_visual_state ()
4117 if (undo_visual_stack.empty()) {
4121 VisualState* vs = undo_visual_stack.back();
4122 undo_visual_stack.pop_back();
4125 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4127 use_visual_state (*vs);
4131 Editor::redo_visual_state ()
4133 if (redo_visual_stack.empty()) {
4137 VisualState* vs = redo_visual_stack.back();
4138 redo_visual_stack.pop_back();
4140 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4142 use_visual_state (*vs);
4146 Editor::swap_visual_state ()
4148 if (undo_visual_stack.empty()) {
4149 redo_visual_state ();
4151 undo_visual_state ();
4156 Editor::use_visual_state (VisualState& vs)
4158 PBD::Unwinder<bool> nsv (no_save_visual, true);
4160 _routes->suspend_redisplay ();
4162 vertical_adjustment.set_value (vs.y_position);
4164 set_zoom_focus (vs.zoom_focus);
4165 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4168 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4170 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4171 (*i)->reset_visual_state ();
4175 _routes->update_visibility ();
4176 _routes->resume_redisplay ();
4179 /** This is the core function that controls the zoom level of the canvas. It is called
4180 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4181 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4184 Editor::set_frames_per_unit (double fpu)
4187 tempo_lines->tempo_map_changed();
4190 frames_per_unit = fpu;
4192 /* convert fpu to frame count */
4194 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4196 if (frames_per_unit != zoom_range_clock->current_duration()) {
4197 zoom_range_clock->set (frames);
4200 bool const showing_time_selection = selection->time.length() > 0;
4202 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4203 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4204 (*i)->reshow_selection (selection->time);
4208 ZoomChanged (); /* EMIT_SIGNAL */
4210 //reset_scrolling_region ();
4212 if (playhead_cursor) {
4213 playhead_cursor->set_position (playhead_cursor->current_frame);
4216 refresh_location_display();
4217 _summary->set_overlays_dirty ();
4219 update_marker_labels ();
4225 Editor::ensure_visual_change_idle_handler ()
4227 if (pending_visual_change.idle_handler_id < 0) {
4228 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4233 Editor::_idle_visual_changer (void* arg)
4235 return static_cast<Editor*>(arg)->idle_visual_changer ();
4239 Editor::idle_visual_changer ()
4241 /* set_horizontal_position() below (and maybe other calls) call
4242 gtk_main_iteration(), so it's possible that a signal will be handled
4243 half-way through this method. If this signal wants an
4244 idle_visual_changer we must schedule another one after this one, so
4245 mark the idle_handler_id as -1 here to allow that. Also make a note
4246 that we are doing the visual change, so that changes in response to
4247 super-rapid-screen-update can be dropped if we are still processing
4250 cerr << "EDITOR:: IDLE VISUAL CHANGE\n";
4252 pending_visual_change.idle_handler_id = -1;
4253 pending_visual_change.being_handled = true;
4255 VisualChange::Type p = pending_visual_change.pending;
4256 pending_visual_change.pending = (VisualChange::Type) 0;
4258 double const last_time_origin = horizontal_position ();
4260 if (p & VisualChange::ZoomLevel) {
4261 set_frames_per_unit (pending_visual_change.frames_per_unit);
4263 compute_fixed_ruler_scale ();
4264 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4265 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4266 update_tempo_based_rulers ();
4268 if (p & VisualChange::TimeOrigin) {
4269 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4271 if (p & VisualChange::YOrigin) {
4272 vertical_adjustment.set_value (pending_visual_change.y_origin);
4275 if (last_time_origin == horizontal_position ()) {
4276 /* changed signal not emitted */
4277 update_fixed_rulers ();
4278 redisplay_tempo (true);
4281 _summary->set_overlays_dirty ();
4283 pending_visual_change.being_handled = false;
4284 return 0; /* this is always a one-shot call */
4287 struct EditorOrderTimeAxisSorter {
4288 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4289 return a->order () < b->order ();
4294 Editor::sort_track_selection (TrackViewList& sel)
4296 EditorOrderTimeAxisSorter cmp;
4301 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4304 framepos_t where = 0;
4305 EditPoint ep = _edit_point;
4307 if (from_context_menu && (ep == EditAtMouse)) {
4308 return event_frame (&context_click_event, 0, 0);
4311 if (entered_marker) {
4312 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4313 return entered_marker->position();
4316 if (ignore_playhead && ep == EditAtPlayhead) {
4317 ep = EditAtSelectedMarker;
4321 case EditAtPlayhead:
4322 where = _session->audible_frame();
4323 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4326 case EditAtSelectedMarker:
4327 if (!selection->markers.empty()) {
4329 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4332 where = loc->start();
4336 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4344 if (!mouse_frame (where, ignored)) {
4345 /* XXX not right but what can we do ? */
4349 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4357 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4359 if (!_session) return;
4361 begin_reversible_command (cmd);
4365 if ((tll = transport_loop_location()) == 0) {
4366 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4367 XMLNode &before = _session->locations()->get_state();
4368 _session->locations()->add (loc, true);
4369 _session->set_auto_loop_location (loc);
4370 XMLNode &after = _session->locations()->get_state();
4371 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4373 XMLNode &before = tll->get_state();
4374 tll->set_hidden (false, this);
4375 tll->set (start, end);
4376 XMLNode &after = tll->get_state();
4377 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4380 commit_reversible_command ();
4384 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4386 if (!_session) return;
4388 begin_reversible_command (cmd);
4392 if ((tpl = transport_punch_location()) == 0) {
4393 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4394 XMLNode &before = _session->locations()->get_state();
4395 _session->locations()->add (loc, true);
4396 _session->set_auto_loop_location (loc);
4397 XMLNode &after = _session->locations()->get_state();
4398 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4401 XMLNode &before = tpl->get_state();
4402 tpl->set_hidden (false, this);
4403 tpl->set (start, end);
4404 XMLNode &after = tpl->get_state();
4405 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4408 commit_reversible_command ();
4411 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4412 * @param rs List to which found regions are added.
4413 * @param where Time to look at.
4414 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4417 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4419 const TrackViewList* tracks;
4422 tracks = &track_views;
4427 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4429 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4432 boost::shared_ptr<Track> tr;
4433 boost::shared_ptr<Playlist> pl;
4435 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4437 boost::shared_ptr<RegionList> regions = pl->regions_at (
4438 (framepos_t) floor ( (double) where * tr->speed()));
4440 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4441 RegionView* rv = rtv->view()->find_view (*i);
4452 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4454 const TrackViewList* tracks;
4457 tracks = &track_views;
4462 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4463 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4465 boost::shared_ptr<Track> tr;
4466 boost::shared_ptr<Playlist> pl;
4468 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4470 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4471 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4473 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4475 RegionView* rv = rtv->view()->find_view (*i);
4486 /** Start with regions that are selected. Then add equivalent regions
4487 * on tracks in the same active edit-enabled route group as any of
4488 * the regions that we started with.
4492 Editor::get_regions_from_selection ()
4494 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4497 /** Get regions using the following method:
4499 * Make an initial region list using the selected regions, unless
4500 * the edit point is `mouse' and the mouse is over an unselected
4501 * region. In this case, start with just that region.
4503 * Then, add equivalent regions in active edit groups to the region list.
4505 * Then, search the list of selected tracks to find any selected tracks which
4506 * do not contain regions already in the region list. If there are no selected
4507 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4508 * than just the selected.
4510 * Add any regions that are under the edit point on these tracks to get the
4511 * returned region list.
4513 * The rationale here is that the mouse edit point is special in that
4514 * its position describes both a time and a track; the other edit
4515 * modes only describe a time. Hence if the edit point is `mouse' we
4516 * ignore selected tracks, as we assume the user means something by
4517 * pointing at a particular track. Also in this case we take note of
4518 * the region directly under the edit point, as there is always just one
4519 * (rather than possibly several with non-mouse edit points).
4523 Editor::get_regions_from_selection_and_edit_point ()
4525 RegionSelection regions;
4527 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4528 regions.add (entered_regionview);
4530 regions = selection->regions;
4533 TrackViewList tracks;
4535 if (_edit_point != EditAtMouse) {
4536 tracks = selection->tracks;
4539 /* Add any other regions that are in the same
4540 edit-activated route group as one of our regions.
4542 regions = get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4543 framepos_t const where = get_preferred_edit_position ();
4545 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4546 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4547 * is enabled, so consider all tracks
4549 tracks = track_views;
4552 if (!tracks.empty()) {
4553 /* now search the selected tracks for tracks which don't
4554 already contain regions to be acted upon, and get regions at
4555 the edit point on those tracks too.
4557 TrackViewList tracks_without_relevant_regions;
4559 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4560 if (!regions.involves (**t)) {
4561 /* there are no equivalent regions on this track */
4562 tracks_without_relevant_regions.push_back (*t);
4566 if (!tracks_without_relevant_regions.empty()) {
4567 /* there are some selected tracks with neither selected
4568 * regions or their equivalents: act upon all regions in
4571 get_regions_at (regions, where, tracks_without_relevant_regions);
4578 /** Start with regions that are selected, or the entered regionview if none are selected.
4579 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4580 * of the regions that we started with.
4584 Editor::get_regions_from_selection_and_entered ()
4586 RegionSelection regions = selection->regions;
4588 if (regions.empty() && entered_regionview) {
4589 regions.add (entered_regionview);
4592 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4596 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4598 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4600 RouteTimeAxisView* tatv;
4602 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4604 boost::shared_ptr<Playlist> pl;
4605 vector<boost::shared_ptr<Region> > results;
4607 boost::shared_ptr<Track> tr;
4609 if ((tr = tatv->track()) == 0) {
4614 if ((pl = (tr->playlist())) != 0) {
4615 pl->get_region_list_equivalent_regions (region, results);
4618 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4619 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4620 regions.push_back (marv);
4629 Editor::show_rhythm_ferret ()
4631 if (rhythm_ferret == 0) {
4632 rhythm_ferret = new RhythmFerret(*this);
4635 rhythm_ferret->set_session (_session);
4636 rhythm_ferret->show ();
4637 rhythm_ferret->present ();
4641 Editor::first_idle ()
4643 MessageDialog* dialog = 0;
4645 if (track_views.size() > 1) {
4646 dialog = new MessageDialog (
4648 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4652 ARDOUR_UI::instance()->flush_pending ();
4655 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4659 // first idle adds route children (automation tracks), so we need to redisplay here
4660 _routes->redisplay ();
4667 Editor::_idle_resize (gpointer arg)
4669 return ((Editor*)arg)->idle_resize ();
4673 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4675 if (resize_idle_id < 0) {
4676 resize_idle_id = g_idle_add (_idle_resize, this);
4677 _pending_resize_amount = 0;
4680 /* make a note of the smallest resulting height, so that we can clamp the
4681 lower limit at TimeAxisView::hSmall */
4683 int32_t min_resulting = INT32_MAX;
4685 _pending_resize_amount += h;
4686 _pending_resize_view = view;
4688 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4690 if (selection->tracks.contains (_pending_resize_view)) {
4691 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4692 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4696 if (min_resulting < 0) {
4701 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4702 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4706 /** Handle pending resizing of tracks */
4708 Editor::idle_resize ()
4710 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4712 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4713 selection->tracks.contains (_pending_resize_view)) {
4715 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4716 if (*i != _pending_resize_view) {
4717 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4722 _pending_resize_amount = 0;
4724 _group_tabs->set_dirty ();
4725 resize_idle_id = -1;
4733 ENSURE_GUI_THREAD (*this, &Editor::located);
4736 playhead_cursor->set_position (_session->audible_frame ());
4737 if (_follow_playhead && !_pending_initial_locate) {
4738 reset_x_origin_to_follow_playhead ();
4742 _pending_locate_request = false;
4743 _pending_initial_locate = false;
4747 Editor::region_view_added (RegionView *)
4749 _summary->set_dirty ();
4753 Editor::region_view_removed ()
4755 _summary->set_dirty ();
4759 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4761 TrackViewList::const_iterator j = track_views.begin ();
4762 while (j != track_views.end()) {
4763 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4764 if (rtv && rtv->route() == r) {
4775 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4779 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4780 TimeAxisView* tv = axis_view_from_route (*i);
4790 Editor::add_routes (RouteList& routes)
4792 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4794 RouteTimeAxisView *rtv;
4795 list<RouteTimeAxisView*> new_views;
4797 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4798 boost::shared_ptr<Route> route = (*x);
4800 if (route->is_hidden() || route->is_monitor()) {
4804 DataType dt = route->input()->default_type();
4806 if (dt == ARDOUR::DataType::AUDIO) {
4807 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4808 rtv->set_route (route);
4809 } else if (dt == ARDOUR::DataType::MIDI) {
4810 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4811 rtv->set_route (route);
4813 throw unknown_type();
4816 new_views.push_back (rtv);
4817 track_views.push_back (rtv);
4819 rtv->effective_gain_display ();
4821 if (internal_editing()) {
4822 rtv->enter_internal_edit_mode ();
4824 rtv->leave_internal_edit_mode ();
4827 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4828 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4831 _routes->routes_added (new_views);
4832 _summary->routes_added (new_views);
4834 if (show_editor_mixer_when_tracks_arrive) {
4835 show_editor_mixer (true);
4838 editor_list_button.set_sensitive (true);
4842 Editor::timeaxisview_deleted (TimeAxisView *tv)
4844 if (_session && _session->deletion_in_progress()) {
4845 /* the situation is under control */
4849 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4851 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4853 _routes->route_removed (tv);
4855 if (tv == entered_track) {
4859 TimeAxisView::Children c = tv->get_child_list ();
4860 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4861 if (entered_track == i->get()) {
4866 /* remove it from the list of track views */
4868 TrackViewList::iterator i;
4870 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4871 i = track_views.erase (i);
4874 /* update whatever the current mixer strip is displaying, if revelant */
4876 boost::shared_ptr<Route> route;
4879 route = rtav->route ();
4882 if (current_mixer_strip && current_mixer_strip->route() == route) {
4884 TimeAxisView* next_tv;
4886 if (track_views.empty()) {
4888 } else if (i == track_views.end()) {
4889 next_tv = track_views.front();
4896 set_selected_mixer_strip (*next_tv);
4898 /* make the editor mixer strip go away setting the
4899 * button to inactive (which also unticks the menu option)
4902 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4908 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4910 if (apply_to_selection) {
4911 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4913 TrackSelection::iterator j = i;
4916 hide_track_in_display (*i, false);
4921 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4923 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4924 // this will hide the mixer strip
4925 set_selected_mixer_strip (*tv);
4928 _routes->hide_track_in_display (*tv);
4933 Editor::sync_track_view_list_and_routes ()
4935 track_views = TrackViewList (_routes->views ());
4937 _summary->set_dirty ();
4938 _group_tabs->set_dirty ();
4940 return false; // do not call again (until needed)
4944 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4946 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4951 /** Find a RouteTimeAxisView by the ID of its route */
4953 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4955 RouteTimeAxisView* v;
4957 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4958 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4959 if(v->route()->id() == id) {
4969 Editor::fit_route_group (RouteGroup *g)
4971 TrackViewList ts = axis_views_from_routes (g->route_list ());
4976 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4978 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4981 _session->cancel_audition ();
4985 if (_session->is_auditioning()) {
4986 _session->cancel_audition ();
4987 if (r == last_audition_region) {
4992 _session->audition_region (r);
4993 last_audition_region = r;
4998 Editor::hide_a_region (boost::shared_ptr<Region> r)
5000 r->set_hidden (true);
5004 Editor::show_a_region (boost::shared_ptr<Region> r)
5006 r->set_hidden (false);
5010 Editor::audition_region_from_region_list ()
5012 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5016 Editor::hide_region_from_region_list ()
5018 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5022 Editor::show_region_in_region_list ()
5024 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5028 Editor::step_edit_status_change (bool yn)
5031 start_step_editing ();
5033 stop_step_editing ();
5038 Editor::start_step_editing ()
5040 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5044 Editor::stop_step_editing ()
5046 step_edit_connection.disconnect ();
5050 Editor::check_step_edit ()
5052 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5053 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5055 mtv->check_step_edit ();
5059 return true; // do it again, till we stop
5063 Editor::scroll_press (Direction dir)
5065 ++_scroll_callbacks;
5067 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5068 /* delay the first auto-repeat */
5074 scroll_backward (1);
5082 scroll_tracks_up_line ();
5086 scroll_tracks_down_line ();
5090 /* do hacky auto-repeat */
5091 if (!_scroll_connection.connected ()) {
5093 _scroll_connection = Glib::signal_timeout().connect (
5094 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5097 _scroll_callbacks = 0;
5104 Editor::scroll_release ()
5106 _scroll_connection.disconnect ();
5109 /** Queue a change for the Editor viewport x origin to follow the playhead */
5111 Editor::reset_x_origin_to_follow_playhead ()
5113 framepos_t const frame = playhead_cursor->current_frame;
5115 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5117 if (_session->transport_speed() < 0) {
5119 if (frame > (current_page_frames() / 2)) {
5120 center_screen (frame-(current_page_frames()/2));
5122 center_screen (current_page_frames()/2);
5129 if (frame < leftmost_frame) {
5131 if (_session->transport_rolling()) {
5132 /* rolling; end up with the playhead at the right of the page */
5133 l = frame - current_page_frames ();
5135 /* not rolling: end up with the playhead 1/4 of the way along the page */
5136 l = frame - current_page_frames() / 4;
5140 if (_session->transport_rolling()) {
5141 /* rolling: end up with the playhead on the left of the page */
5144 /* not rolling: end up with the playhead 3/4 of the way along the page */
5145 l = frame - 3 * current_page_frames() / 4;
5153 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5159 Editor::super_rapid_screen_update ()
5161 if (!_session || !_session->engine().running()) {
5165 /* METERING / MIXER STRIPS */
5167 /* update track meters, if required */
5168 if (is_mapped() && meters_running) {
5169 RouteTimeAxisView* rtv;
5170 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5171 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5172 rtv->fast_update ();
5177 /* and any current mixer strip */
5178 if (current_mixer_strip) {
5179 current_mixer_strip->fast_update ();
5182 /* PLAYHEAD AND VIEWPORT */
5184 framepos_t const frame = _session->audible_frame();
5186 /* There are a few reasons why we might not update the playhead / viewport stuff:
5188 * 1. we don't update things when there's a pending locate request, otherwise
5189 * when the editor requests a locate there is a chance that this method
5190 * will move the playhead before the locate request is processed, causing
5192 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5193 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5196 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5198 last_update_frame = frame;
5200 if (!_dragging_playhead) {
5201 playhead_cursor->set_position (frame);
5204 if (!_stationary_playhead) {
5206 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5207 /* We only do this if we aren't already
5208 handling a visual change (ie if
5209 pending_visual_change.being_handled is
5210 false) so that these requests don't stack
5211 up there are too many of them to handle in
5214 reset_x_origin_to_follow_playhead ();
5219 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5223 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5224 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5225 if (target <= 0.0) {
5228 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5229 target = (target * 0.15) + (current * 0.85);
5235 set_horizontal_position (current);
5244 Editor::session_going_away ()
5246 _have_idled = false;
5248 _session_connections.drop_connections ();
5250 super_rapid_screen_update_connection.disconnect ();
5252 selection->clear ();
5253 cut_buffer->clear ();
5255 clicked_regionview = 0;
5256 clicked_axisview = 0;
5257 clicked_routeview = 0;
5258 entered_regionview = 0;
5260 last_update_frame = 0;
5263 playhead_cursor->canvas_item.hide ();
5265 /* rip everything out of the list displays */
5269 _route_groups->clear ();
5271 /* do this first so that deleting a track doesn't reset cms to null
5272 and thus cause a leak.
5275 if (current_mixer_strip) {
5276 if (current_mixer_strip->get_parent() != 0) {
5277 global_hpacker.remove (*current_mixer_strip);
5279 delete current_mixer_strip;
5280 current_mixer_strip = 0;
5283 /* delete all trackviews */
5285 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5288 track_views.clear ();
5290 zoom_range_clock->set_session (0);
5291 nudge_clock->set_session (0);
5293 editor_list_button.set_active(false);
5294 editor_list_button.set_sensitive(false);
5296 /* clear tempo/meter rulers */
5297 remove_metric_marks ();
5299 clear_marker_display ();
5301 stop_step_editing ();
5303 current_bbt_points_begin = current_bbt_points_end;
5305 /* get rid of any existing editor mixer strip */
5307 WindowTitle title(Glib::get_application_name());
5308 title += _("Editor");
5310 set_title (title.get_string());
5312 SessionHandlePtr::session_going_away ();
5317 Editor::show_editor_list (bool yn)
5320 _the_notebook.show ();
5322 _the_notebook.hide ();
5327 Editor::change_region_layering_order (bool from_context_menu)
5329 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5331 if (!clicked_routeview) {
5332 if (layering_order_editor) {
5333 layering_order_editor->hide ();
5338 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5344 boost::shared_ptr<Playlist> pl = track->playlist();
5350 if (layering_order_editor == 0) {
5351 layering_order_editor = new RegionLayeringOrderEditor (*this);
5352 layering_order_editor->set_position (WIN_POS_MOUSE);
5355 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5356 layering_order_editor->maybe_present ();
5360 Editor::update_region_layering_order_editor ()
5362 if (layering_order_editor && layering_order_editor->is_visible ()) {
5363 change_region_layering_order (true);
5368 Editor::setup_fade_images ()
5370 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5371 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5372 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5373 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5374 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5376 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5377 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5378 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5379 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5380 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5382 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5383 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5384 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5385 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5386 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5388 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5389 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5390 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5391 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5392 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5396 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5398 Editor::action_menu_item (std::string const & name)
5400 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5403 return *manage (a->create_menu_item ());
5407 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5409 EventBox* b = manage (new EventBox);
5410 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5411 Label* l = manage (new Label (name));
5415 _the_notebook.append_page (widget, *b);
5419 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5421 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5422 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5425 if (ev->type == GDK_2BUTTON_PRESS) {
5427 /* double-click on a notebook tab shrinks or expands the notebook */
5429 if (_notebook_shrunk) {
5430 if (pre_notebook_shrink_pane_width) {
5431 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5433 _notebook_shrunk = false;
5435 pre_notebook_shrink_pane_width = edit_pane.get_position();
5437 /* this expands the LHS of the edit pane to cover the notebook
5438 PAGE but leaves the tabs visible.
5440 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5441 _notebook_shrunk = true;
5449 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5451 using namespace Menu_Helpers;
5453 MenuList& items = _control_point_context_menu.items ();
5456 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5457 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5458 if (!can_remove_control_point (item)) {
5459 items.back().set_sensitive (false);
5462 _control_point_context_menu.popup (event->button.button, event->button.time);
5466 Editor::shift_key_released ()
5468 _stepping_axis_view = 0;