2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
48 #include <glibmm/miscutils.h>
49 #include <gtkmm/image.h>
50 #include <gdkmm/color.h>
51 #include <gdkmm/bitmap.h>
53 #include "gtkmm2ext/bindings.h"
54 #include "gtkmm2ext/grouped_buttons.h"
55 #include "gtkmm2ext/gtk_ui.h"
56 #include "gtkmm2ext/tearoff.h"
57 #include "gtkmm2ext/utils.h"
58 #include "gtkmm2ext/window_title.h"
59 #include "gtkmm2ext/choice.h"
60 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioengine.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/profile.h"
67 #include "ardour/route_group.h"
68 #include "ardour/session_playlists.h"
69 #include "ardour/tempo.h"
70 #include "ardour/utils.h"
72 #include "control_protocol/control_protocol.h"
76 #include "analysis_window.h"
77 #include "audio_clock.h"
78 #include "audio_region_view.h"
79 #include "audio_streamview.h"
80 #include "audio_time_axis.h"
81 #include "automation_time_axis.h"
82 #include "bundle_manager.h"
83 #include "button_joiner.h"
84 #include "canvas-noevent-text.h"
85 #include "canvas_impl.h"
86 #include "crossfade_edit.h"
90 #include "editor_cursors.h"
91 #include "editor_drag.h"
92 #include "editor_group_tabs.h"
93 #include "editor_locations.h"
94 #include "editor_regions.h"
95 #include "editor_route_groups.h"
96 #include "editor_routes.h"
97 #include "editor_snapshots.h"
98 #include "editor_summary.h"
99 #include "global_port_matrix.h"
100 #include "gui_object.h"
101 #include "gui_thread.h"
102 #include "keyboard.h"
104 #include "midi_time_axis.h"
105 #include "mixer_strip.h"
106 #include "mixer_ui.h"
107 #include "mouse_cursors.h"
108 #include "playlist_selector.h"
109 #include "public_editor.h"
110 #include "region_layering_order_editor.h"
111 #include "rgb_macros.h"
112 #include "rhythm_ferret.h"
113 #include "selection.h"
115 #include "simpleline.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 show_me_the_size (Requisition* r, const char* what)
214 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
219 pane_size_watcher (Paned* pane)
221 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
222 it is no longer accessible. so stop that. this doesn't happen on X11,
223 just the quartz backend.
228 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
230 gint pos = pane->get_position ();
232 if (pos > max_width_of_lhs) {
233 pane->set_position (max_width_of_lhs);
239 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
241 /* time display buttons */
242 , minsec_label (_("Mins:Secs"))
243 , bbt_label (_("Bars:Beats"))
244 , timecode_label (_("Timecode"))
245 , samples_label (_("Samples"))
246 , tempo_label (_("Tempo"))
247 , meter_label (_("Meter"))
248 , mark_label (_("Location Markers"))
249 , range_mark_label (_("Range Markers"))
250 , transport_mark_label (_("Loop/Punch Ranges"))
251 , cd_mark_label (_("CD Markers"))
252 , edit_packer (4, 4, true)
254 /* the values here don't matter: layout widgets
255 reset them as needed.
258 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
260 /* tool bar related */
262 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
264 , toolbar_selection_clock_table (2,3)
266 , automation_mode_button (_("mode"))
268 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
271 , image_socket_listener(0)
276 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
277 , meters_running(false)
278 , _pending_locate_request (false)
279 , _pending_initial_locate (false)
280 , _last_cut_copy_source_track (0)
282 , _region_selection_change_updates_region_list (true)
283 , _following_mixer_selection (false)
284 , _control_point_toggled_on_press (false)
288 /* we are a singleton */
290 PublicEditor::_instance = this;
294 selection = new Selection (this);
295 cut_buffer = new Selection (this);
297 clicked_regionview = 0;
298 clicked_axisview = 0;
299 clicked_routeview = 0;
300 clicked_control_point = 0;
301 last_update_frame = 0;
302 pre_press_cursor = 0;
303 _drags = new DragManager (this);
304 current_mixer_strip = 0;
307 snap_type_strings = I18N (_snap_type_strings);
308 snap_mode_strings = I18N (_snap_mode_strings);
309 zoom_focus_strings = I18N (_zoom_focus_strings);
310 edit_point_strings = I18N (_edit_point_strings);
311 #ifdef USE_RUBBERBAND
312 rb_opt_strings = I18N (_rb_opt_strings);
316 snap_threshold = 5.0;
317 bbt_beat_subdivision = 4;
320 last_autoscroll_x = 0;
321 last_autoscroll_y = 0;
322 autoscroll_active = false;
323 autoscroll_timeout_tag = -1;
328 current_interthread_info = 0;
329 _show_measures = true;
331 show_gain_after_trim = false;
333 have_pending_keyboard_selection = false;
334 _follow_playhead = true;
335 _stationary_playhead = false;
336 editor_ruler_menu = 0;
337 no_ruler_shown_update = false;
339 range_marker_menu = 0;
340 marker_menu_item = 0;
341 tempo_or_meter_marker_menu = 0;
342 transport_marker_menu = 0;
343 new_transport_marker_menu = 0;
344 editor_mixer_strip_width = Wide;
345 show_editor_mixer_when_tracks_arrive = false;
346 region_edit_menu_split_multichannel_item = 0;
347 region_edit_menu_split_item = 0;
350 current_stepping_trackview = 0;
352 entered_regionview = 0;
354 clear_entered_track = false;
357 button_release_can_deselect = true;
358 _dragging_playhead = false;
359 _dragging_edit_point = false;
360 select_new_marker = false;
362 layering_order_editor = 0;
363 no_save_visual = false;
365 within_track_canvas = false;
367 scrubbing_direction = 0;
371 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
372 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
373 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
374 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
375 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
377 _edit_point = EditAtMouse;
378 _internal_editing = false;
379 current_canvas_cursor = 0;
381 frames_per_unit = 2048; /* too early to use reset_zoom () */
383 _scroll_callbacks = 0;
385 zoom_focus = ZoomFocusLeft;
386 set_zoom_focus (ZoomFocusLeft);
387 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
389 bbt_label.set_name ("EditorTimeButton");
390 bbt_label.set_size_request (-1, (int)timebar_height);
391 bbt_label.set_alignment (1.0, 0.5);
392 bbt_label.set_padding (5,0);
394 bbt_label.set_no_show_all();
395 minsec_label.set_name ("EditorTimeButton");
396 minsec_label.set_size_request (-1, (int)timebar_height);
397 minsec_label.set_alignment (1.0, 0.5);
398 minsec_label.set_padding (5,0);
399 minsec_label.hide ();
400 minsec_label.set_no_show_all();
401 timecode_label.set_name ("EditorTimeButton");
402 timecode_label.set_size_request (-1, (int)timebar_height);
403 timecode_label.set_alignment (1.0, 0.5);
404 timecode_label.set_padding (5,0);
405 timecode_label.hide ();
406 timecode_label.set_no_show_all();
407 samples_label.set_name ("EditorTimeButton");
408 samples_label.set_size_request (-1, (int)timebar_height);
409 samples_label.set_alignment (1.0, 0.5);
410 samples_label.set_padding (5,0);
411 samples_label.hide ();
412 samples_label.set_no_show_all();
414 tempo_label.set_name ("EditorTimeButton");
415 tempo_label.set_size_request (-1, (int)timebar_height);
416 tempo_label.set_alignment (1.0, 0.5);
417 tempo_label.set_padding (5,0);
419 tempo_label.set_no_show_all();
421 meter_label.set_name ("EditorTimeButton");
422 meter_label.set_size_request (-1, (int)timebar_height);
423 meter_label.set_alignment (1.0, 0.5);
424 meter_label.set_padding (5,0);
426 meter_label.set_no_show_all();
428 mark_label.set_name ("EditorTimeButton");
429 mark_label.set_size_request (-1, (int)timebar_height);
430 mark_label.set_alignment (1.0, 0.5);
431 mark_label.set_padding (5,0);
433 mark_label.set_no_show_all();
435 cd_mark_label.set_name ("EditorTimeButton");
436 cd_mark_label.set_size_request (-1, (int)timebar_height);
437 cd_mark_label.set_alignment (1.0, 0.5);
438 cd_mark_label.set_padding (5,0);
439 cd_mark_label.hide();
440 cd_mark_label.set_no_show_all();
442 range_mark_label.set_name ("EditorTimeButton");
443 range_mark_label.set_size_request (-1, (int)timebar_height);
444 range_mark_label.set_alignment (1.0, 0.5);
445 range_mark_label.set_padding (5,0);
446 range_mark_label.hide();
447 range_mark_label.set_no_show_all();
449 transport_mark_label.set_name ("EditorTimeButton");
450 transport_mark_label.set_size_request (-1, (int)timebar_height);
451 transport_mark_label.set_alignment (1.0, 0.5);
452 transport_mark_label.set_padding (5,0);
453 transport_mark_label.hide();
454 transport_mark_label.set_no_show_all();
456 initialize_rulers ();
457 initialize_canvas ();
459 _summary = new EditorSummary (this);
461 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
462 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
464 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
466 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
467 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
469 edit_controls_vbox.set_spacing (0);
470 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
471 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
473 HBox* h = manage (new HBox);
474 _group_tabs = new EditorGroupTabs (this);
475 h->pack_start (*_group_tabs, PACK_SHRINK);
476 h->pack_start (edit_controls_vbox);
477 controls_layout.add (*h);
479 controls_layout.set_name ("EditControlsBase");
480 controls_layout.add_events (Gdk::SCROLL_MASK);
481 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
483 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
484 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
486 _cursors = new MouseCursors;
488 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
489 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
490 0.0, 1.0, 100.0, 1.0));
492 pad_line_1->property_color_rgba() = 0xFF0000FF;
497 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
498 time_canvas_vbox.set_size_request (-1, -1);
500 ruler_label_event_box.add (ruler_label_vbox);
501 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
502 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
504 time_button_event_box.add (time_button_vbox);
505 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
506 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
508 /* these enable us to have a dedicated window (for cursor setting, etc.)
509 for the canvas areas.
512 track_canvas_event_box.add (*track_canvas);
514 time_canvas_event_box.add (time_canvas_vbox);
515 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
517 edit_packer.set_col_spacings (0);
518 edit_packer.set_row_spacings (0);
519 edit_packer.set_homogeneous (false);
520 edit_packer.set_border_width (0);
521 edit_packer.set_name ("EditorWindow");
523 /* labels for the rulers */
524 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
525 /* labels for the marker "tracks" */
526 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
528 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
530 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
532 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
534 bottom_hbox.set_border_width (2);
535 bottom_hbox.set_spacing (3);
537 _route_groups = new EditorRouteGroups (this);
538 _routes = new EditorRoutes (this);
539 _regions = new EditorRegions (this);
540 _snapshots = new EditorSnapshots (this);
541 _locations = new EditorLocations (this);
543 add_notebook_page (_("Regions"), _regions->widget ());
544 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
545 add_notebook_page (_("Snapshots"), _snapshots->widget ());
546 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
547 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
549 _the_notebook.set_show_tabs (true);
550 _the_notebook.set_scrollable (true);
551 _the_notebook.popup_disable ();
552 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
553 _the_notebook.show_all ();
555 _notebook_shrunk = false;
557 editor_summary_pane.pack1(edit_packer);
559 Button* summary_arrows_left_left = manage (new Button);
560 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
561 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
562 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
564 Button* summary_arrows_left_right = manage (new Button);
565 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
566 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
567 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 VBox* summary_arrows_left = manage (new VBox);
570 summary_arrows_left->pack_start (*summary_arrows_left_left);
571 summary_arrows_left->pack_start (*summary_arrows_left_right);
573 Button* summary_arrows_right_up = manage (new Button);
574 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
575 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
576 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
578 Button* summary_arrows_right_down = manage (new Button);
579 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
580 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
581 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 VBox* summary_arrows_right = manage (new VBox);
584 summary_arrows_right->pack_start (*summary_arrows_right_up);
585 summary_arrows_right->pack_start (*summary_arrows_right_down);
587 Frame* summary_frame = manage (new Frame);
588 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
590 summary_frame->add (*_summary);
591 summary_frame->show ();
593 _summary_hbox.pack_start (*summary_arrows_left, false, false);
594 _summary_hbox.pack_start (*summary_frame, true, true);
595 _summary_hbox.pack_start (*summary_arrows_right, false, false);
597 editor_summary_pane.pack2 (_summary_hbox);
599 edit_pane.pack1 (editor_summary_pane, true, true);
600 edit_pane.pack2 (_the_notebook, false, true);
602 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
604 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
606 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
608 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
609 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
611 top_hbox.pack_start (toolbar_frame);
613 HBox *hbox = manage (new HBox);
614 hbox->pack_start (edit_pane, true, true);
616 global_vpacker.pack_start (top_hbox, false, false);
617 global_vpacker.pack_start (*hbox, true, true);
619 global_hpacker.pack_start (global_vpacker, true, true);
621 set_name ("EditorWindow");
622 add_accel_group (ActionManager::ui_manager->get_accel_group());
624 status_bar_hpacker.show ();
626 vpacker.pack_end (status_bar_hpacker, false, false);
627 vpacker.pack_end (global_hpacker, true, true);
629 /* register actions now so that set_state() can find them and set toggles/checks etc */
632 /* when we start using our own keybinding system for the editor, this
633 * will be uncommented
639 _snap_type = SnapToBeat;
640 set_snap_to (_snap_type);
641 _snap_mode = SnapOff;
642 set_snap_mode (_snap_mode);
643 set_mouse_mode (MouseObject, true);
644 pre_internal_mouse_mode = MouseObject;
645 pre_internal_snap_type = _snap_type;
646 pre_internal_snap_mode = _snap_mode;
647 internal_snap_type = _snap_type;
648 internal_snap_mode = _snap_mode;
649 set_edit_point_preference (EditAtMouse, true);
651 _playlist_selector = new PlaylistSelector();
652 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
654 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
658 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
659 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
661 nudge_forward_button.set_name ("TransportButton");
662 nudge_backward_button.set_name ("TransportButton");
664 fade_context_menu.set_name ("ArdourContextMenu");
666 /* icons, titles, WM stuff */
668 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
669 Glib::RefPtr<Gdk::Pixbuf> icon;
671 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
672 window_icons.push_back (icon);
674 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
675 window_icons.push_back (icon);
677 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
678 window_icons.push_back (icon);
680 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
681 window_icons.push_back (icon);
683 if (!window_icons.empty()) {
684 // set_icon_list (window_icons);
685 set_default_icon_list (window_icons);
688 WindowTitle title(Glib::get_application_name());
689 title += _("Editor");
690 set_title (title.get_string());
691 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
694 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
696 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
697 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
699 /* allow external control surfaces/protocols to do various things */
701 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
702 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
703 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
704 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
705 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
706 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
707 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
708 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
709 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
710 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
711 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
712 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
713 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
714 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
716 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
717 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
718 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
719 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
720 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
722 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
724 /* problematic: has to return a value and thus cannot be x-thread */
726 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
728 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
730 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
732 _ignore_region_action = false;
733 _last_region_menu_was_main = false;
734 _popup_region_menu_item = 0;
736 _show_marker_lines = false;
737 _over_region_trim_target = false;
739 /* Button bindings */
741 button_bindings = new Bindings;
743 XMLNode* node = button_settings();
745 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
746 button_bindings->load (**i);
753 setup_fade_images ();
759 if(image_socket_listener) {
760 if(image_socket_listener->is_connected())
762 image_socket_listener->close_connection() ;
765 delete image_socket_listener ;
766 image_socket_listener = 0 ;
770 delete button_bindings;
772 delete _route_groups;
778 Editor::button_settings () const
780 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
781 XMLNode* node = find_named_node (*settings, X_("Buttons"));
784 node = new XMLNode (X_("Buttons"));
791 Editor::add_toplevel_controls (Container& cont)
793 vpacker.pack_start (cont, false, false);
798 Editor::catch_vanishing_regionview (RegionView *rv)
800 /* note: the selection will take care of the vanishing
801 audioregionview by itself.
804 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
808 if (clicked_regionview == rv) {
809 clicked_regionview = 0;
812 if (entered_regionview == rv) {
813 set_entered_regionview (0);
816 if (!_all_region_actions_sensitized) {
817 sensitize_all_region_actions (true);
820 _over_region_trim_target = false;
824 Editor::set_entered_regionview (RegionView* rv)
826 if (rv == entered_regionview) {
830 if (entered_regionview) {
831 entered_regionview->exited ();
834 if ((entered_regionview = rv) != 0) {
835 entered_regionview->entered (internal_editing ());
838 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
839 /* This RegionView entry might have changed what region actions
840 are allowed, so sensitize them all in case a key is pressed.
842 sensitize_all_region_actions (true);
847 Editor::set_entered_track (TimeAxisView* tav)
850 entered_track->exited ();
853 if ((entered_track = tav) != 0) {
854 entered_track->entered ();
859 Editor::show_window ()
861 if (!is_visible ()) {
864 /* XXX: this is a bit unfortunate; it would probably
865 be nicer if we could just call show () above rather
866 than needing the show_all ()
869 /* re-hide stuff if necessary */
870 editor_list_button_toggled ();
871 parameter_changed ("show-summary");
872 parameter_changed ("show-group-tabs");
873 parameter_changed ("show-zoom-tools");
875 /* now reset all audio_time_axis heights, because widgets might need
881 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
882 tv = (static_cast<TimeAxisView*>(*i));
886 if (current_mixer_strip) {
887 current_mixer_strip->hide_things ();
888 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
896 Editor::instant_save ()
898 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
903 _session->add_instant_xml(get_state());
905 Config->add_instant_xml(get_state());
910 Editor::zoom_adjustment_changed ()
916 double fpu = zoom_range_clock->current_duration() / _canvas_width;
920 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
921 } else if (fpu > _session->current_end_frame() / _canvas_width) {
922 fpu = _session->current_end_frame() / _canvas_width;
923 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
930 Editor::control_vertical_zoom_in_all ()
932 tav_zoom_smooth (false, true);
936 Editor::control_vertical_zoom_out_all ()
938 tav_zoom_smooth (true, true);
942 Editor::control_vertical_zoom_in_selected ()
944 tav_zoom_smooth (false, false);
948 Editor::control_vertical_zoom_out_selected ()
950 tav_zoom_smooth (true, false);
954 Editor::control_view (uint32_t view)
956 goto_visual_state (view);
960 Editor::control_unselect ()
962 selection->clear_tracks ();
966 Editor::control_select (uint32_t rid, Selection::Operation op)
968 /* handles the (static) signal from the ControlProtocol class that
969 * requests setting the selected track to a given RID
976 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
982 TimeAxisView* tav = axis_view_from_route (r);
987 selection->add (tav);
989 case Selection::Toggle:
990 selection->toggle (tav);
992 case Selection::Extend:
995 selection->set (tav);
999 selection->clear_tracks ();
1004 Editor::control_step_tracks_up ()
1006 scroll_tracks_up_line ();
1010 Editor::control_step_tracks_down ()
1012 scroll_tracks_down_line ();
1016 Editor::control_scroll (float fraction)
1018 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1024 double step = fraction * current_page_frames();
1027 _control_scroll_target is an optional<T>
1029 it acts like a pointer to an framepos_t, with
1030 a operator conversion to boolean to check
1031 that it has a value could possibly use
1032 playhead_cursor->current_frame to store the
1033 value and a boolean in the class to know
1034 when it's out of date
1037 if (!_control_scroll_target) {
1038 _control_scroll_target = _session->transport_frame();
1039 _dragging_playhead = true;
1042 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1043 *_control_scroll_target = 0;
1044 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1045 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1047 *_control_scroll_target += (framepos_t) floor (step);
1050 /* move visuals, we'll catch up with it later */
1052 playhead_cursor->set_position (*_control_scroll_target);
1053 UpdateAllTransportClocks (*_control_scroll_target);
1055 if (*_control_scroll_target > (current_page_frames() / 2)) {
1056 /* try to center PH in window */
1057 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1063 Now we do a timeout to actually bring the session to the right place
1064 according to the playhead. This is to avoid reading disk buffers on every
1065 call to control_scroll, which is driven by ScrollTimeline and therefore
1066 probably by a control surface wheel which can generate lots of events.
1068 /* cancel the existing timeout */
1070 control_scroll_connection.disconnect ();
1072 /* add the next timeout */
1074 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1078 Editor::deferred_control_scroll (framepos_t /*target*/)
1080 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1081 // reset for next stream
1082 _control_scroll_target = boost::none;
1083 _dragging_playhead = false;
1088 Editor::access_action (std::string action_group, std::string action_item)
1094 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1097 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1105 Editor::on_realize ()
1107 Window::on_realize ();
1112 Editor::map_position_change (framepos_t frame)
1114 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1116 if (_session == 0) {
1120 if (_follow_playhead) {
1121 center_screen (frame);
1124 playhead_cursor->set_position (frame);
1128 Editor::center_screen (framepos_t frame)
1130 double page = _canvas_width * frames_per_unit;
1132 /* if we're off the page, then scroll.
1135 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1136 center_screen_internal (frame, page);
1141 Editor::center_screen_internal (framepos_t frame, float page)
1146 frame -= (framepos_t) page;
1151 reset_x_origin (frame);
1156 Editor::update_title ()
1158 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1161 bool dirty = _session->dirty();
1163 string session_name;
1165 if (_session->snap_name() != _session->name()) {
1166 session_name = _session->snap_name();
1168 session_name = _session->name();
1172 session_name = "*" + session_name;
1175 WindowTitle title(session_name);
1176 title += Glib::get_application_name();
1177 set_title (title.get_string());
1182 Editor::set_session (Session *t)
1184 SessionHandlePtr::set_session (t);
1190 zoom_range_clock->set_session (_session);
1191 _playlist_selector->set_session (_session);
1192 nudge_clock->set_session (_session);
1193 _summary->set_session (_session);
1194 _group_tabs->set_session (_session);
1195 _route_groups->set_session (_session);
1196 _regions->set_session (_session);
1197 _snapshots->set_session (_session);
1198 _routes->set_session (_session);
1199 _locations->set_session (_session);
1201 if (rhythm_ferret) {
1202 rhythm_ferret->set_session (_session);
1205 if (analysis_window) {
1206 analysis_window->set_session (_session);
1210 sfbrowser->set_session (_session);
1213 compute_fixed_ruler_scale ();
1215 /* Make sure we have auto loop and auto punch ranges */
1217 Location* loc = _session->locations()->auto_loop_location();
1219 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1221 if (loc->start() == loc->end()) {
1222 loc->set_end (loc->start() + 1);
1225 _session->locations()->add (loc, false);
1226 _session->set_auto_loop_location (loc);
1229 loc->set_name (_("Loop"));
1232 loc = _session->locations()->auto_punch_location();
1235 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1237 if (loc->start() == loc->end()) {
1238 loc->set_end (loc->start() + 1);
1241 _session->locations()->add (loc, false);
1242 _session->set_auto_punch_location (loc);
1245 loc->set_name (_("Punch"));
1248 refresh_location_display ();
1250 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1251 the selected Marker; this needs the LocationMarker list to be available.
1253 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1254 set_state (*node, Stateful::loading_state_version);
1256 /* catch up with the playhead */
1258 _session->request_locate (playhead_cursor->current_frame);
1259 _pending_initial_locate = true;
1263 /* These signals can all be emitted by a non-GUI thread. Therefore the
1264 handlers for them must not attempt to directly interact with the GUI,
1265 but use Gtkmm2ext::UI::instance()->call_slot();
1268 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1269 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1270 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1271 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::handle_new_route, this, _1), gui_context());
1272 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1273 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1274 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1275 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1276 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1277 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1278 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1279 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1280 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1281 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1283 playhead_cursor->canvas_item.show ();
1285 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1286 Config->map_parameters (pc);
1287 _session->config.map_parameters (pc);
1289 restore_ruler_visibility ();
1290 //tempo_map_changed (PropertyChange (0));
1291 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1293 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1294 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1297 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1298 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1301 switch (_snap_type) {
1302 case SnapToRegionStart:
1303 case SnapToRegionEnd:
1304 case SnapToRegionSync:
1305 case SnapToRegionBoundary:
1306 build_region_boundary_cache ();
1313 /* register for undo history */
1314 _session->register_with_memento_command_factory(id(), this);
1316 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1318 start_updating_meters ();
1322 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1324 if (a->get_name() == "RegionMenu") {
1325 /* When the main menu's region menu is opened, we setup the actions so that they look right
1326 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1327 so we resensitize all region actions when the entered regionview or the region selection
1328 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1329 happens after the region context menu is opened. So we set a flag here, too.
1333 sensitize_the_right_region_actions ();
1334 _last_region_menu_was_main = true;
1339 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1341 using namespace Menu_Helpers;
1343 void (Editor::*emf)(FadeShape);
1344 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1347 images = &_xfade_in_images;
1348 emf = &Editor::set_fade_in_shape;
1350 images = &_xfade_out_images;
1351 emf = &Editor::set_fade_out_shape;
1356 _("Linear (for highly correlated material)"),
1357 *(*images)[FadeLinear],
1358 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1362 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1367 *(*images)[FadeConstantPower],
1368 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1371 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1376 *(*images)[FadeSymmetric],
1377 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1381 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1386 *(*images)[FadeSlow],
1387 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1390 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1395 *(*images)[FadeFast],
1396 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1399 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1402 /** Pop up a context menu for when the user clicks on a start crossfade */
1404 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1406 using namespace Menu_Helpers;
1408 MenuList& items (xfade_in_context_menu.items());
1410 if (items.empty()) {
1411 fill_xfade_menu (items, true);
1414 xfade_in_context_menu.popup (button, time);
1417 /** Pop up a context menu for when the user clicks on an end crossfade */
1419 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1421 using namespace Menu_Helpers;
1423 MenuList& items (xfade_out_context_menu.items());
1425 if (items.empty()) {
1426 fill_xfade_menu (items, false);
1429 xfade_out_context_menu.popup (button, time);
1433 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1435 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1437 using namespace Menu_Helpers;
1438 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1441 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1445 MenuList& items (fade_context_menu.items());
1448 switch (item_type) {
1450 case FadeInHandleItem:
1451 if (arv->audio_region()->fade_in_active()) {
1452 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1454 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1457 items.push_back (SeparatorElem());
1459 if (Profile->get_sae()) {
1461 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1462 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1469 *_fade_in_images[FadeLinear],
1470 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1474 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1479 *_fade_in_images[FadeSlow],
1480 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1483 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1488 *_fade_in_images[FadeFast],
1489 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1492 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1497 *_fade_in_images[FadeSymmetric],
1498 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1503 _("Constant Power"),
1504 *_fade_in_images[FadeConstantPower],
1505 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1508 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1514 case FadeOutHandleItem:
1515 if (arv->audio_region()->fade_out_active()) {
1516 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1518 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1521 items.push_back (SeparatorElem());
1523 if (Profile->get_sae()) {
1524 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1525 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1531 *_fade_out_images[FadeLinear],
1532 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1536 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1541 *_fade_out_images[FadeSlow],
1542 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1545 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1550 *_fade_out_images[FadeFast],
1551 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1554 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1559 *_fade_out_images[FadeSymmetric],
1560 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1565 _("Constant Power"),
1566 *_fade_out_images[FadeConstantPower],
1567 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1570 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1576 fatal << _("programming error: ")
1577 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1582 fade_context_menu.popup (button, time);
1586 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1588 using namespace Menu_Helpers;
1589 Menu* (Editor::*build_menu_function)();
1592 switch (item_type) {
1594 case RegionViewName:
1595 case RegionViewNameHighlight:
1596 case LeftFrameHandle:
1597 case RightFrameHandle:
1598 if (with_selection) {
1599 build_menu_function = &Editor::build_track_selection_context_menu;
1601 build_menu_function = &Editor::build_track_region_context_menu;
1606 if (with_selection) {
1607 build_menu_function = &Editor::build_track_selection_context_menu;
1609 build_menu_function = &Editor::build_track_context_menu;
1614 if (clicked_routeview->track()) {
1615 build_menu_function = &Editor::build_track_context_menu;
1617 build_menu_function = &Editor::build_track_bus_context_menu;
1622 /* probably shouldn't happen but if it does, we don't care */
1626 menu = (this->*build_menu_function)();
1627 menu->set_name ("ArdourContextMenu");
1629 /* now handle specific situations */
1631 switch (item_type) {
1633 case RegionViewName:
1634 case RegionViewNameHighlight:
1635 case LeftFrameHandle:
1636 case RightFrameHandle:
1637 if (!with_selection) {
1638 if (region_edit_menu_split_item) {
1639 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1640 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1642 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1645 if (region_edit_menu_split_multichannel_item) {
1646 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1647 region_edit_menu_split_multichannel_item->set_sensitive (true);
1649 region_edit_menu_split_multichannel_item->set_sensitive (false);
1662 /* probably shouldn't happen but if it does, we don't care */
1666 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1668 /* Bounce to disk */
1670 using namespace Menu_Helpers;
1671 MenuList& edit_items = menu->items();
1673 edit_items.push_back (SeparatorElem());
1675 switch (clicked_routeview->audio_track()->freeze_state()) {
1676 case AudioTrack::NoFreeze:
1677 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1680 case AudioTrack::Frozen:
1681 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1684 case AudioTrack::UnFrozen:
1685 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1691 if (item_type == StreamItem && clicked_routeview) {
1692 clicked_routeview->build_underlay_menu(menu);
1695 /* When the region menu is opened, we setup the actions so that they look right
1698 sensitize_the_right_region_actions ();
1699 _last_region_menu_was_main = false;
1701 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1702 menu->popup (button, time);
1706 Editor::build_track_context_menu ()
1708 using namespace Menu_Helpers;
1710 MenuList& edit_items = track_context_menu.items();
1713 add_dstream_context_items (edit_items);
1714 return &track_context_menu;
1718 Editor::build_track_bus_context_menu ()
1720 using namespace Menu_Helpers;
1722 MenuList& edit_items = track_context_menu.items();
1725 add_bus_context_items (edit_items);
1726 return &track_context_menu;
1730 Editor::build_track_region_context_menu ()
1732 using namespace Menu_Helpers;
1733 MenuList& edit_items = track_region_context_menu.items();
1736 /* we've just cleared the track region context menu, so the menu that these
1737 two items were on will have disappeared; stop them dangling.
1739 region_edit_menu_split_item = 0;
1740 region_edit_menu_split_multichannel_item = 0;
1742 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1745 boost::shared_ptr<Track> tr;
1746 boost::shared_ptr<Playlist> pl;
1748 if ((tr = rtv->track())) {
1749 add_region_context_items (edit_items, tr);
1753 add_dstream_context_items (edit_items);
1755 return &track_region_context_menu;
1759 Editor::analyze_region_selection ()
1761 if (analysis_window == 0) {
1762 analysis_window = new AnalysisWindow();
1765 analysis_window->set_session(_session);
1767 analysis_window->show_all();
1770 analysis_window->set_regionmode();
1771 analysis_window->analyze();
1773 analysis_window->present();
1777 Editor::analyze_range_selection()
1779 if (analysis_window == 0) {
1780 analysis_window = new AnalysisWindow();
1783 analysis_window->set_session(_session);
1785 analysis_window->show_all();
1788 analysis_window->set_rangemode();
1789 analysis_window->analyze();
1791 analysis_window->present();
1795 Editor::build_track_selection_context_menu ()
1797 using namespace Menu_Helpers;
1798 MenuList& edit_items = track_selection_context_menu.items();
1799 edit_items.clear ();
1801 add_selection_context_items (edit_items);
1802 // edit_items.push_back (SeparatorElem());
1803 // add_dstream_context_items (edit_items);
1805 return &track_selection_context_menu;
1809 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1811 using namespace Menu_Helpers;
1813 /* OK, stick the region submenu at the top of the list, and then add
1817 RegionSelection rs = get_regions_from_selection_and_entered ();
1819 string::size_type pos = 0;
1820 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1822 /* we have to hack up the region name because "_" has a special
1823 meaning for menu titles.
1826 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1827 menu_item_name.replace (pos, 1, "__");
1831 if (_popup_region_menu_item == 0) {
1832 _popup_region_menu_item = new MenuItem (menu_item_name);
1833 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1834 _popup_region_menu_item->show ();
1836 _popup_region_menu_item->set_label (menu_item_name);
1839 const framepos_t position = get_preferred_edit_position (false, true);
1841 edit_items.push_back (*_popup_region_menu_item);
1842 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1843 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1845 edit_items.push_back (SeparatorElem());
1848 /** Add context menu items relevant to selection ranges.
1849 * @param edit_items List to add the items to.
1852 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1854 using namespace Menu_Helpers;
1856 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1857 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1859 edit_items.push_back (SeparatorElem());
1860 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1862 edit_items.push_back (SeparatorElem());
1864 edit_items.push_back (
1866 _("Move Range Start to Previous Region Boundary"),
1867 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1871 edit_items.push_back (
1873 _("Move Range Start to Next Region Boundary"),
1874 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1878 edit_items.push_back (
1880 _("Move Range End to Previous Region Boundary"),
1881 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1885 edit_items.push_back (
1887 _("Move Range End to Next Region Boundary"),
1888 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1892 edit_items.push_back (SeparatorElem());
1893 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1894 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1896 edit_items.push_back (SeparatorElem());
1897 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1899 edit_items.push_back (SeparatorElem());
1900 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1901 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1903 edit_items.push_back (SeparatorElem());
1904 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1906 edit_items.push_back (SeparatorElem());
1907 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1908 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1909 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1913 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1914 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1915 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1916 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1921 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1923 using namespace Menu_Helpers;
1927 Menu *play_menu = manage (new Menu);
1928 MenuList& play_items = play_menu->items();
1929 play_menu->set_name ("ArdourContextMenu");
1931 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1932 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1933 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1934 play_items.push_back (SeparatorElem());
1935 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1937 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1941 Menu *select_menu = manage (new Menu);
1942 MenuList& select_items = select_menu->items();
1943 select_menu->set_name ("ArdourContextMenu");
1945 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1946 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1947 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1948 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1949 select_items.push_back (SeparatorElem());
1950 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1951 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1952 select_items.push_back (SeparatorElem());
1953 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1954 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1955 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1956 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1957 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1958 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1959 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1961 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1965 Menu *cutnpaste_menu = manage (new Menu);
1966 MenuList& cutnpaste_items = cutnpaste_menu->items();
1967 cutnpaste_menu->set_name ("ArdourContextMenu");
1969 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1970 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1971 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1973 cutnpaste_items.push_back (SeparatorElem());
1975 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1976 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1978 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1980 /* Adding new material */
1982 edit_items.push_back (SeparatorElem());
1983 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1984 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1988 Menu *nudge_menu = manage (new Menu());
1989 MenuList& nudge_items = nudge_menu->items();
1990 nudge_menu->set_name ("ArdourContextMenu");
1992 edit_items.push_back (SeparatorElem());
1993 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1994 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1995 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1996 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1998 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2002 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2004 using namespace Menu_Helpers;
2008 Menu *play_menu = manage (new Menu);
2009 MenuList& play_items = play_menu->items();
2010 play_menu->set_name ("ArdourContextMenu");
2012 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2013 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2014 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2018 Menu *select_menu = manage (new Menu);
2019 MenuList& select_items = select_menu->items();
2020 select_menu->set_name ("ArdourContextMenu");
2022 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2023 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2024 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2025 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2026 select_items.push_back (SeparatorElem());
2027 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2028 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2029 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2030 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2032 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2036 Menu *cutnpaste_menu = manage (new Menu);
2037 MenuList& cutnpaste_items = cutnpaste_menu->items();
2038 cutnpaste_menu->set_name ("ArdourContextMenu");
2040 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2041 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2042 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2044 Menu *nudge_menu = manage (new Menu());
2045 MenuList& nudge_items = nudge_menu->items();
2046 nudge_menu->set_name ("ArdourContextMenu");
2048 edit_items.push_back (SeparatorElem());
2049 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2050 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2051 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2052 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2054 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2058 Editor::snap_type() const
2064 Editor::snap_mode() const
2070 Editor::set_snap_to (SnapType st)
2072 unsigned int snap_ind = (unsigned int)st;
2076 if (snap_ind > snap_type_strings.size() - 1) {
2078 _snap_type = (SnapType)snap_ind;
2081 string str = snap_type_strings[snap_ind];
2083 if (str != snap_type_selector.get_active_text()) {
2084 snap_type_selector.set_active_text (str);
2089 switch (_snap_type) {
2090 case SnapToBeatDiv128:
2091 case SnapToBeatDiv64:
2092 case SnapToBeatDiv32:
2093 case SnapToBeatDiv28:
2094 case SnapToBeatDiv24:
2095 case SnapToBeatDiv20:
2096 case SnapToBeatDiv16:
2097 case SnapToBeatDiv14:
2098 case SnapToBeatDiv12:
2099 case SnapToBeatDiv10:
2100 case SnapToBeatDiv8:
2101 case SnapToBeatDiv7:
2102 case SnapToBeatDiv6:
2103 case SnapToBeatDiv5:
2104 case SnapToBeatDiv4:
2105 case SnapToBeatDiv3:
2106 case SnapToBeatDiv2:
2107 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2108 update_tempo_based_rulers ();
2111 case SnapToRegionStart:
2112 case SnapToRegionEnd:
2113 case SnapToRegionSync:
2114 case SnapToRegionBoundary:
2115 build_region_boundary_cache ();
2123 SnapChanged (); /* EMIT SIGNAL */
2127 Editor::set_snap_mode (SnapMode mode)
2130 string str = snap_mode_strings[(int)mode];
2132 if (str != snap_mode_selector.get_active_text ()) {
2133 snap_mode_selector.set_active_text (str);
2139 Editor::set_edit_point_preference (EditPoint ep, bool force)
2141 bool changed = (_edit_point != ep);
2144 string str = edit_point_strings[(int)ep];
2146 if (str != edit_point_selector.get_active_text ()) {
2147 edit_point_selector.set_active_text (str);
2150 set_canvas_cursor ();
2152 if (!force && !changed) {
2156 const char* action=NULL;
2158 switch (_edit_point) {
2159 case EditAtPlayhead:
2160 action = "edit-at-playhead";
2162 case EditAtSelectedMarker:
2163 action = "edit-at-marker";
2166 action = "edit-at-mouse";
2170 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2172 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2176 bool in_track_canvas;
2178 if (!mouse_frame (foo, in_track_canvas)) {
2179 in_track_canvas = false;
2182 reset_canvas_action_sensitivity (in_track_canvas);
2188 Editor::set_state (const XMLNode& node, int /*version*/)
2190 const XMLProperty* prop;
2197 g.base_width = default_width;
2198 g.base_height = default_height;
2202 if ((geometry = find_named_node (node, "geometry")) != 0) {
2206 if ((prop = geometry->property("x_size")) == 0) {
2207 prop = geometry->property ("x-size");
2210 g.base_width = atoi(prop->value());
2212 if ((prop = geometry->property("y_size")) == 0) {
2213 prop = geometry->property ("y-size");
2216 g.base_height = atoi(prop->value());
2219 if ((prop = geometry->property ("x_pos")) == 0) {
2220 prop = geometry->property ("x-pos");
2223 x = atoi (prop->value());
2226 if ((prop = geometry->property ("y_pos")) == 0) {
2227 prop = geometry->property ("y-pos");
2230 y = atoi (prop->value());
2234 set_default_size (g.base_width, g.base_height);
2237 if (_session && (prop = node.property ("playhead"))) {
2239 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2240 playhead_cursor->set_position (pos);
2242 playhead_cursor->set_position (0);
2245 if ((prop = node.property ("mixer-width"))) {
2246 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2249 if ((prop = node.property ("zoom-focus"))) {
2250 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2253 if ((prop = node.property ("zoom"))) {
2254 reset_zoom (PBD::atof (prop->value()));
2256 reset_zoom (frames_per_unit);
2259 if ((prop = node.property ("snap-to"))) {
2260 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2263 if ((prop = node.property ("snap-mode"))) {
2264 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2267 if ((prop = node.property ("internal-snap-to"))) {
2268 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2271 if ((prop = node.property ("internal-snap-mode"))) {
2272 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2275 if ((prop = node.property ("pre-internal-snap-to"))) {
2276 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2279 if ((prop = node.property ("pre-internal-snap-mode"))) {
2280 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2283 if ((prop = node.property ("mouse-mode"))) {
2284 MouseMode m = str2mousemode(prop->value());
2285 set_mouse_mode (m, true);
2287 set_mouse_mode (MouseObject, true);
2290 if ((prop = node.property ("left-frame")) != 0) {
2292 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2296 reset_x_origin (pos);
2300 if ((prop = node.property ("y-origin")) != 0) {
2301 reset_y_origin (atof (prop->value ()));
2304 if ((prop = node.property ("internal-edit"))) {
2305 bool yn = string_is_affirmative (prop->value());
2306 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2308 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2309 tact->set_active (!yn);
2310 tact->set_active (yn);
2314 if ((prop = node.property ("join-object-range"))) {
2315 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2318 if ((prop = node.property ("edit-point"))) {
2319 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2322 if ((prop = node.property ("show-measures"))) {
2323 bool yn = string_is_affirmative (prop->value());
2324 _show_measures = yn;
2325 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2327 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2328 /* do it twice to force the change */
2329 tact->set_active (!yn);
2330 tact->set_active (yn);
2334 if ((prop = node.property ("follow-playhead"))) {
2335 bool yn = string_is_affirmative (prop->value());
2336 set_follow_playhead (yn);
2337 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2339 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2340 if (tact->get_active() != yn) {
2341 tact->set_active (yn);
2346 if ((prop = node.property ("stationary-playhead"))) {
2347 bool yn = string_is_affirmative (prop->value());
2348 set_stationary_playhead (yn);
2349 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2351 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2352 if (tact->get_active() != yn) {
2353 tact->set_active (yn);
2358 if ((prop = node.property ("region-list-sort-type"))) {
2359 RegionListSortType st;
2360 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2363 if ((prop = node.property ("show-editor-mixer"))) {
2365 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2368 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2369 bool yn = string_is_affirmative (prop->value());
2371 /* do it twice to force the change */
2373 tact->set_active (!yn);
2374 tact->set_active (yn);
2377 if ((prop = node.property ("show-editor-list"))) {
2379 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2382 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2383 bool yn = string_is_affirmative (prop->value());
2385 /* do it twice to force the change */
2387 tact->set_active (!yn);
2388 tact->set_active (yn);
2391 if ((prop = node.property (X_("editor-list-page")))) {
2392 _the_notebook.set_current_page (atoi (prop->value ()));
2395 if ((prop = node.property (X_("show-marker-lines")))) {
2396 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2398 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2399 bool yn = string_is_affirmative (prop->value ());
2401 tact->set_active (!yn);
2402 tact->set_active (yn);
2405 XMLNodeList children = node.children ();
2406 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2407 selection->set_state (**i, Stateful::current_state_version);
2408 _regions->set_state (**i);
2411 if ((prop = node.property ("maximised"))) {
2412 bool yn = string_is_affirmative (prop->value());
2414 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2418 if ((prop = node.property ("nudge-clock-value"))) {
2420 sscanf (prop->value().c_str(), "%" PRId64, &f);
2421 nudge_clock->set (f);
2423 nudge_clock->set_mode (AudioClock::Timecode);
2424 nudge_clock->set (_session->frame_rate() * 5, true);
2431 Editor::get_state ()
2433 XMLNode* node = new XMLNode ("Editor");
2436 id().print (buf, sizeof (buf));
2437 node->add_property ("id", buf);
2439 if (is_realized()) {
2440 Glib::RefPtr<Gdk::Window> win = get_window();
2442 int x, y, width, height;
2443 win->get_root_origin(x, y);
2444 win->get_size(width, height);
2446 XMLNode* geometry = new XMLNode ("geometry");
2448 snprintf(buf, sizeof(buf), "%d", width);
2449 geometry->add_property("x-size", string(buf));
2450 snprintf(buf, sizeof(buf), "%d", height);
2451 geometry->add_property("y-size", string(buf));
2452 snprintf(buf, sizeof(buf), "%d", x);
2453 geometry->add_property("x-pos", string(buf));
2454 snprintf(buf, sizeof(buf), "%d", y);
2455 geometry->add_property("y-pos", string(buf));
2456 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2457 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2458 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2459 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2460 geometry->add_property("edit-vertical-pane-pos", string(buf));
2462 node->add_child_nocopy (*geometry);
2465 maybe_add_mixer_strip_width (*node);
2467 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2468 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2469 node->add_property ("zoom", buf);
2470 node->add_property ("snap-to", enum_2_string (_snap_type));
2471 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2472 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2473 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2474 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2475 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2476 node->add_property ("edit-point", enum_2_string (_edit_point));
2478 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2479 node->add_property ("playhead", buf);
2480 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2481 node->add_property ("left-frame", buf);
2482 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2483 node->add_property ("y-origin", buf);
2485 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2486 node->add_property ("maximised", _maximised ? "yes" : "no");
2487 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2488 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2489 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2490 node->add_property ("mouse-mode", enum2str(mouse_mode));
2491 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2492 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2494 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2496 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2497 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2500 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2502 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2503 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2506 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2507 node->add_property (X_("editor-list-page"), buf);
2509 if (button_bindings) {
2510 XMLNode* bb = new XMLNode (X_("Buttons"));
2511 button_bindings->save (*bb);
2512 node->add_child_nocopy (*bb);
2515 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2517 node->add_child_nocopy (selection->get_state ());
2518 node->add_child_nocopy (_regions->get_state ());
2520 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2521 node->add_property ("nudge-clock-value", buf);
2528 /** @param y y offset from the top of all trackviews.
2529 * @return pair: TimeAxisView that y is over, layer index.
2530 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2531 * in stacked or expanded region display mode, otherwise 0.
2533 std::pair<TimeAxisView *, double>
2534 Editor::trackview_by_y_position (double y)
2536 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2538 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2544 return std::make_pair ( (TimeAxisView *) 0, 0);
2547 /** Snap a position to the grid, if appropriate, taking into account current
2548 * grid settings and also the state of any snap modifier keys that may be pressed.
2549 * @param start Position to snap.
2550 * @param event Event to get current key modifier information from, or 0.
2553 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2555 if (!_session || !event) {
2559 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2560 if (_snap_mode == SnapOff) {
2561 snap_to_internal (start, direction, for_mark);
2564 if (_snap_mode != SnapOff) {
2565 snap_to_internal (start, direction, for_mark);
2571 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2573 if (!_session || _snap_mode == SnapOff) {
2577 snap_to_internal (start, direction, for_mark);
2581 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2583 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2584 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2586 switch (_snap_type) {
2587 case SnapToTimecodeFrame:
2588 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2589 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2591 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2595 case SnapToTimecodeSeconds:
2596 if (_session->config.get_timecode_offset_negative()) {
2597 start += _session->config.get_timecode_offset ();
2599 start -= _session->config.get_timecode_offset ();
2601 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2602 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2604 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2607 if (_session->config.get_timecode_offset_negative()) {
2608 start -= _session->config.get_timecode_offset ();
2610 start += _session->config.get_timecode_offset ();
2614 case SnapToTimecodeMinutes:
2615 if (_session->config.get_timecode_offset_negative()) {
2616 start += _session->config.get_timecode_offset ();
2618 start -= _session->config.get_timecode_offset ();
2620 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2621 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2623 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2625 if (_session->config.get_timecode_offset_negative()) {
2626 start -= _session->config.get_timecode_offset ();
2628 start += _session->config.get_timecode_offset ();
2632 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2638 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2640 const framepos_t one_second = _session->frame_rate();
2641 const framepos_t one_minute = _session->frame_rate() * 60;
2642 framepos_t presnap = start;
2646 switch (_snap_type) {
2647 case SnapToTimecodeFrame:
2648 case SnapToTimecodeSeconds:
2649 case SnapToTimecodeMinutes:
2650 return timecode_snap_to_internal (start, direction, for_mark);
2653 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2654 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2656 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2661 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2662 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2664 start = (framepos_t) floor ((double) start / one_second) * one_second;
2669 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2670 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2672 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2677 start = _session->tempo_map().round_to_bar (start, direction);
2681 start = _session->tempo_map().round_to_beat (start, direction);
2684 case SnapToBeatDiv128:
2685 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2687 case SnapToBeatDiv64:
2688 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2690 case SnapToBeatDiv32:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2693 case SnapToBeatDiv28:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2696 case SnapToBeatDiv24:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2699 case SnapToBeatDiv20:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2702 case SnapToBeatDiv16:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2705 case SnapToBeatDiv14:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2708 case SnapToBeatDiv12:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2711 case SnapToBeatDiv10:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2714 case SnapToBeatDiv8:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2717 case SnapToBeatDiv7:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2720 case SnapToBeatDiv6:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2723 case SnapToBeatDiv5:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2726 case SnapToBeatDiv4:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2729 case SnapToBeatDiv3:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2732 case SnapToBeatDiv2:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2741 _session->locations()->marks_either_side (start, before, after);
2743 if (before == max_framepos) {
2745 } else if (after == max_framepos) {
2747 } else if (before != max_framepos && after != max_framepos) {
2748 /* have before and after */
2749 if ((start - before) < (after - start)) {
2758 case SnapToRegionStart:
2759 case SnapToRegionEnd:
2760 case SnapToRegionSync:
2761 case SnapToRegionBoundary:
2762 if (!region_boundary_cache.empty()) {
2764 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2765 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2767 if (direction > 0) {
2768 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2770 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2773 if (next != region_boundary_cache.begin ()) {
2778 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2779 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2781 if (start > (p + n) / 2) {
2790 switch (_snap_mode) {
2796 if (presnap > start) {
2797 if (presnap > (start + unit_to_frame(snap_threshold))) {
2801 } else if (presnap < start) {
2802 if (presnap < (start - unit_to_frame(snap_threshold))) {
2808 /* handled at entry */
2816 Editor::setup_toolbar ()
2818 HBox* mode_box = manage(new HBox);
2819 mode_box->set_border_width (2);
2820 mode_box->set_spacing(4);
2822 HBox* mouse_mode_box = manage (new HBox);
2823 HBox* mouse_mode_hbox1 = manage (new HBox);
2824 HBox* mouse_mode_hbox2 = manage (new HBox);
2825 VBox* mouse_mode_vbox1 = manage (new VBox);
2826 VBox* mouse_mode_vbox2 = manage (new VBox);
2827 Alignment* mouse_mode_align1 = manage (new Alignment);
2828 Alignment* mouse_mode_align2 = manage (new Alignment);
2830 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2831 mouse_mode_size_group->add_widget (mouse_move_button);
2832 mouse_mode_size_group->add_widget (mouse_select_button);
2833 mouse_mode_size_group->add_widget (mouse_zoom_button);
2834 mouse_mode_size_group->add_widget (mouse_gain_button);
2835 mouse_mode_size_group->add_widget (mouse_timefx_button);
2836 mouse_mode_size_group->add_widget (mouse_audition_button);
2837 mouse_mode_size_group->add_widget (mouse_draw_button);
2838 mouse_mode_size_group->add_widget (internal_edit_button);
2840 /* make them just a bit bigger */
2841 mouse_move_button.set_size_request (-1, 25);
2843 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2844 smart_mode_joiner->set_related_action (smart_mode_action);
2846 mouse_mode_hbox2->set_spacing (2);
2847 mouse_mode_box->set_spacing (2);
2849 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2850 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2851 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2852 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2853 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2854 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2855 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2857 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2858 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2860 mouse_mode_align1->add (*mouse_mode_vbox1);
2861 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2862 mouse_mode_align2->add (*mouse_mode_vbox2);
2863 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2865 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2866 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2868 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2869 if (!Profile->get_sae()) {
2870 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2872 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2874 edit_mode_selector.set_name ("EditModeSelector");
2875 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2876 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2878 mode_box->pack_start (edit_mode_selector, false, false);
2879 mode_box->pack_start (*mouse_mode_box, false, false);
2881 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2882 _mouse_mode_tearoff->set_name ("MouseModeBase");
2883 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2885 if (Profile->get_sae()) {
2886 _mouse_mode_tearoff->set_can_be_torn_off (false);
2889 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2890 &_mouse_mode_tearoff->tearoff_window()));
2891 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2892 &_mouse_mode_tearoff->tearoff_window(), 1));
2893 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2894 &_mouse_mode_tearoff->tearoff_window()));
2895 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2896 &_mouse_mode_tearoff->tearoff_window(), 1));
2900 _zoom_box.set_spacing (2);
2901 _zoom_box.set_border_width (2);
2905 zoom_in_button.set_name ("zoom button");
2906 zoom_in_button.set_image (::get_icon ("zoom_in"));
2907 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2908 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2909 zoom_in_button.set_related_action (act);
2911 zoom_out_button.set_name ("zoom button");
2912 zoom_out_button.set_image (::get_icon ("zoom_out"));
2913 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2914 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2915 zoom_out_button.set_related_action (act);
2917 zoom_out_full_button.set_name ("zoom button");
2918 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2919 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2920 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2921 zoom_out_full_button.set_related_action (act);
2923 zoom_focus_selector.set_name ("ZoomFocusSelector");
2924 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2925 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2927 _zoom_box.pack_start (zoom_out_button, false, false);
2928 _zoom_box.pack_start (zoom_in_button, false, false);
2929 _zoom_box.pack_start (zoom_out_full_button, false, false);
2931 _zoom_box.pack_start (zoom_focus_selector, false, false);
2933 /* Track zoom buttons */
2934 tav_expand_button.set_name ("TrackHeightButton");
2935 tav_expand_button.set_size_request (-1, 20);
2936 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2937 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2938 act->connect_proxy (tav_expand_button);
2940 tav_shrink_button.set_name ("TrackHeightButton");
2941 tav_shrink_button.set_size_request (-1, 20);
2942 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2943 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2944 act->connect_proxy (tav_shrink_button);
2946 _zoom_box.pack_start (tav_shrink_button);
2947 _zoom_box.pack_start (tav_expand_button);
2949 _zoom_tearoff = manage (new TearOff (_zoom_box));
2951 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2952 &_zoom_tearoff->tearoff_window()));
2953 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2954 &_zoom_tearoff->tearoff_window(), 0));
2955 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2956 &_zoom_tearoff->tearoff_window()));
2957 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2958 &_zoom_tearoff->tearoff_window(), 0));
2960 snap_box.set_spacing (1);
2961 snap_box.set_border_width (2);
2963 snap_type_selector.set_name ("SnapTypeSelector");
2964 set_popdown_strings (snap_type_selector, snap_type_strings);
2965 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2967 snap_mode_selector.set_name ("SnapModeSelector");
2968 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2969 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2971 edit_point_selector.set_name ("EditPointSelector");
2972 set_popdown_strings (edit_point_selector, edit_point_strings);
2973 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2975 snap_box.pack_start (snap_mode_selector, false, false);
2976 snap_box.pack_start (snap_type_selector, false, false);
2977 snap_box.pack_start (edit_point_selector, false, false);
2981 HBox *nudge_box = manage (new HBox);
2982 nudge_box->set_spacing (2);
2983 nudge_box->set_border_width (2);
2985 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2986 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2988 nudge_box->pack_start (nudge_backward_button, false, false);
2989 nudge_box->pack_start (nudge_forward_button, false, false);
2990 nudge_box->pack_start (*nudge_clock, false, false);
2993 /* Pack everything in... */
2995 HBox* hbox = manage (new HBox);
2996 hbox->set_spacing(10);
2998 _tools_tearoff = manage (new TearOff (*hbox));
2999 _tools_tearoff->set_name ("MouseModeBase");
3000 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3002 if (Profile->get_sae()) {
3003 _tools_tearoff->set_can_be_torn_off (false);
3006 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3007 &_tools_tearoff->tearoff_window()));
3008 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3009 &_tools_tearoff->tearoff_window(), 0));
3010 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3011 &_tools_tearoff->tearoff_window()));
3012 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3013 &_tools_tearoff->tearoff_window(), 0));
3015 toolbar_hbox.set_spacing (10);
3016 toolbar_hbox.set_border_width (1);
3018 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3019 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3020 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3022 hbox->pack_start (snap_box, false, false);
3023 if (!Profile->get_small_screen()) {
3024 hbox->pack_start (*nudge_box, false, false);
3026 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3028 hbox->pack_start (panic_box, false, false);
3032 toolbar_base.set_name ("ToolBarBase");
3033 toolbar_base.add (toolbar_hbox);
3035 _toolbar_viewport.add (toolbar_base);
3036 /* stick to the required height but allow width to vary if there's not enough room */
3037 _toolbar_viewport.set_size_request (1, -1);
3039 toolbar_frame.set_shadow_type (SHADOW_OUT);
3040 toolbar_frame.set_name ("BaseFrame");
3041 toolbar_frame.add (_toolbar_viewport);
3045 Editor::setup_tooltips ()
3047 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3048 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3049 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3050 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3051 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3052 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3053 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3054 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3055 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3056 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3057 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3058 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3059 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3060 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3061 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3062 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3063 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3064 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3065 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3066 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3067 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3068 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3069 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3073 Editor::convert_drop_to_paths (
3074 vector<string>& paths,
3075 const RefPtr<Gdk::DragContext>& /*context*/,
3078 const SelectionData& data,
3082 if (_session == 0) {
3086 vector<string> uris = data.get_uris();
3090 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3091 are actually URI lists. So do it by hand.
3094 if (data.get_target() != "text/plain") {
3098 /* Parse the "uri-list" format that Nautilus provides,
3099 where each pathname is delimited by \r\n.
3101 THERE MAY BE NO NULL TERMINATING CHAR!!!
3104 string txt = data.get_text();
3108 p = (const char *) malloc (txt.length() + 1);
3109 txt.copy ((char *) p, txt.length(), 0);
3110 ((char*)p)[txt.length()] = '\0';
3116 while (g_ascii_isspace (*p))
3120 while (*q && (*q != '\n') && (*q != '\r')) {
3127 while (q > p && g_ascii_isspace (*q))
3132 uris.push_back (string (p, q - p + 1));
3136 p = strchr (p, '\n');
3148 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3150 if ((*i).substr (0,7) == "file://") {
3152 string const p = PBD::url_decode (*i);
3154 // scan forward past three slashes
3156 string::size_type slashcnt = 0;
3157 string::size_type n = 0;
3158 string::const_iterator x = p.begin();
3160 while (slashcnt < 3 && x != p.end()) {
3163 } else if (slashcnt == 3) {
3170 if (slashcnt != 3 || x == p.end()) {
3171 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3175 paths.push_back (p.substr (n - 1));
3183 Editor::new_tempo_section ()
3189 Editor::map_transport_state ()
3191 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3193 if (_session && _session->transport_stopped()) {
3194 have_pending_keyboard_selection = false;
3197 update_loop_range_view (true);
3203 Editor::begin_reversible_command (string name)
3206 _session->begin_reversible_command (name);
3211 Editor::begin_reversible_command (GQuark q)
3214 _session->begin_reversible_command (q);
3219 Editor::commit_reversible_command ()
3222 _session->commit_reversible_command ();
3227 Editor::history_changed ()
3231 if (undo_action && _session) {
3232 if (_session->undo_depth() == 0) {
3233 label = S_("Command|Undo");
3235 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3237 undo_action->property_label() = label;
3240 if (redo_action && _session) {
3241 if (_session->redo_depth() == 0) {
3244 label = string_compose(_("Redo (%1)"), _session->next_redo());
3246 redo_action->property_label() = label;
3251 Editor::duplicate_dialog (bool with_dialog)
3255 if (mouse_mode == MouseRange) {
3256 if (selection->time.length() == 0) {
3261 RegionSelection rs = get_regions_from_selection_and_entered ();
3263 if (mouse_mode != MouseRange && rs.empty()) {
3269 ArdourDialog win (_("Duplicate"));
3270 Label label (_("Number of duplications:"));
3271 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3272 SpinButton spinner (adjustment, 0.0, 1);
3275 win.get_vbox()->set_spacing (12);
3276 win.get_vbox()->pack_start (hbox);
3277 hbox.set_border_width (6);
3278 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3280 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3281 place, visually. so do this by hand.
3284 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3285 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3286 spinner.grab_focus();
3292 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3293 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3294 win.set_default_response (RESPONSE_ACCEPT);
3296 win.set_position (WIN_POS_MOUSE);
3298 spinner.grab_focus ();
3300 switch (win.run ()) {
3301 case RESPONSE_ACCEPT:
3307 times = adjustment.get_value();
3310 if (mouse_mode == MouseRange) {
3311 duplicate_selection (times);
3313 duplicate_some_regions (rs, times);
3318 Editor::set_edit_mode (EditMode m)
3320 Config->set_edit_mode (m);
3324 Editor::cycle_edit_mode ()
3326 switch (Config->get_edit_mode()) {
3328 if (Profile->get_sae()) {
3329 Config->set_edit_mode (Lock);
3331 Config->set_edit_mode (Splice);
3335 Config->set_edit_mode (Lock);
3338 Config->set_edit_mode (Slide);
3344 Editor::edit_mode_selection_done ()
3346 string s = edit_mode_selector.get_active_text ();
3349 Config->set_edit_mode (string_to_edit_mode (s));
3354 Editor::snap_type_selection_done ()
3356 string choice = snap_type_selector.get_active_text();
3357 SnapType snaptype = SnapToBeat;
3359 if (choice == _("Beats/2")) {
3360 snaptype = SnapToBeatDiv2;
3361 } else if (choice == _("Beats/3")) {
3362 snaptype = SnapToBeatDiv3;
3363 } else if (choice == _("Beats/4")) {
3364 snaptype = SnapToBeatDiv4;
3365 } else if (choice == _("Beats/5")) {
3366 snaptype = SnapToBeatDiv5;
3367 } else if (choice == _("Beats/6")) {
3368 snaptype = SnapToBeatDiv6;
3369 } else if (choice == _("Beats/7")) {
3370 snaptype = SnapToBeatDiv7;
3371 } else if (choice == _("Beats/8")) {
3372 snaptype = SnapToBeatDiv8;
3373 } else if (choice == _("Beats/10")) {
3374 snaptype = SnapToBeatDiv10;
3375 } else if (choice == _("Beats/12")) {
3376 snaptype = SnapToBeatDiv12;
3377 } else if (choice == _("Beats/14")) {
3378 snaptype = SnapToBeatDiv14;
3379 } else if (choice == _("Beats/16")) {
3380 snaptype = SnapToBeatDiv16;
3381 } else if (choice == _("Beats/20")) {
3382 snaptype = SnapToBeatDiv20;
3383 } else if (choice == _("Beats/24")) {
3384 snaptype = SnapToBeatDiv24;
3385 } else if (choice == _("Beats/28")) {
3386 snaptype = SnapToBeatDiv28;
3387 } else if (choice == _("Beats/32")) {
3388 snaptype = SnapToBeatDiv32;
3389 } else if (choice == _("Beats/64")) {
3390 snaptype = SnapToBeatDiv64;
3391 } else if (choice == _("Beats/128")) {
3392 snaptype = SnapToBeatDiv128;
3393 } else if (choice == _("Beats")) {
3394 snaptype = SnapToBeat;
3395 } else if (choice == _("Bars")) {
3396 snaptype = SnapToBar;
3397 } else if (choice == _("Marks")) {
3398 snaptype = SnapToMark;
3399 } else if (choice == _("Region starts")) {
3400 snaptype = SnapToRegionStart;
3401 } else if (choice == _("Region ends")) {
3402 snaptype = SnapToRegionEnd;
3403 } else if (choice == _("Region bounds")) {
3404 snaptype = SnapToRegionBoundary;
3405 } else if (choice == _("Region syncs")) {
3406 snaptype = SnapToRegionSync;
3407 } else if (choice == _("CD Frames")) {
3408 snaptype = SnapToCDFrame;
3409 } else if (choice == _("Timecode Frames")) {
3410 snaptype = SnapToTimecodeFrame;
3411 } else if (choice == _("Timecode Seconds")) {
3412 snaptype = SnapToTimecodeSeconds;
3413 } else if (choice == _("Timecode Minutes")) {
3414 snaptype = SnapToTimecodeMinutes;
3415 } else if (choice == _("Seconds")) {
3416 snaptype = SnapToSeconds;
3417 } else if (choice == _("Minutes")) {
3418 snaptype = SnapToMinutes;
3421 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3423 ract->set_active ();
3428 Editor::snap_mode_selection_done ()
3430 string choice = snap_mode_selector.get_active_text();
3431 SnapMode mode = SnapNormal;
3433 if (choice == _("No Grid")) {
3435 } else if (choice == _("Grid")) {
3437 } else if (choice == _("Magnetic")) {
3438 mode = SnapMagnetic;
3441 RefPtr<RadioAction> ract = snap_mode_action (mode);
3444 ract->set_active (true);
3449 Editor::cycle_edit_point (bool with_marker)
3451 switch (_edit_point) {
3453 set_edit_point_preference (EditAtPlayhead);
3455 case EditAtPlayhead:
3457 set_edit_point_preference (EditAtSelectedMarker);
3459 set_edit_point_preference (EditAtMouse);
3462 case EditAtSelectedMarker:
3463 set_edit_point_preference (EditAtMouse);
3469 Editor::edit_point_selection_done ()
3471 string choice = edit_point_selector.get_active_text();
3472 EditPoint ep = EditAtSelectedMarker;
3474 if (choice == _("Marker")) {
3475 set_edit_point_preference (EditAtSelectedMarker);
3476 } else if (choice == _("Playhead")) {
3477 set_edit_point_preference (EditAtPlayhead);
3479 set_edit_point_preference (EditAtMouse);
3482 RefPtr<RadioAction> ract = edit_point_action (ep);
3485 ract->set_active (true);
3490 Editor::zoom_focus_selection_done ()
3492 string choice = zoom_focus_selector.get_active_text();
3493 ZoomFocus focus_type = ZoomFocusLeft;
3495 if (choice == _("Left")) {
3496 focus_type = ZoomFocusLeft;
3497 } else if (choice == _("Right")) {
3498 focus_type = ZoomFocusRight;
3499 } else if (choice == _("Center")) {
3500 focus_type = ZoomFocusCenter;
3501 } else if (choice == _("Playhead")) {
3502 focus_type = ZoomFocusPlayhead;
3503 } else if (choice == _("Mouse")) {
3504 focus_type = ZoomFocusMouse;
3505 } else if (choice == _("Edit point")) {
3506 focus_type = ZoomFocusEdit;
3509 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3512 ract->set_active ();
3517 Editor::edit_controls_button_release (GdkEventButton* ev)
3519 if (Keyboard::is_context_menu_event (ev)) {
3520 ARDOUR_UI::instance()->add_route (this);
3521 } else if (ev->button == 1) {
3522 selection->clear_tracks ();
3529 Editor::mouse_select_button_release (GdkEventButton* ev)
3531 /* this handles just right-clicks */
3533 if (ev->button != 3) {
3541 Editor::set_zoom_focus (ZoomFocus f)
3543 string str = zoom_focus_strings[(int)f];
3545 if (str != zoom_focus_selector.get_active_text()) {
3546 zoom_focus_selector.set_active_text (str);
3549 if (zoom_focus != f) {
3556 Editor::ensure_float (Window& win)
3558 win.set_transient_for (*this);
3562 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3564 /* recover or initialize pane positions. do this here rather than earlier because
3565 we don't want the positions to change the child allocations, which they seem to do.
3571 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3580 XMLNode* geometry = find_named_node (*node, "geometry");
3582 if (which == static_cast<Paned*> (&edit_pane)) {
3584 if (done & Horizontal) {
3588 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3589 _notebook_shrunk = string_is_affirmative (prop->value ());
3592 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3593 /* initial allocation is 90% to canvas, 10% to notebook */
3594 pos = (int) floor (alloc.get_width() * 0.90f);
3595 snprintf (buf, sizeof(buf), "%d", pos);
3597 pos = atoi (prop->value());
3600 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3601 edit_pane.set_position (pos);
3604 done = (Pane) (done | Horizontal);
3606 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3608 if (done & Vertical) {
3612 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3613 /* initial allocation is 90% to canvas, 10% to summary */
3614 pos = (int) floor (alloc.get_height() * 0.90f);
3615 snprintf (buf, sizeof(buf), "%d", pos);
3618 pos = atoi (prop->value());
3621 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3622 editor_summary_pane.set_position (pos);
3625 done = (Pane) (done | Vertical);
3630 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3632 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3633 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3634 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3635 top_hbox.remove (toolbar_frame);
3640 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3642 if (toolbar_frame.get_parent() == 0) {
3643 top_hbox.pack_end (toolbar_frame);
3648 Editor::set_show_measures (bool yn)
3650 if (_show_measures != yn) {
3653 if ((_show_measures = yn) == true) {
3655 tempo_lines->show();
3663 Editor::toggle_follow_playhead ()
3665 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3667 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3668 set_follow_playhead (tact->get_active());
3672 /** @param yn true to follow playhead, otherwise false.
3673 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3676 Editor::set_follow_playhead (bool yn, bool catch_up)
3678 if (_follow_playhead != yn) {
3679 if ((_follow_playhead = yn) == true && catch_up) {
3681 reset_x_origin_to_follow_playhead ();
3688 Editor::toggle_stationary_playhead ()
3690 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3692 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3693 set_stationary_playhead (tact->get_active());
3698 Editor::set_stationary_playhead (bool yn)
3700 if (_stationary_playhead != yn) {
3701 if ((_stationary_playhead = yn) == true) {
3703 // FIXME need a 3.0 equivalent of this 2.X call
3704 // update_current_screen ();
3711 Editor::playlist_selector () const
3713 return *_playlist_selector;
3717 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3721 switch (_snap_type) {
3726 case SnapToBeatDiv128:
3729 case SnapToBeatDiv64:
3732 case SnapToBeatDiv32:
3735 case SnapToBeatDiv28:
3738 case SnapToBeatDiv24:
3741 case SnapToBeatDiv20:
3744 case SnapToBeatDiv16:
3747 case SnapToBeatDiv14:
3750 case SnapToBeatDiv12:
3753 case SnapToBeatDiv10:
3756 case SnapToBeatDiv8:
3759 case SnapToBeatDiv7:
3762 case SnapToBeatDiv6:
3765 case SnapToBeatDiv5:
3768 case SnapToBeatDiv4:
3771 case SnapToBeatDiv3:
3774 case SnapToBeatDiv2:
3780 return _session->tempo_map().meter_at (position).divisions_per_bar();
3785 case SnapToTimecodeFrame:
3786 case SnapToTimecodeSeconds:
3787 case SnapToTimecodeMinutes:
3790 case SnapToRegionStart:
3791 case SnapToRegionEnd:
3792 case SnapToRegionSync:
3793 case SnapToRegionBoundary:
3803 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3807 ret = nudge_clock->current_duration (pos);
3808 next = ret + 1; /* XXXX fix me */
3814 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3816 ArdourDialog dialog (_("Playlist Deletion"));
3817 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3818 "If it is kept, its audio files will not be cleaned.\n"
3819 "If it is deleted, audio files used by it alone will be cleaned."),
3822 dialog.set_position (WIN_POS_CENTER);
3823 dialog.get_vbox()->pack_start (label);
3827 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3828 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3829 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3831 switch (dialog.run ()) {
3832 case RESPONSE_ACCEPT:
3833 /* delete the playlist */
3837 case RESPONSE_REJECT:
3838 /* keep the playlist */
3850 Editor::audio_region_selection_covers (framepos_t where)
3852 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3853 if ((*a)->region()->covers (where)) {
3862 Editor::prepare_for_cleanup ()
3864 cut_buffer->clear_regions ();
3865 cut_buffer->clear_playlists ();
3867 selection->clear_regions ();
3868 selection->clear_playlists ();
3870 _regions->suspend_redisplay ();
3874 Editor::finish_cleanup ()
3876 _regions->resume_redisplay ();
3880 Editor::transport_loop_location()
3883 return _session->locations()->auto_loop_location();
3890 Editor::transport_punch_location()
3893 return _session->locations()->auto_punch_location();
3900 Editor::control_layout_scroll (GdkEventScroll* ev)
3902 if (Keyboard::some_magic_widget_has_focus()) {
3906 switch (ev->direction) {
3908 scroll_tracks_up_line ();
3912 case GDK_SCROLL_DOWN:
3913 scroll_tracks_down_line ();
3917 /* no left/right handling yet */
3925 Editor::session_state_saved (string)
3928 _snapshots->redisplay ();
3932 Editor::maximise_editing_space ()
3940 if (!Config->get_keep_tearoffs()) {
3941 /* these calls will leave each tearoff visible *if* it is torn off,
3942 but invisible otherwise.
3944 _mouse_mode_tearoff->set_visible (false);
3945 _tools_tearoff->set_visible (false);
3946 _zoom_tearoff->set_visible (false);
3953 Editor::restore_editing_space ()
3961 if (!Config->get_keep_tearoffs()) {
3962 _mouse_mode_tearoff->set_visible (true);
3963 _tools_tearoff->set_visible (true);
3964 _zoom_tearoff->set_visible (true);
3971 * Make new playlists for a given track and also any others that belong
3972 * to the same active route group with the `edit' property.
3977 Editor::new_playlists (TimeAxisView* v)
3979 begin_reversible_command (_("new playlists"));
3980 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3981 _session->playlists->get (playlists);
3982 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3983 commit_reversible_command ();
3987 * Use a copy of the current playlist for a given track and also any others that belong
3988 * to the same active route group with the `edit' property.
3993 Editor::copy_playlists (TimeAxisView* v)
3995 begin_reversible_command (_("copy playlists"));
3996 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3997 _session->playlists->get (playlists);
3998 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3999 commit_reversible_command ();
4002 /** Clear the current playlist for a given track and also any others that belong
4003 * to the same active route group with the `edit' property.
4008 Editor::clear_playlists (TimeAxisView* v)
4010 begin_reversible_command (_("clear playlists"));
4011 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4012 _session->playlists->get (playlists);
4013 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4014 commit_reversible_command ();
4018 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4020 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4024 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4026 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4030 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4032 atv.clear_playlist ();
4036 Editor::on_key_press_event (GdkEventKey* ev)
4038 return key_press_focus_accelerator_handler (*this, ev);
4042 Editor::on_key_release_event (GdkEventKey* ev)
4044 return Gtk::Window::on_key_release_event (ev);
4045 // return key_press_focus_accelerator_handler (*this, ev);
4048 /** Queue up a change to the viewport x origin.
4049 * @param frame New x origin.
4052 Editor::reset_x_origin (framepos_t frame)
4054 queue_visual_change (frame);
4058 Editor::reset_y_origin (double y)
4060 queue_visual_change_y (y);
4064 Editor::reset_zoom (double fpu)
4066 queue_visual_change (fpu);
4070 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4072 reset_x_origin (frame);
4075 if (!no_save_visual) {
4076 undo_visual_stack.push_back (current_visual_state(false));
4080 Editor::VisualState::VisualState (bool with_tracks)
4081 : gui_state (with_tracks ? new GUIObjectState : 0)
4085 Editor::VisualState::~VisualState ()
4090 Editor::VisualState*
4091 Editor::current_visual_state (bool with_tracks)
4093 VisualState* vs = new VisualState (with_tracks);
4094 vs->y_position = vertical_adjustment.get_value();
4095 vs->frames_per_unit = frames_per_unit;
4096 vs->leftmost_frame = leftmost_frame;
4097 vs->zoom_focus = zoom_focus;
4100 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4107 Editor::undo_visual_state ()
4109 if (undo_visual_stack.empty()) {
4113 VisualState* vs = undo_visual_stack.back();
4114 undo_visual_stack.pop_back();
4117 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4119 use_visual_state (*vs);
4123 Editor::redo_visual_state ()
4125 if (redo_visual_stack.empty()) {
4129 VisualState* vs = redo_visual_stack.back();
4130 redo_visual_stack.pop_back();
4132 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4134 use_visual_state (*vs);
4138 Editor::swap_visual_state ()
4140 if (undo_visual_stack.empty()) {
4141 redo_visual_state ();
4143 undo_visual_state ();
4148 Editor::use_visual_state (VisualState& vs)
4150 PBD::Unwinder<bool> nsv (no_save_visual, true);
4152 _routes->suspend_redisplay ();
4154 vertical_adjustment.set_value (vs.y_position);
4156 set_zoom_focus (vs.zoom_focus);
4157 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4160 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4162 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4163 (*i)->reset_visual_state ();
4167 _routes->update_visibility ();
4168 _routes->resume_redisplay ();
4172 Editor::set_frames_per_unit (double fpu)
4174 /* this is the core function that controls the zoom level of the canvas. it is called
4175 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4178 if (fpu == frames_per_unit) {
4187 /* don't allow zooms that fit more than the maximum number
4188 of frames into an 800 pixel wide space.
4191 if (max_framepos / fpu < 800.0) {
4196 tempo_lines->tempo_map_changed();
4198 frames_per_unit = fpu;
4203 Editor::post_zoom ()
4205 // convert fpu to frame count
4207 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4209 if (frames_per_unit != zoom_range_clock->current_duration()) {
4210 zoom_range_clock->set (frames);
4213 bool const showing_time_selection =
4214 mouse_mode == MouseRange ||
4215 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4217 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4218 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4219 (*i)->reshow_selection (selection->time);
4223 ZoomChanged (); /* EMIT_SIGNAL */
4225 //reset_scrolling_region ();
4227 if (playhead_cursor) {
4228 playhead_cursor->set_position (playhead_cursor->current_frame);
4231 refresh_location_display();
4232 _summary->set_overlays_dirty ();
4234 update_marker_labels ();
4240 Editor::queue_visual_change (framepos_t where)
4242 pending_visual_change.add (VisualChange::TimeOrigin);
4243 pending_visual_change.time_origin = where;
4244 ensure_visual_change_idle_handler ();
4248 Editor::queue_visual_change (double fpu)
4250 pending_visual_change.add (VisualChange::ZoomLevel);
4251 pending_visual_change.frames_per_unit = fpu;
4253 ensure_visual_change_idle_handler ();
4257 Editor::queue_visual_change_y (double y)
4259 pending_visual_change.add (VisualChange::YOrigin);
4260 pending_visual_change.y_origin = y;
4262 ensure_visual_change_idle_handler ();
4266 Editor::ensure_visual_change_idle_handler ()
4268 if (pending_visual_change.idle_handler_id < 0) {
4269 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4274 Editor::_idle_visual_changer (void* arg)
4276 return static_cast<Editor*>(arg)->idle_visual_changer ();
4280 Editor::idle_visual_changer ()
4282 VisualChange::Type p = pending_visual_change.pending;
4283 pending_visual_change.pending = (VisualChange::Type) 0;
4285 double const last_time_origin = horizontal_position ();
4287 if (p & VisualChange::ZoomLevel) {
4288 set_frames_per_unit (pending_visual_change.frames_per_unit);
4290 compute_fixed_ruler_scale ();
4291 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4292 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4293 update_tempo_based_rulers ();
4295 if (p & VisualChange::TimeOrigin) {
4296 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4298 if (p & VisualChange::YOrigin) {
4299 vertical_adjustment.set_value (pending_visual_change.y_origin);
4302 if (last_time_origin == horizontal_position ()) {
4303 /* changed signal not emitted */
4304 update_fixed_rulers ();
4305 redisplay_tempo (true);
4308 _summary->set_overlays_dirty ();
4310 pending_visual_change.idle_handler_id = -1;
4311 return 0; /* this is always a one-shot call */
4314 struct EditorOrderTimeAxisSorter {
4315 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4316 return a->order () < b->order ();
4321 Editor::sort_track_selection (TrackViewList& sel)
4323 EditorOrderTimeAxisSorter cmp;
4328 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4331 framepos_t where = 0;
4332 EditPoint ep = _edit_point;
4334 if (from_context_menu && (ep == EditAtMouse)) {
4335 return event_frame (&context_click_event, 0, 0);
4338 if (entered_marker) {
4339 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4340 return entered_marker->position();
4343 if (ignore_playhead && ep == EditAtPlayhead) {
4344 ep = EditAtSelectedMarker;
4348 case EditAtPlayhead:
4349 where = _session->audible_frame();
4350 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4353 case EditAtSelectedMarker:
4354 if (!selection->markers.empty()) {
4356 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4359 where = loc->start();
4363 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4371 if (!mouse_frame (where, ignored)) {
4372 /* XXX not right but what can we do ? */
4376 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4384 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4386 if (!_session) return;
4388 begin_reversible_command (cmd);
4392 if ((tll = transport_loop_location()) == 0) {
4393 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
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));
4400 XMLNode &before = tll->get_state();
4401 tll->set_hidden (false, this);
4402 tll->set (start, end);
4403 XMLNode &after = tll->get_state();
4404 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4407 commit_reversible_command ();
4411 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4413 if (!_session) return;
4415 begin_reversible_command (cmd);
4419 if ((tpl = transport_punch_location()) == 0) {
4420 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4421 XMLNode &before = _session->locations()->get_state();
4422 _session->locations()->add (loc, true);
4423 _session->set_auto_loop_location (loc);
4424 XMLNode &after = _session->locations()->get_state();
4425 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4428 XMLNode &before = tpl->get_state();
4429 tpl->set_hidden (false, this);
4430 tpl->set (start, end);
4431 XMLNode &after = tpl->get_state();
4432 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4435 commit_reversible_command ();
4438 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4439 * @param rs List to which found regions are added.
4440 * @param where Time to look at.
4441 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4444 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4446 const TrackViewList* tracks;
4449 tracks = &track_views;
4454 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4456 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4459 boost::shared_ptr<Track> tr;
4460 boost::shared_ptr<Playlist> pl;
4462 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4464 boost::shared_ptr<RegionList> regions = pl->regions_at (
4465 (framepos_t) floor ( (double) where * tr->speed()));
4467 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4468 RegionView* rv = rtv->view()->find_view (*i);
4479 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4481 const TrackViewList* tracks;
4484 tracks = &track_views;
4489 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4490 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4492 boost::shared_ptr<Track> tr;
4493 boost::shared_ptr<Playlist> pl;
4495 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4497 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4498 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4500 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4502 RegionView* rv = rtv->view()->find_view (*i);
4513 /** Start with regions that are selected. Then add equivalent regions
4514 * on tracks in the same active edit-enabled route group as any of
4515 * the regions that we started with.
4519 Editor::get_regions_from_selection ()
4521 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4524 /** Get regions using the following method:
4526 * Make an initial region list using the selected regions, unless
4527 * the edit point is `mouse' and the mouse is over an unselected
4528 * region. In this case, start with just that region.
4530 * Then, add equivalent regions in active edit groups to the region list.
4532 * Then, search the list of selected tracks to find any selected tracks which
4533 * do not contain regions already in the region list. If there are no selected
4534 * tracks and 'No Selection = All Tracks' is active, search all tracks rather
4535 * than just the selected.
4537 * Add any regions that are under the edit point on these tracks to get the
4538 * returned region list.
4540 * The rationale here is that the mouse edit point is special in that
4541 * its position describes both a time and a track; the other edit
4542 * modes only describe a time. Hence if the edit point is `mouse' we
4543 * ignore selected tracks, as we assume the user means something by
4544 * pointing at a particular track. Also in this case we take note of
4545 * the region directly under the edit point, as there is always just one
4546 * (rather than possibly several with non-mouse edit points).
4550 Editor::get_regions_from_selection_and_edit_point ()
4552 RegionSelection regions;
4554 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4555 regions.add (entered_regionview);
4557 regions = selection->regions;
4560 TrackViewList tracks;
4562 if (_edit_point != EditAtMouse) {
4563 tracks = selection->tracks;
4566 /* Add any other regions that are in the same
4567 edit-activated route group as one of our regions.
4569 regions = get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4570 framepos_t const where = get_preferred_edit_position ();
4572 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4573 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4574 * is enabled, so consider all tracks
4576 tracks = track_views;
4579 if (!tracks.empty()) {
4580 /* now search the selected tracks for tracks which don't
4581 already contain regions to be acted upon, and get regions at
4582 the edit point on those tracks too.
4584 TrackViewList tracks_without_relevant_regions;
4586 for (TrackViewList::iterator t = tracks.begin (); t != tracks.end (); ++t) {
4587 if (!regions.involves (**t)) {
4588 /* there are no equivalent regions on this track */
4589 tracks_without_relevant_regions.push_back (*t);
4593 if (!tracks_without_relevant_regions.empty()) {
4594 /* there are some selected tracks with neither selected
4595 * regions or their equivalents: act upon all regions in
4598 get_regions_at (regions, where, tracks_without_relevant_regions);
4605 /** Start with regions that are selected, or the entered regionview if none are selected.
4606 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4607 * of the regions that we started with.
4611 Editor::get_regions_from_selection_and_entered ()
4613 RegionSelection regions = selection->regions;
4615 if (regions.empty() && entered_regionview) {
4616 regions.add (entered_regionview);
4619 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4623 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4625 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4627 RouteTimeAxisView* tatv;
4629 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4631 boost::shared_ptr<Playlist> pl;
4632 vector<boost::shared_ptr<Region> > results;
4634 boost::shared_ptr<Track> tr;
4636 if ((tr = tatv->track()) == 0) {
4641 if ((pl = (tr->playlist())) != 0) {
4642 pl->get_region_list_equivalent_regions (region, results);
4645 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4646 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4647 regions.push_back (marv);
4656 Editor::show_rhythm_ferret ()
4658 if (rhythm_ferret == 0) {
4659 rhythm_ferret = new RhythmFerret(*this);
4662 rhythm_ferret->set_session (_session);
4663 rhythm_ferret->show ();
4664 rhythm_ferret->present ();
4668 Editor::first_idle ()
4670 MessageDialog* dialog = 0;
4672 if (track_views.size() > 1) {
4673 dialog = new MessageDialog (
4675 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4679 ARDOUR_UI::instance()->flush_pending ();
4682 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4686 // first idle adds route children (automation tracks), so we need to redisplay here
4687 _routes->redisplay ();
4694 Editor::_idle_resize (gpointer arg)
4696 return ((Editor*)arg)->idle_resize ();
4700 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4702 if (resize_idle_id < 0) {
4703 resize_idle_id = g_idle_add (_idle_resize, this);
4704 _pending_resize_amount = 0;
4707 /* make a note of the smallest resulting height, so that we can clamp the
4708 lower limit at TimeAxisView::hSmall */
4710 int32_t min_resulting = INT32_MAX;
4712 _pending_resize_amount += h;
4713 _pending_resize_view = view;
4715 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4717 if (selection->tracks.contains (_pending_resize_view)) {
4718 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4719 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4723 if (min_resulting < 0) {
4728 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4729 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4733 /** Handle pending resizing of tracks */
4735 Editor::idle_resize ()
4737 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4739 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4740 selection->tracks.contains (_pending_resize_view)) {
4742 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4743 if (*i != _pending_resize_view) {
4744 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4749 _pending_resize_amount = 0;
4751 _group_tabs->set_dirty ();
4752 resize_idle_id = -1;
4760 ENSURE_GUI_THREAD (*this, &Editor::located);
4762 playhead_cursor->set_position (_session->audible_frame ());
4763 if (_follow_playhead && !_pending_initial_locate) {
4764 reset_x_origin_to_follow_playhead ();
4767 _pending_locate_request = false;
4768 _pending_initial_locate = false;
4772 Editor::region_view_added (RegionView *)
4774 _summary->set_dirty ();
4778 Editor::region_view_removed ()
4780 _summary->set_dirty ();
4784 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4786 TrackViewList::const_iterator j = track_views.begin ();
4787 while (j != track_views.end()) {
4788 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4789 if (rtv && rtv->route() == r) {
4800 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4804 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4805 TimeAxisView* tv = axis_view_from_route (*i);
4816 Editor::handle_new_route (RouteList& routes)
4818 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4820 RouteTimeAxisView *rtv;
4821 list<RouteTimeAxisView*> new_views;
4823 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4824 boost::shared_ptr<Route> route = (*x);
4826 if (route->is_hidden() || route->is_monitor()) {
4830 DataType dt = route->input()->default_type();
4832 if (dt == ARDOUR::DataType::AUDIO) {
4833 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4834 rtv->set_route (route);
4835 } else if (dt == ARDOUR::DataType::MIDI) {
4836 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4837 rtv->set_route (route);
4839 throw unknown_type();
4842 new_views.push_back (rtv);
4843 track_views.push_back (rtv);
4845 rtv->effective_gain_display ();
4847 if (internal_editing()) {
4848 rtv->enter_internal_edit_mode ();
4850 rtv->leave_internal_edit_mode ();
4853 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4854 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4857 _routes->routes_added (new_views);
4858 _summary->routes_added (new_views);
4860 if (show_editor_mixer_when_tracks_arrive) {
4861 show_editor_mixer (true);
4864 editor_list_button.set_sensitive (true);
4868 Editor::timeaxisview_deleted (TimeAxisView *tv)
4870 if (_session && _session->deletion_in_progress()) {
4871 /* the situation is under control */
4875 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4877 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4879 _routes->route_removed (tv);
4881 if (tv == entered_track) {
4885 TimeAxisView::Children c = tv->get_child_list ();
4886 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4887 if (entered_track == i->get()) {
4892 /* remove it from the list of track views */
4894 TrackViewList::iterator i;
4896 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4897 i = track_views.erase (i);
4900 /* update whatever the current mixer strip is displaying, if revelant */
4902 boost::shared_ptr<Route> route;
4905 route = rtav->route ();
4908 if (current_mixer_strip && current_mixer_strip->route() == route) {
4910 TimeAxisView* next_tv;
4912 if (track_views.empty()) {
4914 } else if (i == track_views.end()) {
4915 next_tv = track_views.front();
4922 set_selected_mixer_strip (*next_tv);
4924 /* make the editor mixer strip go away setting the
4925 * button to inactive (which also unticks the menu option)
4928 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4934 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4936 if (apply_to_selection) {
4937 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4939 TrackSelection::iterator j = i;
4942 hide_track_in_display (*i, false);
4947 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4949 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4950 // this will hide the mixer strip
4951 set_selected_mixer_strip (*tv);
4954 _routes->hide_track_in_display (*tv);
4959 Editor::sync_track_view_list_and_routes ()
4961 track_views = TrackViewList (_routes->views ());
4963 _summary->set_dirty ();
4964 _group_tabs->set_dirty ();
4966 return false; // do not call again (until needed)
4970 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4972 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4977 /** Find a RouteTimeAxisView by the ID of its route */
4979 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4981 RouteTimeAxisView* v;
4983 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4984 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4985 if(v->route()->id() == id) {
4995 Editor::fit_route_group (RouteGroup *g)
4997 TrackViewList ts = axis_views_from_routes (g->route_list ());
5002 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5004 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5007 _session->cancel_audition ();
5011 if (_session->is_auditioning()) {
5012 _session->cancel_audition ();
5013 if (r == last_audition_region) {
5018 _session->audition_region (r);
5019 last_audition_region = r;
5024 Editor::hide_a_region (boost::shared_ptr<Region> r)
5026 r->set_hidden (true);
5030 Editor::show_a_region (boost::shared_ptr<Region> r)
5032 r->set_hidden (false);
5036 Editor::audition_region_from_region_list ()
5038 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5042 Editor::hide_region_from_region_list ()
5044 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5048 Editor::show_region_in_region_list ()
5050 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5054 Editor::step_edit_status_change (bool yn)
5057 start_step_editing ();
5059 stop_step_editing ();
5064 Editor::start_step_editing ()
5066 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5070 Editor::stop_step_editing ()
5072 step_edit_connection.disconnect ();
5076 Editor::check_step_edit ()
5078 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5079 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5081 mtv->check_step_edit ();
5085 return true; // do it again, till we stop
5089 Editor::scroll_press (Direction dir)
5091 ++_scroll_callbacks;
5093 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5094 /* delay the first auto-repeat */
5100 scroll_backward (1);
5108 scroll_tracks_up_line ();
5112 scroll_tracks_down_line ();
5116 /* do hacky auto-repeat */
5117 if (!_scroll_connection.connected ()) {
5119 _scroll_connection = Glib::signal_timeout().connect (
5120 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5123 _scroll_callbacks = 0;
5130 Editor::scroll_release ()
5132 _scroll_connection.disconnect ();
5135 /** Queue a change for the Editor viewport x origin to follow the playhead */
5137 Editor::reset_x_origin_to_follow_playhead ()
5139 framepos_t const frame = playhead_cursor->current_frame;
5141 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5143 if (_session->transport_speed() < 0) {
5145 if (frame > (current_page_frames() / 2)) {
5146 center_screen (frame-(current_page_frames()/2));
5148 center_screen (current_page_frames()/2);
5155 if (frame < leftmost_frame) {
5157 if (_session->transport_rolling()) {
5158 /* rolling; end up with the playhead at the right of the page */
5159 l = frame - current_page_frames ();
5161 /* not rolling: end up with the playhead 1/4 of the way along the page */
5162 l = frame - current_page_frames() / 4;
5166 if (_session->transport_rolling()) {
5167 /* rolling: end up with the playhead on the left of the page */
5170 /* not rolling: end up with the playhead 3/4 of the way along the page */
5171 l = frame - 3 * current_page_frames() / 4;
5179 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5185 Editor::super_rapid_screen_update ()
5187 if (!_session || !_session->engine().running()) {
5191 /* METERING / MIXER STRIPS */
5193 /* update track meters, if required */
5194 if (is_mapped() && meters_running) {
5195 RouteTimeAxisView* rtv;
5196 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5197 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5198 rtv->fast_update ();
5203 /* and any current mixer strip */
5204 if (current_mixer_strip) {
5205 current_mixer_strip->fast_update ();
5208 /* PLAYHEAD AND VIEWPORT */
5210 framepos_t const frame = _session->audible_frame();
5212 /* There are a few reasons why we might not update the playhead / viewport stuff:
5214 * 1. we don't update things when there's a pending locate request, otherwise
5215 * when the editor requests a locate there is a chance that this method
5216 * will move the playhead before the locate request is processed, causing
5218 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5219 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5222 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5224 last_update_frame = frame;
5226 if (!_dragging_playhead) {
5227 playhead_cursor->set_position (frame);
5230 if (!_stationary_playhead) {
5232 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5233 reset_x_origin_to_follow_playhead ();
5238 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5242 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5243 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5244 if (target <= 0.0) {
5247 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5248 target = (target * 0.15) + (current * 0.85);
5254 set_horizontal_position (current);
5263 Editor::session_going_away ()
5265 _have_idled = false;
5267 _session_connections.drop_connections ();
5269 super_rapid_screen_update_connection.disconnect ();
5271 selection->clear ();
5272 cut_buffer->clear ();
5274 clicked_regionview = 0;
5275 clicked_axisview = 0;
5276 clicked_routeview = 0;
5277 entered_regionview = 0;
5279 last_update_frame = 0;
5282 playhead_cursor->canvas_item.hide ();
5284 /* rip everything out of the list displays */
5288 _route_groups->clear ();
5290 /* do this first so that deleting a track doesn't reset cms to null
5291 and thus cause a leak.
5294 if (current_mixer_strip) {
5295 if (current_mixer_strip->get_parent() != 0) {
5296 global_hpacker.remove (*current_mixer_strip);
5298 delete current_mixer_strip;
5299 current_mixer_strip = 0;
5302 /* delete all trackviews */
5304 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5307 track_views.clear ();
5309 zoom_range_clock->set_session (0);
5310 nudge_clock->set_session (0);
5312 editor_list_button.set_active(false);
5313 editor_list_button.set_sensitive(false);
5315 /* clear tempo/meter rulers */
5316 remove_metric_marks ();
5318 clear_marker_display ();
5320 current_bbt_points_begin = current_bbt_points_end;
5322 /* get rid of any existing editor mixer strip */
5324 WindowTitle title(Glib::get_application_name());
5325 title += _("Editor");
5327 set_title (title.get_string());
5329 SessionHandlePtr::session_going_away ();
5334 Editor::show_editor_list (bool yn)
5337 _the_notebook.show ();
5339 _the_notebook.hide ();
5344 Editor::change_region_layering_order (bool from_context_menu)
5346 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5348 if (!clicked_routeview) {
5349 if (layering_order_editor) {
5350 layering_order_editor->hide ();
5355 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5361 boost::shared_ptr<Playlist> pl = track->playlist();
5367 if (layering_order_editor == 0) {
5368 layering_order_editor = new RegionLayeringOrderEditor (*this);
5369 layering_order_editor->set_position (WIN_POS_MOUSE);
5372 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5373 layering_order_editor->maybe_present ();
5377 Editor::update_region_layering_order_editor ()
5379 if (layering_order_editor && layering_order_editor->is_visible ()) {
5380 change_region_layering_order (true);
5385 Editor::setup_fade_images ()
5387 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5388 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5389 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5390 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5391 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5393 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5394 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5395 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5396 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5397 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5399 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5400 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5401 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5402 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5403 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5405 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5406 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5407 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5408 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5409 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5413 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5415 Editor::action_menu_item (std::string const & name)
5417 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5420 return *manage (a->create_menu_item ());
5424 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5426 EventBox* b = manage (new EventBox);
5427 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5428 Label* l = manage (new Label (name));
5432 _the_notebook.append_page (widget, *b);
5436 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5438 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5439 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5442 if (ev->type == GDK_2BUTTON_PRESS) {
5444 /* double-click on a notebook tab shrinks or expands the notebook */
5446 if (_notebook_shrunk) {
5447 if (pre_notebook_shrink_pane_width) {
5448 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5450 _notebook_shrunk = false;
5452 pre_notebook_shrink_pane_width = edit_pane.get_position();
5454 /* this expands the LHS of the edit pane to cover the notebook
5455 PAGE but leaves the tabs visible.
5457 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5458 _notebook_shrunk = true;
5466 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5468 using namespace Menu_Helpers;
5470 MenuList& items = _control_point_context_menu.items ();
5473 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5474 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5475 if (!can_remove_control_point (item)) {
5476 items.back().set_sensitive (false);
5479 _control_point_context_menu.popup (event->button.button, event->button.time);