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/audioplaylist.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/midi_region.h"
67 #include "ardour/plugin_manager.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_directory.h"
71 #include "ardour/session_route.h"
72 #include "ardour/session_state_utils.h"
73 #include "ardour/tempo.h"
74 #include "ardour/utils.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/audioengine.h"
78 #include "control_protocol/control_protocol.h"
82 #include "analysis_window.h"
83 #include "audio_clock.h"
84 #include "audio_region_view.h"
85 #include "audio_streamview.h"
86 #include "audio_time_axis.h"
87 #include "automation_time_axis.h"
88 #include "bundle_manager.h"
89 #include "button_joiner.h"
90 #include "canvas-noevent-text.h"
91 #include "canvas_impl.h"
92 #include "crossfade_edit.h"
96 #include "editor_cursors.h"
97 #include "editor_drag.h"
98 #include "editor_group_tabs.h"
99 #include "editor_locations.h"
100 #include "editor_regions.h"
101 #include "editor_route_groups.h"
102 #include "editor_routes.h"
103 #include "editor_snapshots.h"
104 #include "editor_summary.h"
105 #include "global_port_matrix.h"
106 #include "gui_object.h"
107 #include "gui_thread.h"
108 #include "keyboard.h"
110 #include "midi_time_axis.h"
111 #include "mixer_strip.h"
112 #include "mixer_ui.h"
113 #include "mouse_cursors.h"
114 #include "playlist_selector.h"
115 #include "public_editor.h"
116 #include "region_layering_order_editor.h"
117 #include "rgb_macros.h"
118 #include "rhythm_ferret.h"
119 #include "selection.h"
121 #include "simpleline.h"
122 #include "tempo_lines.h"
123 #include "time_axis_view.h"
129 #include "imageframe_socket_handler.h"
133 using namespace ARDOUR;
136 using namespace Glib;
137 using namespace Gtkmm2ext;
138 using namespace Editing;
140 using PBD::internationalize;
142 using Gtkmm2ext::Keyboard;
144 const double Editor::timebar_height = 15.0;
146 static const gchar *_snap_type_strings[] = {
148 N_("Timecode Frames"),
149 N_("Timecode Seconds"),
150 N_("Timecode Minutes"),
180 static const gchar *_snap_mode_strings[] = {
187 static const gchar *_edit_point_strings[] = {
194 static const gchar *_zoom_focus_strings[] = {
204 #ifdef USE_RUBBERBAND
205 static const gchar *_rb_opt_strings[] = {
208 N_("Balanced multitimbral mixture"),
209 N_("Unpitched percussion with stable notes"),
210 N_("Crisp monophonic instrumental"),
211 N_("Unpitched solo percussion"),
212 N_("Resample without preserving pitch"),
218 show_me_the_size (Requisition* r, const char* what)
220 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
225 pane_size_watcher (Paned* pane)
227 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
228 it is no longer accessible. so stop that. this doesn't happen on X11,
229 just the quartz backend.
234 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
236 gint pos = pane->get_position ();
238 if (pos > max_width_of_lhs) {
239 pane->set_position (max_width_of_lhs);
245 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
247 /* time display buttons */
248 , minsec_label (_("Mins:Secs"))
249 , bbt_label (_("Bars:Beats"))
250 , timecode_label (_("Timecode"))
251 , samples_label (_("Samples"))
252 , tempo_label (_("Tempo"))
253 , meter_label (_("Meter"))
254 , mark_label (_("Location Markers"))
255 , range_mark_label (_("Range Markers"))
256 , transport_mark_label (_("Loop/Punch Ranges"))
257 , cd_mark_label (_("CD Markers"))
258 , edit_packer (4, 4, true)
260 /* the values here don't matter: layout widgets
261 reset them as needed.
264 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
266 /* tool bar related */
268 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
270 , toolbar_selection_clock_table (2,3)
272 , automation_mode_button (_("mode"))
274 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
277 , image_socket_listener(0)
282 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
283 , meters_running(false)
284 , _pending_locate_request (false)
285 , _pending_initial_locate (false)
286 , _last_cut_copy_source_track (0)
288 , _region_selection_change_updates_region_list (true)
289 , _following_mixer_selection (false)
293 /* we are a singleton */
295 PublicEditor::_instance = this;
299 selection = new Selection (this);
300 cut_buffer = new Selection (this);
302 clicked_regionview = 0;
303 clicked_axisview = 0;
304 clicked_routeview = 0;
305 clicked_control_point = 0;
306 last_update_frame = 0;
307 pre_press_cursor = 0;
308 _drags = new DragManager (this);
309 current_mixer_strip = 0;
312 snap_type_strings = I18N (_snap_type_strings);
313 snap_mode_strings = I18N (_snap_mode_strings);
314 zoom_focus_strings = I18N (_zoom_focus_strings);
315 edit_point_strings = I18N (_edit_point_strings);
316 #ifdef USE_RUBBERBAND
317 rb_opt_strings = I18N (_rb_opt_strings);
321 snap_threshold = 5.0;
322 bbt_beat_subdivision = 4;
325 last_autoscroll_x = 0;
326 last_autoscroll_y = 0;
327 autoscroll_active = false;
328 autoscroll_timeout_tag = -1;
333 current_interthread_info = 0;
334 _show_measures = true;
336 show_gain_after_trim = false;
338 have_pending_keyboard_selection = false;
339 _follow_playhead = true;
340 _stationary_playhead = false;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
368 no_save_visual = false;
370 within_track_canvas = false;
372 scrubbing_direction = 0;
376 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
377 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
378 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
379 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
380 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
382 _edit_point = EditAtMouse;
383 _internal_editing = false;
384 current_canvas_cursor = 0;
386 frames_per_unit = 2048; /* too early to use reset_zoom () */
388 _scroll_callbacks = 0;
390 zoom_focus = ZoomFocusLeft;
391 set_zoom_focus (ZoomFocusLeft);
392 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
394 bbt_label.set_name ("EditorTimeButton");
395 bbt_label.set_size_request (-1, (int)timebar_height);
396 bbt_label.set_alignment (1.0, 0.5);
397 bbt_label.set_padding (5,0);
399 bbt_label.set_no_show_all();
400 minsec_label.set_name ("EditorTimeButton");
401 minsec_label.set_size_request (-1, (int)timebar_height);
402 minsec_label.set_alignment (1.0, 0.5);
403 minsec_label.set_padding (5,0);
404 minsec_label.hide ();
405 minsec_label.set_no_show_all();
406 timecode_label.set_name ("EditorTimeButton");
407 timecode_label.set_size_request (-1, (int)timebar_height);
408 timecode_label.set_alignment (1.0, 0.5);
409 timecode_label.set_padding (5,0);
410 timecode_label.hide ();
411 timecode_label.set_no_show_all();
412 samples_label.set_name ("EditorTimeButton");
413 samples_label.set_size_request (-1, (int)timebar_height);
414 samples_label.set_alignment (1.0, 0.5);
415 samples_label.set_padding (5,0);
416 samples_label.hide ();
417 samples_label.set_no_show_all();
419 tempo_label.set_name ("EditorTimeButton");
420 tempo_label.set_size_request (-1, (int)timebar_height);
421 tempo_label.set_alignment (1.0, 0.5);
422 tempo_label.set_padding (5,0);
424 tempo_label.set_no_show_all();
426 meter_label.set_name ("EditorTimeButton");
427 meter_label.set_size_request (-1, (int)timebar_height);
428 meter_label.set_alignment (1.0, 0.5);
429 meter_label.set_padding (5,0);
431 meter_label.set_no_show_all();
433 mark_label.set_name ("EditorTimeButton");
434 mark_label.set_size_request (-1, (int)timebar_height);
435 mark_label.set_alignment (1.0, 0.5);
436 mark_label.set_padding (5,0);
438 mark_label.set_no_show_all();
440 cd_mark_label.set_name ("EditorTimeButton");
441 cd_mark_label.set_size_request (-1, (int)timebar_height);
442 cd_mark_label.set_alignment (1.0, 0.5);
443 cd_mark_label.set_padding (5,0);
444 cd_mark_label.hide();
445 cd_mark_label.set_no_show_all();
447 range_mark_label.set_name ("EditorTimeButton");
448 range_mark_label.set_size_request (-1, (int)timebar_height);
449 range_mark_label.set_alignment (1.0, 0.5);
450 range_mark_label.set_padding (5,0);
451 range_mark_label.hide();
452 range_mark_label.set_no_show_all();
454 transport_mark_label.set_name ("EditorTimeButton");
455 transport_mark_label.set_size_request (-1, (int)timebar_height);
456 transport_mark_label.set_alignment (1.0, 0.5);
457 transport_mark_label.set_padding (5,0);
458 transport_mark_label.hide();
459 transport_mark_label.set_no_show_all();
461 initialize_rulers ();
462 initialize_canvas ();
464 _summary = new EditorSummary (this);
466 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
467 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
469 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
471 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
472 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
474 edit_controls_vbox.set_spacing (0);
475 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
476 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
478 HBox* h = manage (new HBox);
479 _group_tabs = new EditorGroupTabs (this);
480 h->pack_start (*_group_tabs, PACK_SHRINK);
481 h->pack_start (edit_controls_vbox);
482 controls_layout.add (*h);
484 controls_layout.set_name ("EditControlsBase");
485 controls_layout.add_events (Gdk::SCROLL_MASK);
486 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
488 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
489 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
491 _cursors = new MouseCursors;
493 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
494 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
495 0.0, 1.0, 100.0, 1.0));
497 pad_line_1->property_color_rgba() = 0xFF0000FF;
502 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
503 time_canvas_vbox.set_size_request (-1, -1);
505 ruler_label_event_box.add (ruler_label_vbox);
506 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
507 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
509 time_button_event_box.add (time_button_vbox);
510 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
511 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
513 /* these enable us to have a dedicated window (for cursor setting, etc.)
514 for the canvas areas.
517 track_canvas_event_box.add (*track_canvas);
519 time_canvas_event_box.add (time_canvas_vbox);
520 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
522 edit_packer.set_col_spacings (0);
523 edit_packer.set_row_spacings (0);
524 edit_packer.set_homogeneous (false);
525 edit_packer.set_border_width (0);
526 edit_packer.set_name ("EditorWindow");
528 /* labels for the rulers */
529 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
530 /* labels for the marker "tracks" */
531 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
533 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
535 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
537 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
539 bottom_hbox.set_border_width (2);
540 bottom_hbox.set_spacing (3);
542 _route_groups = new EditorRouteGroups (this);
543 _routes = new EditorRoutes (this);
544 _regions = new EditorRegions (this);
545 _snapshots = new EditorSnapshots (this);
546 _locations = new EditorLocations (this);
548 add_notebook_page (_("Regions"), _regions->widget ());
549 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
550 add_notebook_page (_("Snapshots"), _snapshots->widget ());
551 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
552 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
554 _the_notebook.set_show_tabs (true);
555 _the_notebook.set_scrollable (true);
556 _the_notebook.popup_disable ();
557 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
558 _the_notebook.show_all ();
560 _notebook_shrunk = false;
562 editor_summary_pane.pack1(edit_packer);
564 Button* summary_arrows_left_left = manage (new Button);
565 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
566 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
567 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
569 Button* summary_arrows_left_right = manage (new Button);
570 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
571 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
572 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
574 VBox* summary_arrows_left = manage (new VBox);
575 summary_arrows_left->pack_start (*summary_arrows_left_left);
576 summary_arrows_left->pack_start (*summary_arrows_left_right);
578 Button* summary_arrows_right_up = manage (new Button);
579 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
580 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
581 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
583 Button* summary_arrows_right_down = manage (new Button);
584 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
585 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
586 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
588 VBox* summary_arrows_right = manage (new VBox);
589 summary_arrows_right->pack_start (*summary_arrows_right_up);
590 summary_arrows_right->pack_start (*summary_arrows_right_down);
592 Frame* summary_frame = manage (new Frame);
593 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
595 summary_frame->add (*_summary);
596 summary_frame->show ();
598 _summary_hbox.pack_start (*summary_arrows_left, false, false);
599 _summary_hbox.pack_start (*summary_frame, true, true);
600 _summary_hbox.pack_start (*summary_arrows_right, false, false);
602 editor_summary_pane.pack2 (_summary_hbox);
604 edit_pane.pack1 (editor_summary_pane, true, true);
605 edit_pane.pack2 (_the_notebook, false, true);
607 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
609 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
611 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
613 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
614 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
616 top_hbox.pack_start (toolbar_frame);
618 HBox *hbox = manage (new HBox);
619 hbox->pack_start (edit_pane, true, true);
621 global_vpacker.pack_start (top_hbox, false, false);
622 global_vpacker.pack_start (*hbox, true, true);
624 global_hpacker.pack_start (global_vpacker, true, true);
626 set_name ("EditorWindow");
627 add_accel_group (ActionManager::ui_manager->get_accel_group());
629 status_bar_hpacker.show ();
631 vpacker.pack_end (status_bar_hpacker, false, false);
632 vpacker.pack_end (global_hpacker, true, true);
634 /* register actions now so that set_state() can find them and set toggles/checks etc */
637 /* when we start using our own keybinding system for the editor, this
638 * will be uncommented
644 _snap_type = SnapToBeat;
645 set_snap_to (_snap_type);
646 _snap_mode = SnapOff;
647 set_snap_mode (_snap_mode);
648 set_mouse_mode (MouseObject, true);
649 pre_internal_mouse_mode = MouseObject;
650 pre_internal_snap_type = _snap_type;
651 pre_internal_snap_mode = _snap_mode;
652 internal_snap_type = _snap_type;
653 internal_snap_mode = _snap_mode;
654 set_edit_point_preference (EditAtMouse, true);
656 _playlist_selector = new PlaylistSelector();
657 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
659 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
663 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
664 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
666 nudge_forward_button.set_name ("TransportButton");
667 nudge_backward_button.set_name ("TransportButton");
669 fade_context_menu.set_name ("ArdourContextMenu");
671 /* icons, titles, WM stuff */
673 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
674 Glib::RefPtr<Gdk::Pixbuf> icon;
676 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
683 window_icons.push_back (icon);
685 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
686 window_icons.push_back (icon);
688 if (!window_icons.empty()) {
689 // set_icon_list (window_icons);
690 set_default_icon_list (window_icons);
693 WindowTitle title(Glib::get_application_name());
694 title += _("Editor");
695 set_title (title.get_string());
696 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
699 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
701 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
702 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
704 /* allow external control surfaces/protocols to do various things */
706 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
707 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
708 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
709 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
710 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
711 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
712 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
713 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
714 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
715 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
716 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
717 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
718 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
719 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
721 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
722 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
723 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
724 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
725 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
727 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
729 /* problematic: has to return a value and thus cannot be x-thread */
731 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
733 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
735 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
737 _ignore_region_action = false;
738 _last_region_menu_was_main = false;
739 _popup_region_menu_item = 0;
741 _show_marker_lines = false;
742 _over_region_trim_target = false;
744 /* Button bindings */
746 button_bindings = new Bindings;
748 XMLNode* node = button_settings();
750 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
751 button_bindings->load (**i);
758 setup_fade_images ();
764 if(image_socket_listener) {
765 if(image_socket_listener->is_connected())
767 image_socket_listener->close_connection() ;
770 delete image_socket_listener ;
771 image_socket_listener = 0 ;
775 delete button_bindings;
777 delete _route_groups;
783 Editor::button_settings () const
785 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
786 XMLNode* node = find_named_node (*settings, X_("Buttons"));
789 node = new XMLNode (X_("Buttons"));
796 Editor::add_toplevel_controls (Container& cont)
798 vpacker.pack_start (cont, false, false);
803 Editor::catch_vanishing_regionview (RegionView *rv)
805 /* note: the selection will take care of the vanishing
806 audioregionview by itself.
809 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
813 if (clicked_regionview == rv) {
814 clicked_regionview = 0;
817 if (entered_regionview == rv) {
818 set_entered_regionview (0);
821 if (!_all_region_actions_sensitized) {
822 sensitize_all_region_actions (true);
825 _over_region_trim_target = false;
829 Editor::set_entered_regionview (RegionView* rv)
831 if (rv == entered_regionview) {
835 if (entered_regionview) {
836 entered_regionview->exited ();
839 if ((entered_regionview = rv) != 0) {
840 entered_regionview->entered (internal_editing ());
843 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
844 /* This RegionView entry might have changed what region actions
845 are allowed, so sensitize them all in case a key is pressed.
847 sensitize_all_region_actions (true);
852 Editor::set_entered_track (TimeAxisView* tav)
855 entered_track->exited ();
858 if ((entered_track = tav) != 0) {
859 entered_track->entered ();
864 Editor::show_window ()
866 if (!is_visible ()) {
869 /* XXX: this is a bit unfortunate; it would probably
870 be nicer if we could just call show () above rather
871 than needing the show_all ()
874 /* re-hide stuff if necessary */
875 editor_list_button_toggled ();
876 parameter_changed ("show-summary");
877 parameter_changed ("show-group-tabs");
878 parameter_changed ("show-zoom-tools");
880 /* now reset all audio_time_axis heights, because widgets might need
886 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
887 tv = (static_cast<TimeAxisView*>(*i));
891 if (current_mixer_strip) {
892 current_mixer_strip->hide_things ();
893 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
901 Editor::instant_save ()
903 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
908 _session->add_instant_xml(get_state());
910 Config->add_instant_xml(get_state());
915 Editor::zoom_adjustment_changed ()
921 double fpu = zoom_range_clock->current_duration() / _canvas_width;
925 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
926 } else if (fpu > _session->current_end_frame() / _canvas_width) {
927 fpu = _session->current_end_frame() / _canvas_width;
928 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
935 Editor::control_vertical_zoom_in_all ()
937 tav_zoom_smooth (false, true);
941 Editor::control_vertical_zoom_out_all ()
943 tav_zoom_smooth (true, true);
947 Editor::control_vertical_zoom_in_selected ()
949 tav_zoom_smooth (false, false);
953 Editor::control_vertical_zoom_out_selected ()
955 tav_zoom_smooth (true, false);
959 Editor::control_view (uint32_t view)
961 goto_visual_state (view);
965 Editor::control_unselect ()
967 selection->clear_tracks ();
971 Editor::control_select (uint32_t rid, Selection::Operation op)
973 /* handles the (static) signal from the ControlProtocol class that
974 * requests setting the selected track to a given RID
981 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
987 TimeAxisView* tav = axis_view_from_route (r);
992 selection->add (tav);
994 case Selection::Toggle:
995 selection->toggle (tav);
997 case Selection::Extend:
1000 selection->set (tav);
1004 selection->clear_tracks ();
1009 Editor::control_step_tracks_up ()
1011 scroll_tracks_up_line ();
1015 Editor::control_step_tracks_down ()
1017 scroll_tracks_down_line ();
1021 Editor::control_scroll (float fraction)
1023 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1029 double step = fraction * current_page_frames();
1032 _control_scroll_target is an optional<T>
1034 it acts like a pointer to an framepos_t, with
1035 a operator conversion to boolean to check
1036 that it has a value could possibly use
1037 playhead_cursor->current_frame to store the
1038 value and a boolean in the class to know
1039 when it's out of date
1042 if (!_control_scroll_target) {
1043 _control_scroll_target = _session->transport_frame();
1044 _dragging_playhead = true;
1047 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1048 *_control_scroll_target = 0;
1049 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1050 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1052 *_control_scroll_target += (framepos_t) floor (step);
1055 /* move visuals, we'll catch up with it later */
1057 playhead_cursor->set_position (*_control_scroll_target);
1058 UpdateAllTransportClocks (*_control_scroll_target);
1060 if (*_control_scroll_target > (current_page_frames() / 2)) {
1061 /* try to center PH in window */
1062 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1068 Now we do a timeout to actually bring the session to the right place
1069 according to the playhead. This is to avoid reading disk buffers on every
1070 call to control_scroll, which is driven by ScrollTimeline and therefore
1071 probably by a control surface wheel which can generate lots of events.
1073 /* cancel the existing timeout */
1075 control_scroll_connection.disconnect ();
1077 /* add the next timeout */
1079 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1083 Editor::deferred_control_scroll (framepos_t /*target*/)
1085 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1086 // reset for next stream
1087 _control_scroll_target = boost::none;
1088 _dragging_playhead = false;
1093 Editor::access_action (std::string action_group, std::string action_item)
1099 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1102 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1110 Editor::on_realize ()
1112 Window::on_realize ();
1117 Editor::map_position_change (framepos_t frame)
1119 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1121 if (_session == 0) {
1125 if (_follow_playhead) {
1126 center_screen (frame);
1129 playhead_cursor->set_position (frame);
1133 Editor::center_screen (framepos_t frame)
1135 double page = _canvas_width * frames_per_unit;
1137 /* if we're off the page, then scroll.
1140 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1141 center_screen_internal (frame, page);
1146 Editor::center_screen_internal (framepos_t frame, float page)
1151 frame -= (framepos_t) page;
1156 reset_x_origin (frame);
1161 Editor::update_title ()
1163 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1166 bool dirty = _session->dirty();
1168 string session_name;
1170 if (_session->snap_name() != _session->name()) {
1171 session_name = _session->snap_name();
1173 session_name = _session->name();
1177 session_name = "*" + session_name;
1180 WindowTitle title(session_name);
1181 title += Glib::get_application_name();
1182 set_title (title.get_string());
1187 Editor::set_session (Session *t)
1189 SessionHandlePtr::set_session (t);
1195 zoom_range_clock->set_session (_session);
1196 _playlist_selector->set_session (_session);
1197 nudge_clock->set_session (_session);
1198 _summary->set_session (_session);
1199 _group_tabs->set_session (_session);
1200 _route_groups->set_session (_session);
1201 _regions->set_session (_session);
1202 _snapshots->set_session (_session);
1203 _routes->set_session (_session);
1204 _locations->set_session (_session);
1206 if (rhythm_ferret) {
1207 rhythm_ferret->set_session (_session);
1210 if (analysis_window) {
1211 analysis_window->set_session (_session);
1215 sfbrowser->set_session (_session);
1218 compute_fixed_ruler_scale ();
1220 /* Make sure we have auto loop and auto punch ranges */
1222 Location* loc = _session->locations()->auto_loop_location();
1224 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1226 if (loc->start() == loc->end()) {
1227 loc->set_end (loc->start() + 1);
1230 _session->locations()->add (loc, false);
1231 _session->set_auto_loop_location (loc);
1234 loc->set_name (_("Loop"));
1237 loc = _session->locations()->auto_punch_location();
1240 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1242 if (loc->start() == loc->end()) {
1243 loc->set_end (loc->start() + 1);
1246 _session->locations()->add (loc, false);
1247 _session->set_auto_punch_location (loc);
1250 loc->set_name (_("Punch"));
1253 refresh_location_display ();
1255 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1256 the selected Marker; this needs the LocationMarker list to be available.
1258 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1259 set_state (*node, Stateful::loading_state_version);
1261 /* catch up with the playhead */
1263 _session->request_locate (playhead_cursor->current_frame);
1264 _pending_initial_locate = true;
1268 /* These signals can all be emitted by a non-GUI thread. Therefore the
1269 handlers for them must not attempt to directly interact with the GUI,
1270 but use Gtkmm2ext::UI::instance()->call_slot();
1273 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1274 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1275 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1276 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::handle_new_route, this, _1), gui_context());
1277 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1278 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1279 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1280 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1281 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1282 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1283 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1284 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1285 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1286 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1288 playhead_cursor->canvas_item.show ();
1290 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1291 Config->map_parameters (pc);
1292 _session->config.map_parameters (pc);
1294 restore_ruler_visibility ();
1295 //tempo_map_changed (PropertyChange (0));
1296 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1298 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1299 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1302 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1303 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1306 switch (_snap_type) {
1307 case SnapToRegionStart:
1308 case SnapToRegionEnd:
1309 case SnapToRegionSync:
1310 case SnapToRegionBoundary:
1311 build_region_boundary_cache ();
1318 /* register for undo history */
1319 _session->register_with_memento_command_factory(id(), this);
1321 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1323 start_updating_meters ();
1327 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1329 if (a->get_name() == "RegionMenu") {
1330 /* When the main menu's region menu is opened, we setup the actions so that they look right
1331 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1332 so we resensitize all region actions when the entered regionview or the region selection
1333 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1334 happens after the region context menu is opened. So we set a flag here, too.
1338 sensitize_the_right_region_actions ();
1339 _last_region_menu_was_main = true;
1344 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1346 using namespace Menu_Helpers;
1348 void (Editor::*emf)(FadeShape);
1349 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1352 images = &_xfade_in_images;
1353 emf = &Editor::set_fade_in_shape;
1355 images = &_xfade_out_images;
1356 emf = &Editor::set_fade_out_shape;
1361 _("Linear (for highly correlated material)"),
1362 *(*images)[FadeLinear],
1363 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1367 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1372 *(*images)[FadeConstantPower],
1373 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1376 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1381 *(*images)[FadeSymmetric],
1382 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1386 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1391 *(*images)[FadeSlow],
1392 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1395 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 *(*images)[FadeFast],
1401 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1407 /** Pop up a context menu for when the user clicks on a start crossfade */
1409 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1411 using namespace Menu_Helpers;
1413 MenuList& items (xfade_in_context_menu.items());
1415 if (items.empty()) {
1416 fill_xfade_menu (items, true);
1419 xfade_in_context_menu.popup (button, time);
1422 /** Pop up a context menu for when the user clicks on an end crossfade */
1424 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1426 using namespace Menu_Helpers;
1428 MenuList& items (xfade_out_context_menu.items());
1430 if (items.empty()) {
1431 fill_xfade_menu (items, false);
1434 xfade_out_context_menu.popup (button, time);
1438 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1440 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1442 using namespace Menu_Helpers;
1443 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1446 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1450 MenuList& items (fade_context_menu.items());
1453 switch (item_type) {
1455 case FadeInHandleItem:
1456 if (arv->audio_region()->fade_in_active()) {
1457 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1459 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1462 items.push_back (SeparatorElem());
1464 if (Profile->get_sae()) {
1466 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1467 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1474 *_fade_in_images[FadeLinear],
1475 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1479 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1484 *_fade_in_images[FadeSlow],
1485 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1488 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1493 *_fade_in_images[FadeFast],
1494 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1497 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1502 *_fade_in_images[FadeSymmetric],
1503 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1508 _("Constant Power"),
1509 *_fade_in_images[FadeConstantPower],
1510 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1513 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1519 case FadeOutHandleItem:
1520 if (arv->audio_region()->fade_out_active()) {
1521 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1523 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1526 items.push_back (SeparatorElem());
1528 if (Profile->get_sae()) {
1529 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1530 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1536 *_fade_out_images[FadeLinear],
1537 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1541 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1546 *_fade_out_images[FadeSlow],
1547 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1550 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1555 *_fade_out_images[FadeFast],
1556 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1559 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1564 *_fade_out_images[FadeSymmetric],
1565 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1570 _("Constant Power"),
1571 *_fade_out_images[FadeConstantPower],
1572 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1575 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1581 fatal << _("programming error: ")
1582 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1587 fade_context_menu.popup (button, time);
1591 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1593 using namespace Menu_Helpers;
1594 Menu* (Editor::*build_menu_function)();
1597 switch (item_type) {
1599 case RegionViewName:
1600 case RegionViewNameHighlight:
1601 case LeftFrameHandle:
1602 case RightFrameHandle:
1603 if (with_selection) {
1604 build_menu_function = &Editor::build_track_selection_context_menu;
1606 build_menu_function = &Editor::build_track_region_context_menu;
1611 if (with_selection) {
1612 build_menu_function = &Editor::build_track_selection_context_menu;
1614 build_menu_function = &Editor::build_track_context_menu;
1619 if (clicked_routeview->track()) {
1620 build_menu_function = &Editor::build_track_context_menu;
1622 build_menu_function = &Editor::build_track_bus_context_menu;
1627 /* probably shouldn't happen but if it does, we don't care */
1631 menu = (this->*build_menu_function)();
1632 menu->set_name ("ArdourContextMenu");
1634 /* now handle specific situations */
1636 switch (item_type) {
1638 case RegionViewName:
1639 case RegionViewNameHighlight:
1640 case LeftFrameHandle:
1641 case RightFrameHandle:
1642 if (!with_selection) {
1643 if (region_edit_menu_split_item) {
1644 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1645 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1647 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1650 if (region_edit_menu_split_multichannel_item) {
1651 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1652 region_edit_menu_split_multichannel_item->set_sensitive (true);
1654 region_edit_menu_split_multichannel_item->set_sensitive (false);
1667 /* probably shouldn't happen but if it does, we don't care */
1671 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1673 /* Bounce to disk */
1675 using namespace Menu_Helpers;
1676 MenuList& edit_items = menu->items();
1678 edit_items.push_back (SeparatorElem());
1680 switch (clicked_routeview->audio_track()->freeze_state()) {
1681 case AudioTrack::NoFreeze:
1682 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1685 case AudioTrack::Frozen:
1686 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1689 case AudioTrack::UnFrozen:
1690 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1696 if (item_type == StreamItem && clicked_routeview) {
1697 clicked_routeview->build_underlay_menu(menu);
1700 /* When the region menu is opened, we setup the actions so that they look right
1703 sensitize_the_right_region_actions ();
1704 _last_region_menu_was_main = false;
1706 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1707 menu->popup (button, time);
1711 Editor::build_track_context_menu ()
1713 using namespace Menu_Helpers;
1715 MenuList& edit_items = track_context_menu.items();
1718 add_dstream_context_items (edit_items);
1719 return &track_context_menu;
1723 Editor::build_track_bus_context_menu ()
1725 using namespace Menu_Helpers;
1727 MenuList& edit_items = track_context_menu.items();
1730 add_bus_context_items (edit_items);
1731 return &track_context_menu;
1735 Editor::build_track_region_context_menu ()
1737 using namespace Menu_Helpers;
1738 MenuList& edit_items = track_region_context_menu.items();
1741 /* we've just cleared the track region context menu, so the menu that these
1742 two items were on will have disappeared; stop them dangling.
1744 region_edit_menu_split_item = 0;
1745 region_edit_menu_split_multichannel_item = 0;
1747 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1750 boost::shared_ptr<Track> tr;
1751 boost::shared_ptr<Playlist> pl;
1753 if ((tr = rtv->track())) {
1754 add_region_context_items (edit_items, tr);
1758 add_dstream_context_items (edit_items);
1760 return &track_region_context_menu;
1764 Editor::analyze_region_selection ()
1766 if (analysis_window == 0) {
1767 analysis_window = new AnalysisWindow();
1770 analysis_window->set_session(_session);
1772 analysis_window->show_all();
1775 analysis_window->set_regionmode();
1776 analysis_window->analyze();
1778 analysis_window->present();
1782 Editor::analyze_range_selection()
1784 if (analysis_window == 0) {
1785 analysis_window = new AnalysisWindow();
1788 analysis_window->set_session(_session);
1790 analysis_window->show_all();
1793 analysis_window->set_rangemode();
1794 analysis_window->analyze();
1796 analysis_window->present();
1800 Editor::build_track_selection_context_menu ()
1802 using namespace Menu_Helpers;
1803 MenuList& edit_items = track_selection_context_menu.items();
1804 edit_items.clear ();
1806 add_selection_context_items (edit_items);
1807 // edit_items.push_back (SeparatorElem());
1808 // add_dstream_context_items (edit_items);
1810 return &track_selection_context_menu;
1814 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1816 using namespace Menu_Helpers;
1818 /* OK, stick the region submenu at the top of the list, and then add
1822 RegionSelection rs = get_regions_from_selection_and_entered ();
1824 string::size_type pos = 0;
1825 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1827 /* we have to hack up the region name because "_" has a special
1828 meaning for menu titles.
1831 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1832 menu_item_name.replace (pos, 1, "__");
1836 if (_popup_region_menu_item == 0) {
1837 _popup_region_menu_item = new MenuItem (menu_item_name);
1838 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1839 _popup_region_menu_item->show ();
1841 _popup_region_menu_item->set_label (menu_item_name);
1844 const framepos_t position = get_preferred_edit_position (false, true);
1846 edit_items.push_back (*_popup_region_menu_item);
1847 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1848 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1850 edit_items.push_back (SeparatorElem());
1853 /** Add context menu items relevant to selection ranges.
1854 * @param edit_items List to add the items to.
1857 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1859 using namespace Menu_Helpers;
1861 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1862 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1864 edit_items.push_back (SeparatorElem());
1865 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1867 edit_items.push_back (SeparatorElem());
1869 edit_items.push_back (
1871 _("Move Range Start to Previous Region Boundary"),
1872 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1876 edit_items.push_back (
1878 _("Move Range Start to Next Region Boundary"),
1879 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1883 edit_items.push_back (
1885 _("Move Range End to Previous Region Boundary"),
1886 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1890 edit_items.push_back (
1892 _("Move Range End to Next Region Boundary"),
1893 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1897 edit_items.push_back (SeparatorElem());
1898 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1899 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1901 edit_items.push_back (SeparatorElem());
1902 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1904 edit_items.push_back (SeparatorElem());
1905 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1906 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1908 edit_items.push_back (SeparatorElem());
1909 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1911 edit_items.push_back (SeparatorElem());
1912 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1913 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1914 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1916 edit_items.push_back (SeparatorElem());
1917 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1918 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1919 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1920 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1921 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1926 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1928 using namespace Menu_Helpers;
1932 Menu *play_menu = manage (new Menu);
1933 MenuList& play_items = play_menu->items();
1934 play_menu->set_name ("ArdourContextMenu");
1936 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1937 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1938 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1939 play_items.push_back (SeparatorElem());
1940 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1942 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1946 Menu *select_menu = manage (new Menu);
1947 MenuList& select_items = select_menu->items();
1948 select_menu->set_name ("ArdourContextMenu");
1950 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1951 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1952 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1953 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1954 select_items.push_back (SeparatorElem());
1955 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1956 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1957 select_items.push_back (SeparatorElem());
1958 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1959 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1960 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1961 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1962 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1963 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1964 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1966 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1970 Menu *cutnpaste_menu = manage (new Menu);
1971 MenuList& cutnpaste_items = cutnpaste_menu->items();
1972 cutnpaste_menu->set_name ("ArdourContextMenu");
1974 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1975 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1976 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1978 cutnpaste_items.push_back (SeparatorElem());
1980 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1981 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1983 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1985 /* Adding new material */
1987 edit_items.push_back (SeparatorElem());
1988 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1989 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1993 Menu *nudge_menu = manage (new Menu());
1994 MenuList& nudge_items = nudge_menu->items();
1995 nudge_menu->set_name ("ArdourContextMenu");
1997 edit_items.push_back (SeparatorElem());
1998 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1999 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2000 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2001 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2003 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2007 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2009 using namespace Menu_Helpers;
2013 Menu *play_menu = manage (new Menu);
2014 MenuList& play_items = play_menu->items();
2015 play_menu->set_name ("ArdourContextMenu");
2017 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2018 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2019 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2023 Menu *select_menu = manage (new Menu);
2024 MenuList& select_items = select_menu->items();
2025 select_menu->set_name ("ArdourContextMenu");
2027 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2028 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2029 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2030 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2031 select_items.push_back (SeparatorElem());
2032 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2033 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2034 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2035 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2037 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2041 Menu *cutnpaste_menu = manage (new Menu);
2042 MenuList& cutnpaste_items = cutnpaste_menu->items();
2043 cutnpaste_menu->set_name ("ArdourContextMenu");
2045 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2046 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2047 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2049 Menu *nudge_menu = manage (new Menu());
2050 MenuList& nudge_items = nudge_menu->items();
2051 nudge_menu->set_name ("ArdourContextMenu");
2053 edit_items.push_back (SeparatorElem());
2054 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2055 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2056 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2057 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2059 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2063 Editor::snap_type() const
2069 Editor::snap_mode() const
2075 Editor::set_snap_to (SnapType st)
2077 unsigned int snap_ind = (unsigned int)st;
2081 if (snap_ind > snap_type_strings.size() - 1) {
2083 _snap_type = (SnapType)snap_ind;
2086 string str = snap_type_strings[snap_ind];
2088 if (str != snap_type_selector.get_active_text()) {
2089 snap_type_selector.set_active_text (str);
2094 switch (_snap_type) {
2095 case SnapToBeatDiv128:
2096 case SnapToBeatDiv64:
2097 case SnapToBeatDiv32:
2098 case SnapToBeatDiv28:
2099 case SnapToBeatDiv24:
2100 case SnapToBeatDiv20:
2101 case SnapToBeatDiv16:
2102 case SnapToBeatDiv14:
2103 case SnapToBeatDiv12:
2104 case SnapToBeatDiv10:
2105 case SnapToBeatDiv8:
2106 case SnapToBeatDiv7:
2107 case SnapToBeatDiv6:
2108 case SnapToBeatDiv5:
2109 case SnapToBeatDiv4:
2110 case SnapToBeatDiv3:
2111 case SnapToBeatDiv2:
2112 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2113 update_tempo_based_rulers ();
2116 case SnapToRegionStart:
2117 case SnapToRegionEnd:
2118 case SnapToRegionSync:
2119 case SnapToRegionBoundary:
2120 build_region_boundary_cache ();
2128 SnapChanged (); /* EMIT SIGNAL */
2132 Editor::set_snap_mode (SnapMode mode)
2135 string str = snap_mode_strings[(int)mode];
2137 if (str != snap_mode_selector.get_active_text ()) {
2138 snap_mode_selector.set_active_text (str);
2144 Editor::set_edit_point_preference (EditPoint ep, bool force)
2146 bool changed = (_edit_point != ep);
2149 string str = edit_point_strings[(int)ep];
2151 if (str != edit_point_selector.get_active_text ()) {
2152 edit_point_selector.set_active_text (str);
2155 set_canvas_cursor ();
2157 if (!force && !changed) {
2161 const char* action=NULL;
2163 switch (_edit_point) {
2164 case EditAtPlayhead:
2165 action = "edit-at-playhead";
2167 case EditAtSelectedMarker:
2168 action = "edit-at-marker";
2171 action = "edit-at-mouse";
2175 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2177 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2181 bool in_track_canvas;
2183 if (!mouse_frame (foo, in_track_canvas)) {
2184 in_track_canvas = false;
2187 reset_canvas_action_sensitivity (in_track_canvas);
2193 Editor::set_state (const XMLNode& node, int /*version*/)
2195 const XMLProperty* prop;
2202 g.base_width = default_width;
2203 g.base_height = default_height;
2207 if ((geometry = find_named_node (node, "geometry")) != 0) {
2211 if ((prop = geometry->property("x_size")) == 0) {
2212 prop = geometry->property ("x-size");
2215 g.base_width = atoi(prop->value());
2217 if ((prop = geometry->property("y_size")) == 0) {
2218 prop = geometry->property ("y-size");
2221 g.base_height = atoi(prop->value());
2224 if ((prop = geometry->property ("x_pos")) == 0) {
2225 prop = geometry->property ("x-pos");
2228 x = atoi (prop->value());
2231 if ((prop = geometry->property ("y_pos")) == 0) {
2232 prop = geometry->property ("y-pos");
2235 y = atoi (prop->value());
2239 set_default_size (g.base_width, g.base_height);
2242 if (_session && (prop = node.property ("playhead"))) {
2244 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2245 playhead_cursor->set_position (pos);
2247 playhead_cursor->set_position (0);
2250 if ((prop = node.property ("mixer-width"))) {
2251 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2254 if ((prop = node.property ("zoom-focus"))) {
2255 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2258 if ((prop = node.property ("zoom"))) {
2259 reset_zoom (PBD::atof (prop->value()));
2261 reset_zoom (frames_per_unit);
2264 if ((prop = node.property ("snap-to"))) {
2265 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2268 if ((prop = node.property ("snap-mode"))) {
2269 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2272 if ((prop = node.property ("internal-snap-to"))) {
2273 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2276 if ((prop = node.property ("internal-snap-mode"))) {
2277 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2280 if ((prop = node.property ("pre-internal-snap-to"))) {
2281 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2284 if ((prop = node.property ("pre-internal-snap-mode"))) {
2285 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2288 if ((prop = node.property ("mouse-mode"))) {
2289 MouseMode m = str2mousemode(prop->value());
2290 set_mouse_mode (m, true);
2292 set_mouse_mode (MouseObject, true);
2295 if ((prop = node.property ("left-frame")) != 0) {
2297 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2301 reset_x_origin (pos);
2305 if ((prop = node.property ("y-origin")) != 0) {
2306 reset_y_origin (atof (prop->value ()));
2309 if ((prop = node.property ("internal-edit"))) {
2310 bool yn = string_is_affirmative (prop->value());
2311 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2313 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2314 tact->set_active (!yn);
2315 tact->set_active (yn);
2319 if ((prop = node.property ("join-object-range"))) {
2320 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2323 if ((prop = node.property ("edit-point"))) {
2324 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2327 if ((prop = node.property ("show-measures"))) {
2328 bool yn = string_is_affirmative (prop->value());
2329 _show_measures = yn;
2330 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2332 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2333 /* do it twice to force the change */
2334 tact->set_active (!yn);
2335 tact->set_active (yn);
2339 if ((prop = node.property ("follow-playhead"))) {
2340 bool yn = string_is_affirmative (prop->value());
2341 set_follow_playhead (yn);
2342 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2344 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2345 if (tact->get_active() != yn) {
2346 tact->set_active (yn);
2351 if ((prop = node.property ("stationary-playhead"))) {
2352 bool yn = string_is_affirmative (prop->value());
2353 set_stationary_playhead (yn);
2354 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2356 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2357 if (tact->get_active() != yn) {
2358 tact->set_active (yn);
2363 if ((prop = node.property ("region-list-sort-type"))) {
2364 RegionListSortType st;
2365 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2368 if ((prop = node.property ("show-editor-mixer"))) {
2370 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2373 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2374 bool yn = string_is_affirmative (prop->value());
2376 /* do it twice to force the change */
2378 tact->set_active (!yn);
2379 tact->set_active (yn);
2382 if ((prop = node.property ("show-editor-list"))) {
2384 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2387 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2388 bool yn = string_is_affirmative (prop->value());
2390 /* do it twice to force the change */
2392 tact->set_active (!yn);
2393 tact->set_active (yn);
2396 if ((prop = node.property (X_("editor-list-page")))) {
2397 _the_notebook.set_current_page (atoi (prop->value ()));
2400 if ((prop = node.property (X_("show-marker-lines")))) {
2401 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2403 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2404 bool yn = string_is_affirmative (prop->value ());
2406 tact->set_active (!yn);
2407 tact->set_active (yn);
2410 XMLNodeList children = node.children ();
2411 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2412 selection->set_state (**i, Stateful::current_state_version);
2413 _regions->set_state (**i);
2416 if ((prop = node.property ("maximised"))) {
2417 bool yn = string_is_affirmative (prop->value());
2419 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2423 if ((prop = node.property ("nudge-clock-value"))) {
2425 sscanf (prop->value().c_str(), "%" PRId64, &f);
2426 nudge_clock->set (f);
2428 nudge_clock->set_mode (AudioClock::Timecode);
2429 nudge_clock->set (_session->frame_rate() * 5, true);
2436 Editor::get_state ()
2438 XMLNode* node = new XMLNode ("Editor");
2441 id().print (buf, sizeof (buf));
2442 node->add_property ("id", buf);
2444 if (is_realized()) {
2445 Glib::RefPtr<Gdk::Window> win = get_window();
2447 int x, y, width, height;
2448 win->get_root_origin(x, y);
2449 win->get_size(width, height);
2451 XMLNode* geometry = new XMLNode ("geometry");
2453 snprintf(buf, sizeof(buf), "%d", width);
2454 geometry->add_property("x-size", string(buf));
2455 snprintf(buf, sizeof(buf), "%d", height);
2456 geometry->add_property("y-size", string(buf));
2457 snprintf(buf, sizeof(buf), "%d", x);
2458 geometry->add_property("x-pos", string(buf));
2459 snprintf(buf, sizeof(buf), "%d", y);
2460 geometry->add_property("y-pos", string(buf));
2461 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2462 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2463 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2464 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2465 geometry->add_property("edit-vertical-pane-pos", string(buf));
2467 node->add_child_nocopy (*geometry);
2470 maybe_add_mixer_strip_width (*node);
2472 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2473 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2474 node->add_property ("zoom", buf);
2475 node->add_property ("snap-to", enum_2_string (_snap_type));
2476 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2477 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2478 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2479 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2480 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2481 node->add_property ("edit-point", enum_2_string (_edit_point));
2483 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2484 node->add_property ("playhead", buf);
2485 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2486 node->add_property ("left-frame", buf);
2487 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2488 node->add_property ("y-origin", buf);
2490 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2491 node->add_property ("maximised", _maximised ? "yes" : "no");
2492 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2493 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2494 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2495 node->add_property ("mouse-mode", enum2str(mouse_mode));
2496 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2497 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2499 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2501 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2502 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2505 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2507 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2508 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2511 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2512 node->add_property (X_("editor-list-page"), buf);
2514 if (button_bindings) {
2515 XMLNode* bb = new XMLNode (X_("Buttons"));
2516 button_bindings->save (*bb);
2517 node->add_child_nocopy (*bb);
2520 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2522 node->add_child_nocopy (selection->get_state ());
2523 node->add_child_nocopy (_regions->get_state ());
2525 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2526 node->add_property ("nudge-clock-value", buf);
2533 /** @param y y offset from the top of all trackviews.
2534 * @return pair: TimeAxisView that y is over, layer index.
2535 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2536 * in stacked or expanded region display mode, otherwise 0.
2538 std::pair<TimeAxisView *, double>
2539 Editor::trackview_by_y_position (double y)
2541 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2543 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2549 return std::make_pair ( (TimeAxisView *) 0, 0);
2552 /** Snap a position to the grid, if appropriate, taking into account current
2553 * grid settings and also the state of any snap modifier keys that may be pressed.
2554 * @param start Position to snap.
2555 * @param event Event to get current key modifier information from, or 0.
2558 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2560 if (!_session || !event) {
2564 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2565 if (_snap_mode == SnapOff) {
2566 snap_to_internal (start, direction, for_mark);
2569 if (_snap_mode != SnapOff) {
2570 snap_to_internal (start, direction, for_mark);
2576 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2578 if (!_session || _snap_mode == SnapOff) {
2582 snap_to_internal (start, direction, for_mark);
2586 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2588 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2589 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2591 switch (_snap_type) {
2592 case SnapToTimecodeFrame:
2593 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2594 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2596 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2600 case SnapToTimecodeSeconds:
2601 if (_session->config.get_timecode_offset_negative()) {
2602 start += _session->config.get_timecode_offset ();
2604 start -= _session->config.get_timecode_offset ();
2606 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2607 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2609 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2612 if (_session->config.get_timecode_offset_negative()) {
2613 start -= _session->config.get_timecode_offset ();
2615 start += _session->config.get_timecode_offset ();
2619 case SnapToTimecodeMinutes:
2620 if (_session->config.get_timecode_offset_negative()) {
2621 start += _session->config.get_timecode_offset ();
2623 start -= _session->config.get_timecode_offset ();
2625 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2626 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2628 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2630 if (_session->config.get_timecode_offset_negative()) {
2631 start -= _session->config.get_timecode_offset ();
2633 start += _session->config.get_timecode_offset ();
2637 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2643 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2645 const framepos_t one_second = _session->frame_rate();
2646 const framepos_t one_minute = _session->frame_rate() * 60;
2647 framepos_t presnap = start;
2651 switch (_snap_type) {
2652 case SnapToTimecodeFrame:
2653 case SnapToTimecodeSeconds:
2654 case SnapToTimecodeMinutes:
2655 return timecode_snap_to_internal (start, direction, for_mark);
2658 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2659 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2661 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2666 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2667 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2669 start = (framepos_t) floor ((double) start / one_second) * one_second;
2674 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2675 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2677 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2682 start = _session->tempo_map().round_to_bar (start, direction);
2686 start = _session->tempo_map().round_to_beat (start, direction);
2689 case SnapToBeatDiv128:
2690 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2692 case SnapToBeatDiv64:
2693 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2695 case SnapToBeatDiv32:
2696 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2698 case SnapToBeatDiv28:
2699 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2701 case SnapToBeatDiv24:
2702 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2704 case SnapToBeatDiv20:
2705 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2707 case SnapToBeatDiv16:
2708 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2710 case SnapToBeatDiv14:
2711 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2713 case SnapToBeatDiv12:
2714 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2716 case SnapToBeatDiv10:
2717 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2719 case SnapToBeatDiv8:
2720 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2722 case SnapToBeatDiv7:
2723 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2725 case SnapToBeatDiv6:
2726 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2728 case SnapToBeatDiv5:
2729 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2731 case SnapToBeatDiv4:
2732 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2734 case SnapToBeatDiv3:
2735 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2737 case SnapToBeatDiv2:
2738 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2746 _session->locations()->marks_either_side (start, before, after);
2748 if (before == max_framepos) {
2750 } else if (after == max_framepos) {
2752 } else if (before != max_framepos && after != max_framepos) {
2753 /* have before and after */
2754 if ((start - before) < (after - start)) {
2763 case SnapToRegionStart:
2764 case SnapToRegionEnd:
2765 case SnapToRegionSync:
2766 case SnapToRegionBoundary:
2767 if (!region_boundary_cache.empty()) {
2769 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2770 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2772 if (direction > 0) {
2773 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2775 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2778 if (next != region_boundary_cache.begin ()) {
2783 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2784 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2786 if (start > (p + n) / 2) {
2795 switch (_snap_mode) {
2801 if (presnap > start) {
2802 if (presnap > (start + unit_to_frame(snap_threshold))) {
2806 } else if (presnap < start) {
2807 if (presnap < (start - unit_to_frame(snap_threshold))) {
2813 /* handled at entry */
2821 Editor::setup_toolbar ()
2823 HBox* mode_box = manage(new HBox);
2824 mode_box->set_border_width (2);
2825 mode_box->set_spacing(4);
2827 HBox* mouse_mode_box = manage (new HBox);
2828 HBox* mouse_mode_hbox1 = manage (new HBox);
2829 HBox* mouse_mode_hbox2 = manage (new HBox);
2830 VBox* mouse_mode_vbox1 = manage (new VBox);
2831 VBox* mouse_mode_vbox2 = manage (new VBox);
2832 Alignment* mouse_mode_align1 = manage (new Alignment);
2833 Alignment* mouse_mode_align2 = manage (new Alignment);
2835 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2836 mouse_mode_size_group->add_widget (mouse_move_button);
2837 mouse_mode_size_group->add_widget (mouse_select_button);
2838 mouse_mode_size_group->add_widget (mouse_zoom_button);
2839 mouse_mode_size_group->add_widget (mouse_gain_button);
2840 mouse_mode_size_group->add_widget (mouse_timefx_button);
2841 mouse_mode_size_group->add_widget (mouse_audition_button);
2842 mouse_mode_size_group->add_widget (mouse_draw_button);
2843 mouse_mode_size_group->add_widget (internal_edit_button);
2845 /* make them just a bit bigger */
2846 mouse_move_button.set_size_request (-1, 25);
2848 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2849 smart_mode_joiner->set_related_action (smart_mode_action);
2851 mouse_mode_hbox2->set_spacing (2);
2852 mouse_mode_box->set_spacing (2);
2854 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2855 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2856 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2857 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2858 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2859 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2860 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2862 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2863 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2865 mouse_mode_align1->add (*mouse_mode_vbox1);
2866 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2867 mouse_mode_align2->add (*mouse_mode_vbox2);
2868 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2870 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2871 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2873 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2874 if (!Profile->get_sae()) {
2875 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2877 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2879 edit_mode_selector.set_name ("EditModeSelector");
2880 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2881 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2883 mode_box->pack_start (edit_mode_selector, false, false);
2884 mode_box->pack_start (*mouse_mode_box, false, false);
2886 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2887 _mouse_mode_tearoff->set_name ("MouseModeBase");
2888 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2890 if (Profile->get_sae()) {
2891 _mouse_mode_tearoff->set_can_be_torn_off (false);
2894 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2895 &_mouse_mode_tearoff->tearoff_window()));
2896 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2897 &_mouse_mode_tearoff->tearoff_window(), 1));
2898 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2899 &_mouse_mode_tearoff->tearoff_window()));
2900 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2901 &_mouse_mode_tearoff->tearoff_window(), 1));
2905 _zoom_box.set_spacing (2);
2906 _zoom_box.set_border_width (2);
2910 zoom_in_button.set_name ("zoom button");
2911 zoom_in_button.set_image (::get_icon ("zoom_in"));
2912 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2913 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2914 zoom_in_button.set_related_action (act);
2916 zoom_out_button.set_name ("zoom button");
2917 zoom_out_button.set_image (::get_icon ("zoom_out"));
2918 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2919 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2920 zoom_out_button.set_related_action (act);
2922 zoom_out_full_button.set_name ("zoom button");
2923 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2924 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2925 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2926 zoom_out_full_button.set_related_action (act);
2928 zoom_focus_selector.set_name ("ZoomFocusSelector");
2929 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2930 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2932 _zoom_box.pack_start (zoom_out_button, false, false);
2933 _zoom_box.pack_start (zoom_in_button, false, false);
2934 _zoom_box.pack_start (zoom_out_full_button, false, false);
2936 _zoom_box.pack_start (zoom_focus_selector, false, false);
2938 /* Track zoom buttons */
2939 tav_expand_button.set_name ("TrackHeightButton");
2940 tav_expand_button.set_size_request (-1, 20);
2941 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2942 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2943 act->connect_proxy (tav_expand_button);
2945 tav_shrink_button.set_name ("TrackHeightButton");
2946 tav_shrink_button.set_size_request (-1, 20);
2947 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2948 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2949 act->connect_proxy (tav_shrink_button);
2951 _zoom_box.pack_start (tav_shrink_button);
2952 _zoom_box.pack_start (tav_expand_button);
2954 _zoom_tearoff = manage (new TearOff (_zoom_box));
2956 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2957 &_zoom_tearoff->tearoff_window()));
2958 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2959 &_zoom_tearoff->tearoff_window(), 0));
2960 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2961 &_zoom_tearoff->tearoff_window()));
2962 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2963 &_zoom_tearoff->tearoff_window(), 0));
2965 snap_box.set_spacing (1);
2966 snap_box.set_border_width (2);
2968 snap_type_selector.set_name ("SnapTypeSelector");
2969 set_popdown_strings (snap_type_selector, snap_type_strings);
2970 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2972 snap_mode_selector.set_name ("SnapModeSelector");
2973 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2974 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2976 edit_point_selector.set_name ("EditPointSelector");
2977 set_popdown_strings (edit_point_selector, edit_point_strings);
2978 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2980 snap_box.pack_start (snap_mode_selector, false, false);
2981 snap_box.pack_start (snap_type_selector, false, false);
2982 snap_box.pack_start (edit_point_selector, false, false);
2986 HBox *nudge_box = manage (new HBox);
2987 nudge_box->set_spacing (2);
2988 nudge_box->set_border_width (2);
2990 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2991 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2993 nudge_box->pack_start (nudge_backward_button, false, false);
2994 nudge_box->pack_start (nudge_forward_button, false, false);
2995 nudge_box->pack_start (*nudge_clock, false, false);
2998 /* Pack everything in... */
3000 HBox* hbox = manage (new HBox);
3001 hbox->set_spacing(10);
3003 _tools_tearoff = manage (new TearOff (*hbox));
3004 _tools_tearoff->set_name ("MouseModeBase");
3005 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3007 if (Profile->get_sae()) {
3008 _tools_tearoff->set_can_be_torn_off (false);
3011 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3012 &_tools_tearoff->tearoff_window()));
3013 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3014 &_tools_tearoff->tearoff_window(), 0));
3015 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3016 &_tools_tearoff->tearoff_window()));
3017 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3018 &_tools_tearoff->tearoff_window(), 0));
3020 toolbar_hbox.set_spacing (10);
3021 toolbar_hbox.set_border_width (1);
3023 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3024 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3025 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3027 hbox->pack_start (snap_box, false, false);
3028 if (!Profile->get_small_screen()) {
3029 hbox->pack_start (*nudge_box, false, false);
3031 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3033 hbox->pack_start (panic_box, false, false);
3037 toolbar_base.set_name ("ToolBarBase");
3038 toolbar_base.add (toolbar_hbox);
3040 _toolbar_viewport.add (toolbar_base);
3041 /* stick to the required height but allow width to vary if there's not enough room */
3042 _toolbar_viewport.set_size_request (1, -1);
3044 toolbar_frame.set_shadow_type (SHADOW_OUT);
3045 toolbar_frame.set_name ("BaseFrame");
3046 toolbar_frame.add (_toolbar_viewport);
3050 Editor::setup_tooltips ()
3052 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3053 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3054 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3055 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3056 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3057 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3058 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3059 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3060 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3061 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3062 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3063 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3064 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3065 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3066 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3067 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3068 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3069 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3070 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3071 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3072 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3073 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3074 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3078 Editor::convert_drop_to_paths (
3079 vector<string>& paths,
3080 const RefPtr<Gdk::DragContext>& /*context*/,
3083 const SelectionData& data,
3087 if (_session == 0) {
3091 vector<string> uris = data.get_uris();
3095 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3096 are actually URI lists. So do it by hand.
3099 if (data.get_target() != "text/plain") {
3103 /* Parse the "uri-list" format that Nautilus provides,
3104 where each pathname is delimited by \r\n.
3106 THERE MAY BE NO NULL TERMINATING CHAR!!!
3109 string txt = data.get_text();
3113 p = (const char *) malloc (txt.length() + 1);
3114 txt.copy ((char *) p, txt.length(), 0);
3115 ((char*)p)[txt.length()] = '\0';
3121 while (g_ascii_isspace (*p))
3125 while (*q && (*q != '\n') && (*q != '\r')) {
3132 while (q > p && g_ascii_isspace (*q))
3137 uris.push_back (string (p, q - p + 1));
3141 p = strchr (p, '\n');
3153 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3155 if ((*i).substr (0,7) == "file://") {
3157 string const p = PBD::url_decode (*i);
3159 // scan forward past three slashes
3161 string::size_type slashcnt = 0;
3162 string::size_type n = 0;
3163 string::const_iterator x = p.begin();
3165 while (slashcnt < 3 && x != p.end()) {
3168 } else if (slashcnt == 3) {
3175 if (slashcnt != 3 || x == p.end()) {
3176 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3180 paths.push_back (p.substr (n - 1));
3188 Editor::new_tempo_section ()
3194 Editor::map_transport_state ()
3196 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3198 if (_session && _session->transport_stopped()) {
3199 have_pending_keyboard_selection = false;
3202 update_loop_range_view (true);
3208 Editor::begin_reversible_command (string name)
3211 _session->begin_reversible_command (name);
3216 Editor::begin_reversible_command (GQuark q)
3219 _session->begin_reversible_command (q);
3224 Editor::commit_reversible_command ()
3227 _session->commit_reversible_command ();
3232 Editor::history_changed ()
3236 if (undo_action && _session) {
3237 if (_session->undo_depth() == 0) {
3238 label = S_("Command|Undo");
3240 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3242 undo_action->property_label() = label;
3245 if (redo_action && _session) {
3246 if (_session->redo_depth() == 0) {
3249 label = string_compose(_("Redo (%1)"), _session->next_redo());
3251 redo_action->property_label() = label;
3256 Editor::duplicate_dialog (bool with_dialog)
3260 if (mouse_mode == MouseRange) {
3261 if (selection->time.length() == 0) {
3266 RegionSelection rs = get_regions_from_selection_and_entered ();
3268 if (mouse_mode != MouseRange && rs.empty()) {
3274 ArdourDialog win (_("Duplicate"));
3275 Label label (_("Number of duplications:"));
3276 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3277 SpinButton spinner (adjustment, 0.0, 1);
3280 win.get_vbox()->set_spacing (12);
3281 win.get_vbox()->pack_start (hbox);
3282 hbox.set_border_width (6);
3283 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3285 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3286 place, visually. so do this by hand.
3289 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3290 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3291 spinner.grab_focus();
3297 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3298 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3299 win.set_default_response (RESPONSE_ACCEPT);
3301 win.set_position (WIN_POS_MOUSE);
3303 spinner.grab_focus ();
3305 switch (win.run ()) {
3306 case RESPONSE_ACCEPT:
3312 times = adjustment.get_value();
3315 if (mouse_mode == MouseRange) {
3316 duplicate_selection (times);
3318 duplicate_some_regions (rs, times);
3323 Editor::set_edit_mode (EditMode m)
3325 Config->set_edit_mode (m);
3329 Editor::cycle_edit_mode ()
3331 switch (Config->get_edit_mode()) {
3333 if (Profile->get_sae()) {
3334 Config->set_edit_mode (Lock);
3336 Config->set_edit_mode (Splice);
3340 Config->set_edit_mode (Lock);
3343 Config->set_edit_mode (Slide);
3349 Editor::edit_mode_selection_done ()
3351 string s = edit_mode_selector.get_active_text ();
3354 Config->set_edit_mode (string_to_edit_mode (s));
3359 Editor::snap_type_selection_done ()
3361 string choice = snap_type_selector.get_active_text();
3362 SnapType snaptype = SnapToBeat;
3364 if (choice == _("Beats/2")) {
3365 snaptype = SnapToBeatDiv2;
3366 } else if (choice == _("Beats/3")) {
3367 snaptype = SnapToBeatDiv3;
3368 } else if (choice == _("Beats/4")) {
3369 snaptype = SnapToBeatDiv4;
3370 } else if (choice == _("Beats/5")) {
3371 snaptype = SnapToBeatDiv5;
3372 } else if (choice == _("Beats/6")) {
3373 snaptype = SnapToBeatDiv6;
3374 } else if (choice == _("Beats/7")) {
3375 snaptype = SnapToBeatDiv7;
3376 } else if (choice == _("Beats/8")) {
3377 snaptype = SnapToBeatDiv8;
3378 } else if (choice == _("Beats/10")) {
3379 snaptype = SnapToBeatDiv10;
3380 } else if (choice == _("Beats/12")) {
3381 snaptype = SnapToBeatDiv12;
3382 } else if (choice == _("Beats/14")) {
3383 snaptype = SnapToBeatDiv14;
3384 } else if (choice == _("Beats/16")) {
3385 snaptype = SnapToBeatDiv16;
3386 } else if (choice == _("Beats/20")) {
3387 snaptype = SnapToBeatDiv20;
3388 } else if (choice == _("Beats/24")) {
3389 snaptype = SnapToBeatDiv24;
3390 } else if (choice == _("Beats/28")) {
3391 snaptype = SnapToBeatDiv28;
3392 } else if (choice == _("Beats/32")) {
3393 snaptype = SnapToBeatDiv32;
3394 } else if (choice == _("Beats/64")) {
3395 snaptype = SnapToBeatDiv64;
3396 } else if (choice == _("Beats/128")) {
3397 snaptype = SnapToBeatDiv128;
3398 } else if (choice == _("Beats")) {
3399 snaptype = SnapToBeat;
3400 } else if (choice == _("Bars")) {
3401 snaptype = SnapToBar;
3402 } else if (choice == _("Marks")) {
3403 snaptype = SnapToMark;
3404 } else if (choice == _("Region starts")) {
3405 snaptype = SnapToRegionStart;
3406 } else if (choice == _("Region ends")) {
3407 snaptype = SnapToRegionEnd;
3408 } else if (choice == _("Region bounds")) {
3409 snaptype = SnapToRegionBoundary;
3410 } else if (choice == _("Region syncs")) {
3411 snaptype = SnapToRegionSync;
3412 } else if (choice == _("CD Frames")) {
3413 snaptype = SnapToCDFrame;
3414 } else if (choice == _("Timecode Frames")) {
3415 snaptype = SnapToTimecodeFrame;
3416 } else if (choice == _("Timecode Seconds")) {
3417 snaptype = SnapToTimecodeSeconds;
3418 } else if (choice == _("Timecode Minutes")) {
3419 snaptype = SnapToTimecodeMinutes;
3420 } else if (choice == _("Seconds")) {
3421 snaptype = SnapToSeconds;
3422 } else if (choice == _("Minutes")) {
3423 snaptype = SnapToMinutes;
3426 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3428 ract->set_active ();
3433 Editor::snap_mode_selection_done ()
3435 string choice = snap_mode_selector.get_active_text();
3436 SnapMode mode = SnapNormal;
3438 if (choice == _("No Grid")) {
3440 } else if (choice == _("Grid")) {
3442 } else if (choice == _("Magnetic")) {
3443 mode = SnapMagnetic;
3446 RefPtr<RadioAction> ract = snap_mode_action (mode);
3449 ract->set_active (true);
3454 Editor::cycle_edit_point (bool with_marker)
3456 switch (_edit_point) {
3458 set_edit_point_preference (EditAtPlayhead);
3460 case EditAtPlayhead:
3462 set_edit_point_preference (EditAtSelectedMarker);
3464 set_edit_point_preference (EditAtMouse);
3467 case EditAtSelectedMarker:
3468 set_edit_point_preference (EditAtMouse);
3474 Editor::edit_point_selection_done ()
3476 string choice = edit_point_selector.get_active_text();
3477 EditPoint ep = EditAtSelectedMarker;
3479 if (choice == _("Marker")) {
3480 set_edit_point_preference (EditAtSelectedMarker);
3481 } else if (choice == _("Playhead")) {
3482 set_edit_point_preference (EditAtPlayhead);
3484 set_edit_point_preference (EditAtMouse);
3487 RefPtr<RadioAction> ract = edit_point_action (ep);
3490 ract->set_active (true);
3495 Editor::zoom_focus_selection_done ()
3497 string choice = zoom_focus_selector.get_active_text();
3498 ZoomFocus focus_type = ZoomFocusLeft;
3500 if (choice == _("Left")) {
3501 focus_type = ZoomFocusLeft;
3502 } else if (choice == _("Right")) {
3503 focus_type = ZoomFocusRight;
3504 } else if (choice == _("Center")) {
3505 focus_type = ZoomFocusCenter;
3506 } else if (choice == _("Playhead")) {
3507 focus_type = ZoomFocusPlayhead;
3508 } else if (choice == _("Mouse")) {
3509 focus_type = ZoomFocusMouse;
3510 } else if (choice == _("Edit point")) {
3511 focus_type = ZoomFocusEdit;
3514 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3517 ract->set_active ();
3522 Editor::edit_controls_button_release (GdkEventButton* ev)
3524 if (Keyboard::is_context_menu_event (ev)) {
3525 ARDOUR_UI::instance()->add_route (this);
3526 } else if (ev->button == 1) {
3527 selection->clear_tracks ();
3534 Editor::mouse_select_button_release (GdkEventButton* ev)
3536 /* this handles just right-clicks */
3538 if (ev->button != 3) {
3546 Editor::set_zoom_focus (ZoomFocus f)
3548 string str = zoom_focus_strings[(int)f];
3550 if (str != zoom_focus_selector.get_active_text()) {
3551 zoom_focus_selector.set_active_text (str);
3554 if (zoom_focus != f) {
3561 Editor::ensure_float (Window& win)
3563 win.set_transient_for (*this);
3567 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3569 /* recover or initialize pane positions. do this here rather than earlier because
3570 we don't want the positions to change the child allocations, which they seem to do.
3576 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3585 XMLNode* geometry = find_named_node (*node, "geometry");
3587 if (which == static_cast<Paned*> (&edit_pane)) {
3589 if (done & Horizontal) {
3593 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3594 _notebook_shrunk = string_is_affirmative (prop->value ());
3597 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3598 /* initial allocation is 90% to canvas, 10% to notebook */
3599 pos = (int) floor (alloc.get_width() * 0.90f);
3600 snprintf (buf, sizeof(buf), "%d", pos);
3602 pos = atoi (prop->value());
3605 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3606 edit_pane.set_position (pos);
3609 done = (Pane) (done | Horizontal);
3611 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3613 if (done & Vertical) {
3617 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3618 /* initial allocation is 90% to canvas, 10% to summary */
3619 pos = (int) floor (alloc.get_height() * 0.90f);
3620 snprintf (buf, sizeof(buf), "%d", pos);
3623 pos = atoi (prop->value());
3626 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3627 editor_summary_pane.set_position (pos);
3630 done = (Pane) (done | Vertical);
3635 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3637 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3638 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3639 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3640 top_hbox.remove (toolbar_frame);
3645 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3647 if (toolbar_frame.get_parent() == 0) {
3648 top_hbox.pack_end (toolbar_frame);
3653 Editor::set_show_measures (bool yn)
3655 if (_show_measures != yn) {
3658 if ((_show_measures = yn) == true) {
3660 tempo_lines->show();
3668 Editor::toggle_follow_playhead ()
3670 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3672 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3673 set_follow_playhead (tact->get_active());
3677 /** @param yn true to follow playhead, otherwise false.
3678 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3681 Editor::set_follow_playhead (bool yn, bool catch_up)
3683 if (_follow_playhead != yn) {
3684 if ((_follow_playhead = yn) == true && catch_up) {
3686 reset_x_origin_to_follow_playhead ();
3693 Editor::toggle_stationary_playhead ()
3695 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3697 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3698 set_stationary_playhead (tact->get_active());
3703 Editor::set_stationary_playhead (bool yn)
3705 if (_stationary_playhead != yn) {
3706 if ((_stationary_playhead = yn) == true) {
3708 // FIXME need a 3.0 equivalent of this 2.X call
3709 // update_current_screen ();
3716 Editor::playlist_selector () const
3718 return *_playlist_selector;
3722 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3726 switch (_snap_type) {
3731 case SnapToBeatDiv128:
3734 case SnapToBeatDiv64:
3737 case SnapToBeatDiv32:
3740 case SnapToBeatDiv28:
3743 case SnapToBeatDiv24:
3746 case SnapToBeatDiv20:
3749 case SnapToBeatDiv16:
3752 case SnapToBeatDiv14:
3755 case SnapToBeatDiv12:
3758 case SnapToBeatDiv10:
3761 case SnapToBeatDiv8:
3764 case SnapToBeatDiv7:
3767 case SnapToBeatDiv6:
3770 case SnapToBeatDiv5:
3773 case SnapToBeatDiv4:
3776 case SnapToBeatDiv3:
3779 case SnapToBeatDiv2:
3785 return _session->tempo_map().meter_at (position).divisions_per_bar();
3790 case SnapToTimecodeFrame:
3791 case SnapToTimecodeSeconds:
3792 case SnapToTimecodeMinutes:
3795 case SnapToRegionStart:
3796 case SnapToRegionEnd:
3797 case SnapToRegionSync:
3798 case SnapToRegionBoundary:
3808 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3812 ret = nudge_clock->current_duration (pos);
3813 next = ret + 1; /* XXXX fix me */
3819 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3821 ArdourDialog dialog (_("Playlist Deletion"));
3822 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3823 "If it is kept, its audio files will not be cleaned.\n"
3824 "If it is deleted, audio files used by it alone will be cleaned."),
3827 dialog.set_position (WIN_POS_CENTER);
3828 dialog.get_vbox()->pack_start (label);
3832 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3833 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3834 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3836 switch (dialog.run ()) {
3837 case RESPONSE_ACCEPT:
3838 /* delete the playlist */
3842 case RESPONSE_REJECT:
3843 /* keep the playlist */
3855 Editor::audio_region_selection_covers (framepos_t where)
3857 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3858 if ((*a)->region()->covers (where)) {
3867 Editor::prepare_for_cleanup ()
3869 cut_buffer->clear_regions ();
3870 cut_buffer->clear_playlists ();
3872 selection->clear_regions ();
3873 selection->clear_playlists ();
3875 _regions->suspend_redisplay ();
3879 Editor::finish_cleanup ()
3881 _regions->resume_redisplay ();
3885 Editor::transport_loop_location()
3888 return _session->locations()->auto_loop_location();
3895 Editor::transport_punch_location()
3898 return _session->locations()->auto_punch_location();
3905 Editor::control_layout_scroll (GdkEventScroll* ev)
3907 if (Keyboard::some_magic_widget_has_focus()) {
3911 switch (ev->direction) {
3913 scroll_tracks_up_line ();
3917 case GDK_SCROLL_DOWN:
3918 scroll_tracks_down_line ();
3922 /* no left/right handling yet */
3930 Editor::session_state_saved (string)
3933 _snapshots->redisplay ();
3937 Editor::maximise_editing_space ()
3945 if (!Config->get_keep_tearoffs()) {
3946 /* these calls will leave each tearoff visible *if* it is torn off,
3947 but invisible otherwise.
3949 _mouse_mode_tearoff->set_visible (false);
3950 _tools_tearoff->set_visible (false);
3951 _zoom_tearoff->set_visible (false);
3958 Editor::restore_editing_space ()
3966 if (!Config->get_keep_tearoffs()) {
3967 _mouse_mode_tearoff->set_visible (true);
3968 _tools_tearoff->set_visible (true);
3969 _zoom_tearoff->set_visible (true);
3976 * Make new playlists for a given track and also any others that belong
3977 * to the same active route group with the `edit' property.
3982 Editor::new_playlists (TimeAxisView* v)
3984 begin_reversible_command (_("new playlists"));
3985 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3986 _session->playlists->get (playlists);
3987 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3988 commit_reversible_command ();
3992 * Use a copy of the current playlist for a given track and also any others that belong
3993 * to the same active route group with the `edit' property.
3998 Editor::copy_playlists (TimeAxisView* v)
4000 begin_reversible_command (_("copy playlists"));
4001 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4002 _session->playlists->get (playlists);
4003 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4004 commit_reversible_command ();
4007 /** Clear the current playlist for a given track and also any others that belong
4008 * to the same active route group with the `edit' property.
4013 Editor::clear_playlists (TimeAxisView* v)
4015 begin_reversible_command (_("clear playlists"));
4016 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4017 _session->playlists->get (playlists);
4018 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4019 commit_reversible_command ();
4023 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4025 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4029 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4031 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4035 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4037 atv.clear_playlist ();
4041 Editor::on_key_press_event (GdkEventKey* ev)
4043 return key_press_focus_accelerator_handler (*this, ev);
4047 Editor::on_key_release_event (GdkEventKey* ev)
4049 return Gtk::Window::on_key_release_event (ev);
4050 // return key_press_focus_accelerator_handler (*this, ev);
4053 /** Queue up a change to the viewport x origin.
4054 * @param frame New x origin.
4057 Editor::reset_x_origin (framepos_t frame)
4059 queue_visual_change (frame);
4063 Editor::reset_y_origin (double y)
4065 queue_visual_change_y (y);
4069 Editor::reset_zoom (double fpu)
4071 queue_visual_change (fpu);
4075 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4077 reset_x_origin (frame);
4080 if (!no_save_visual) {
4081 undo_visual_stack.push_back (current_visual_state(false));
4085 Editor::VisualState::VisualState (bool with_tracks)
4086 : gui_state (with_tracks ? new GUIObjectState : 0)
4090 Editor::VisualState::~VisualState ()
4095 Editor::VisualState*
4096 Editor::current_visual_state (bool with_tracks)
4098 VisualState* vs = new VisualState (with_tracks);
4099 vs->y_position = vertical_adjustment.get_value();
4100 vs->frames_per_unit = frames_per_unit;
4101 vs->leftmost_frame = leftmost_frame;
4102 vs->zoom_focus = zoom_focus;
4105 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4112 Editor::undo_visual_state ()
4114 if (undo_visual_stack.empty()) {
4118 VisualState* vs = undo_visual_stack.back();
4119 undo_visual_stack.pop_back();
4122 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4124 use_visual_state (*vs);
4128 Editor::redo_visual_state ()
4130 if (redo_visual_stack.empty()) {
4134 VisualState* vs = redo_visual_stack.back();
4135 redo_visual_stack.pop_back();
4137 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4139 use_visual_state (*vs);
4143 Editor::swap_visual_state ()
4145 if (undo_visual_stack.empty()) {
4146 redo_visual_state ();
4148 undo_visual_state ();
4153 Editor::use_visual_state (VisualState& vs)
4155 PBD::Unwinder<bool> nsv (no_save_visual, true);
4157 _routes->suspend_redisplay ();
4159 vertical_adjustment.set_value (vs.y_position);
4161 set_zoom_focus (vs.zoom_focus);
4162 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4165 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4167 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4168 (*i)->reset_visual_state ();
4172 _routes->update_visibility ();
4173 _routes->resume_redisplay ();
4177 Editor::set_frames_per_unit (double fpu)
4179 /* this is the core function that controls the zoom level of the canvas. it is called
4180 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4183 if (fpu == frames_per_unit) {
4192 /* don't allow zooms that fit more than the maximum number
4193 of frames into an 800 pixel wide space.
4196 if (max_framepos / fpu < 800.0) {
4201 tempo_lines->tempo_map_changed();
4203 frames_per_unit = fpu;
4208 Editor::post_zoom ()
4210 // convert fpu to frame count
4212 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4214 if (frames_per_unit != zoom_range_clock->current_duration()) {
4215 zoom_range_clock->set (frames);
4218 bool const showing_time_selection =
4219 mouse_mode == MouseRange ||
4220 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4222 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4223 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4224 (*i)->reshow_selection (selection->time);
4228 ZoomChanged (); /* EMIT_SIGNAL */
4230 //reset_scrolling_region ();
4232 if (playhead_cursor) {
4233 playhead_cursor->set_position (playhead_cursor->current_frame);
4236 refresh_location_display();
4237 _summary->set_overlays_dirty ();
4239 update_marker_labels ();
4245 Editor::queue_visual_change (framepos_t where)
4247 pending_visual_change.add (VisualChange::TimeOrigin);
4248 pending_visual_change.time_origin = where;
4249 ensure_visual_change_idle_handler ();
4253 Editor::queue_visual_change (double fpu)
4255 pending_visual_change.add (VisualChange::ZoomLevel);
4256 pending_visual_change.frames_per_unit = fpu;
4258 ensure_visual_change_idle_handler ();
4262 Editor::queue_visual_change_y (double y)
4264 pending_visual_change.add (VisualChange::YOrigin);
4265 pending_visual_change.y_origin = y;
4267 ensure_visual_change_idle_handler ();
4271 Editor::ensure_visual_change_idle_handler ()
4273 if (pending_visual_change.idle_handler_id < 0) {
4274 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4279 Editor::_idle_visual_changer (void* arg)
4281 return static_cast<Editor*>(arg)->idle_visual_changer ();
4285 Editor::idle_visual_changer ()
4287 VisualChange::Type p = pending_visual_change.pending;
4288 pending_visual_change.pending = (VisualChange::Type) 0;
4290 double const last_time_origin = horizontal_position ();
4292 if (p & VisualChange::ZoomLevel) {
4293 set_frames_per_unit (pending_visual_change.frames_per_unit);
4295 compute_fixed_ruler_scale ();
4296 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4297 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4298 update_tempo_based_rulers ();
4300 if (p & VisualChange::TimeOrigin) {
4301 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4303 if (p & VisualChange::YOrigin) {
4304 vertical_adjustment.set_value (pending_visual_change.y_origin);
4307 if (last_time_origin == horizontal_position ()) {
4308 /* changed signal not emitted */
4309 update_fixed_rulers ();
4310 redisplay_tempo (true);
4313 _summary->set_overlays_dirty ();
4315 pending_visual_change.idle_handler_id = -1;
4316 return 0; /* this is always a one-shot call */
4319 struct EditorOrderTimeAxisSorter {
4320 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4321 return a->order () < b->order ();
4326 Editor::sort_track_selection (TrackViewList& sel)
4328 EditorOrderTimeAxisSorter cmp;
4333 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4336 framepos_t where = 0;
4337 EditPoint ep = _edit_point;
4339 if (from_context_menu && (ep == EditAtMouse)) {
4340 return event_frame (&context_click_event, 0, 0);
4343 if (entered_marker) {
4344 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4345 return entered_marker->position();
4348 if (ignore_playhead && ep == EditAtPlayhead) {
4349 ep = EditAtSelectedMarker;
4353 case EditAtPlayhead:
4354 where = _session->audible_frame();
4355 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4358 case EditAtSelectedMarker:
4359 if (!selection->markers.empty()) {
4361 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4364 where = loc->start();
4368 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4376 if (!mouse_frame (where, ignored)) {
4377 /* XXX not right but what can we do ? */
4381 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4389 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4391 if (!_session) return;
4393 begin_reversible_command (cmd);
4397 if ((tll = transport_loop_location()) == 0) {
4398 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4399 XMLNode &before = _session->locations()->get_state();
4400 _session->locations()->add (loc, true);
4401 _session->set_auto_loop_location (loc);
4402 XMLNode &after = _session->locations()->get_state();
4403 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4405 XMLNode &before = tll->get_state();
4406 tll->set_hidden (false, this);
4407 tll->set (start, end);
4408 XMLNode &after = tll->get_state();
4409 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4412 commit_reversible_command ();
4416 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4418 if (!_session) return;
4420 begin_reversible_command (cmd);
4424 if ((tpl = transport_punch_location()) == 0) {
4425 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4426 XMLNode &before = _session->locations()->get_state();
4427 _session->locations()->add (loc, true);
4428 _session->set_auto_loop_location (loc);
4429 XMLNode &after = _session->locations()->get_state();
4430 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4433 XMLNode &before = tpl->get_state();
4434 tpl->set_hidden (false, this);
4435 tpl->set (start, end);
4436 XMLNode &after = tpl->get_state();
4437 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4440 commit_reversible_command ();
4443 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4444 * @param rs List to which found regions are added.
4445 * @param where Time to look at.
4446 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4449 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4451 const TrackViewList* tracks;
4454 tracks = &track_views;
4459 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4461 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4464 boost::shared_ptr<Track> tr;
4465 boost::shared_ptr<Playlist> pl;
4467 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4469 boost::shared_ptr<RegionList> regions = pl->regions_at (
4470 (framepos_t) floor ( (double) where * tr->speed()));
4472 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4473 RegionView* rv = rtv->view()->find_view (*i);
4484 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4486 const TrackViewList* tracks;
4489 tracks = &track_views;
4494 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4495 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4497 boost::shared_ptr<Track> tr;
4498 boost::shared_ptr<Playlist> pl;
4500 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4502 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4503 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4505 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4507 RegionView* rv = rtv->view()->find_view (*i);
4518 /** Start with regions that are selected. Then add equivalent regions
4519 * on tracks in the same active edit-enabled route group as any of
4520 * the regions that we started with.
4524 Editor::get_regions_from_selection ()
4526 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4529 /** Get regions using the following method:
4531 * Make an initial region list using the selected regions, unless
4532 * the edit point is `mouse' and the mouse is over an unselected
4533 * region. In this case, start with just that region.
4535 * Then, make an initial track list of the tracks that these
4536 * regions are on, and if the edit point is not `mouse', add the
4539 * Look at this track list and add any other tracks that are on the
4540 * same active edit-enabled route group as one of the initial tracks.
4542 * Finally take the initial region list and add any regions that are
4543 * under the edit point on one of the tracks on the track list to get
4544 * the returned region list.
4546 * The rationale here is that the mouse edit point is special in that
4547 * its position describes both a time and a track; the other edit
4548 * modes only describe a time. Hence if the edit point is `mouse' we
4549 * ignore selected tracks, as we assume the user means something by
4550 * pointing at a particular track. Also in this case we take note of
4551 * the region directly under the edit point, as there is always just one
4552 * (rather than possibly several with non-mouse edit points).
4556 Editor::get_regions_from_selection_and_edit_point ()
4558 RegionSelection regions;
4560 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4561 regions.add (entered_regionview);
4563 regions = selection->regions;
4566 TrackViewList tracks;
4568 if (_edit_point != EditAtMouse) {
4569 tracks = selection->tracks;
4572 /* Add any other tracks that have regions that are in the same
4573 edit-activated route group as one of our regions.
4575 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4577 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4579 if (g && g->is_active() && g->is_edit()) {
4580 tracks.add (axis_views_from_routes (g->route_list()));
4584 if (!tracks.empty()) {
4585 /* now find regions that are at the edit position on those tracks */
4586 framepos_t const where = get_preferred_edit_position ();
4587 get_regions_at (regions, where, tracks);
4593 /** Start with regions that are selected, or the entered regionview if none are selected.
4594 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4595 * of the regions that we started with.
4599 Editor::get_regions_from_selection_and_entered ()
4601 RegionSelection regions = selection->regions;
4603 if (regions.empty() && entered_regionview) {
4604 regions.add (entered_regionview);
4607 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4611 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4613 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4615 RouteTimeAxisView* tatv;
4617 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4619 boost::shared_ptr<Playlist> pl;
4620 vector<boost::shared_ptr<Region> > results;
4622 boost::shared_ptr<Track> tr;
4624 if ((tr = tatv->track()) == 0) {
4629 if ((pl = (tr->playlist())) != 0) {
4630 pl->get_region_list_equivalent_regions (region, results);
4633 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4634 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4635 regions.push_back (marv);
4644 Editor::show_rhythm_ferret ()
4646 if (rhythm_ferret == 0) {
4647 rhythm_ferret = new RhythmFerret(*this);
4650 rhythm_ferret->set_session (_session);
4651 rhythm_ferret->show ();
4652 rhythm_ferret->present ();
4656 Editor::first_idle ()
4658 MessageDialog* dialog = 0;
4660 if (track_views.size() > 1) {
4661 dialog = new MessageDialog (
4663 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4667 ARDOUR_UI::instance()->flush_pending ();
4670 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4674 // first idle adds route children (automation tracks), so we need to redisplay here
4675 _routes->redisplay ();
4682 Editor::_idle_resize (gpointer arg)
4684 return ((Editor*)arg)->idle_resize ();
4688 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4690 if (resize_idle_id < 0) {
4691 resize_idle_id = g_idle_add (_idle_resize, this);
4692 _pending_resize_amount = 0;
4695 /* make a note of the smallest resulting height, so that we can clamp the
4696 lower limit at TimeAxisView::hSmall */
4698 int32_t min_resulting = INT32_MAX;
4700 _pending_resize_amount += h;
4701 _pending_resize_view = view;
4703 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4705 if (selection->tracks.contains (_pending_resize_view)) {
4706 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4707 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4711 if (min_resulting < 0) {
4716 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4717 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4721 /** Handle pending resizing of tracks */
4723 Editor::idle_resize ()
4725 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4727 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4728 selection->tracks.contains (_pending_resize_view)) {
4730 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4731 if (*i != _pending_resize_view) {
4732 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4737 _pending_resize_amount = 0;
4739 _group_tabs->set_dirty ();
4740 resize_idle_id = -1;
4748 ENSURE_GUI_THREAD (*this, &Editor::located);
4750 playhead_cursor->set_position (_session->audible_frame ());
4751 if (_follow_playhead && !_pending_initial_locate) {
4752 reset_x_origin_to_follow_playhead ();
4755 _pending_locate_request = false;
4756 _pending_initial_locate = false;
4760 Editor::region_view_added (RegionView *)
4762 _summary->set_dirty ();
4766 Editor::region_view_removed ()
4768 _summary->set_dirty ();
4772 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4774 TrackViewList::const_iterator j = track_views.begin ();
4775 while (j != track_views.end()) {
4776 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4777 if (rtv && rtv->route() == r) {
4788 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4792 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4793 TimeAxisView* tv = axis_view_from_route (*i);
4804 Editor::handle_new_route (RouteList& routes)
4806 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4808 RouteTimeAxisView *rtv;
4809 list<RouteTimeAxisView*> new_views;
4811 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4812 boost::shared_ptr<Route> route = (*x);
4814 if (route->is_hidden() || route->is_monitor()) {
4818 DataType dt = route->input()->default_type();
4820 if (dt == ARDOUR::DataType::AUDIO) {
4821 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4822 rtv->set_route (route);
4823 } else if (dt == ARDOUR::DataType::MIDI) {
4824 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4825 rtv->set_route (route);
4827 throw unknown_type();
4830 new_views.push_back (rtv);
4831 track_views.push_back (rtv);
4833 rtv->effective_gain_display ();
4835 if (internal_editing()) {
4836 rtv->enter_internal_edit_mode ();
4838 rtv->leave_internal_edit_mode ();
4841 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4842 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4845 _routes->routes_added (new_views);
4846 _summary->routes_added (new_views);
4848 if (show_editor_mixer_when_tracks_arrive) {
4849 show_editor_mixer (true);
4852 editor_list_button.set_sensitive (true);
4856 Editor::timeaxisview_deleted (TimeAxisView *tv)
4858 if (_session && _session->deletion_in_progress()) {
4859 /* the situation is under control */
4863 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4865 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4867 _routes->route_removed (tv);
4869 if (tv == entered_track) {
4873 TimeAxisView::Children c = tv->get_child_list ();
4874 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4875 if (entered_track == i->get()) {
4880 /* remove it from the list of track views */
4882 TrackViewList::iterator i;
4884 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4885 i = track_views.erase (i);
4888 /* update whatever the current mixer strip is displaying, if revelant */
4890 boost::shared_ptr<Route> route;
4893 route = rtav->route ();
4896 if (current_mixer_strip && current_mixer_strip->route() == route) {
4898 TimeAxisView* next_tv;
4900 if (track_views.empty()) {
4902 } else if (i == track_views.end()) {
4903 next_tv = track_views.front();
4910 set_selected_mixer_strip (*next_tv);
4912 /* make the editor mixer strip go away setting the
4913 * button to inactive (which also unticks the menu option)
4916 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4922 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4924 if (apply_to_selection) {
4925 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4927 TrackSelection::iterator j = i;
4930 hide_track_in_display (*i, false);
4935 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4937 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4938 // this will hide the mixer strip
4939 set_selected_mixer_strip (*tv);
4942 _routes->hide_track_in_display (*tv);
4947 Editor::sync_track_view_list_and_routes ()
4949 track_views = TrackViewList (_routes->views ());
4951 _summary->set_dirty ();
4952 _group_tabs->set_dirty ();
4954 return false; // do not call again (until needed)
4958 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4960 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4965 /** Find a RouteTimeAxisView by the ID of its route */
4967 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4969 RouteTimeAxisView* v;
4971 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4972 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4973 if(v->route()->id() == id) {
4983 Editor::fit_route_group (RouteGroup *g)
4985 TrackViewList ts = axis_views_from_routes (g->route_list ());
4990 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4992 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4995 _session->cancel_audition ();
4999 if (_session->is_auditioning()) {
5000 _session->cancel_audition ();
5001 if (r == last_audition_region) {
5006 _session->audition_region (r);
5007 last_audition_region = r;
5012 Editor::hide_a_region (boost::shared_ptr<Region> r)
5014 r->set_hidden (true);
5018 Editor::show_a_region (boost::shared_ptr<Region> r)
5020 r->set_hidden (false);
5024 Editor::audition_region_from_region_list ()
5026 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5030 Editor::hide_region_from_region_list ()
5032 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5036 Editor::show_region_in_region_list ()
5038 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5042 Editor::step_edit_status_change (bool yn)
5045 start_step_editing ();
5047 stop_step_editing ();
5052 Editor::start_step_editing ()
5054 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5058 Editor::stop_step_editing ()
5060 step_edit_connection.disconnect ();
5064 Editor::check_step_edit ()
5066 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5067 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5069 mtv->check_step_edit ();
5073 return true; // do it again, till we stop
5077 Editor::scroll_press (Direction dir)
5079 ++_scroll_callbacks;
5081 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5082 /* delay the first auto-repeat */
5088 scroll_backward (1);
5096 scroll_tracks_up_line ();
5100 scroll_tracks_down_line ();
5104 /* do hacky auto-repeat */
5105 if (!_scroll_connection.connected ()) {
5107 _scroll_connection = Glib::signal_timeout().connect (
5108 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5111 _scroll_callbacks = 0;
5118 Editor::scroll_release ()
5120 _scroll_connection.disconnect ();
5123 /** Queue a change for the Editor viewport x origin to follow the playhead */
5125 Editor::reset_x_origin_to_follow_playhead ()
5127 framepos_t const frame = playhead_cursor->current_frame;
5129 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5131 if (_session->transport_speed() < 0) {
5133 if (frame > (current_page_frames() / 2)) {
5134 center_screen (frame-(current_page_frames()/2));
5136 center_screen (current_page_frames()/2);
5143 if (frame < leftmost_frame) {
5145 if (_session->transport_rolling()) {
5146 /* rolling; end up with the playhead at the right of the page */
5147 l = frame - current_page_frames ();
5149 /* not rolling: end up with the playhead 1/4 of the way along the page */
5150 l = frame - current_page_frames() / 4;
5154 if (_session->transport_rolling()) {
5155 /* rolling: end up with the playhead on the left of the page */
5158 /* not rolling: end up with the playhead 3/4 of the way along the page */
5159 l = frame - 3 * current_page_frames() / 4;
5167 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5173 Editor::super_rapid_screen_update ()
5175 if (!_session || !_session->engine().running()) {
5179 /* METERING / MIXER STRIPS */
5181 /* update track meters, if required */
5182 if (is_mapped() && meters_running) {
5183 RouteTimeAxisView* rtv;
5184 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5185 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5186 rtv->fast_update ();
5191 /* and any current mixer strip */
5192 if (current_mixer_strip) {
5193 current_mixer_strip->fast_update ();
5196 /* PLAYHEAD AND VIEWPORT */
5198 framepos_t const frame = _session->audible_frame();
5200 /* There are a few reasons why we might not update the playhead / viewport stuff:
5202 * 1. we don't update things when there's a pending locate request, otherwise
5203 * when the editor requests a locate there is a chance that this method
5204 * will move the playhead before the locate request is processed, causing
5206 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5207 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5210 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5212 last_update_frame = frame;
5214 if (!_dragging_playhead) {
5215 playhead_cursor->set_position (frame);
5218 if (!_stationary_playhead) {
5220 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5221 reset_x_origin_to_follow_playhead ();
5226 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5230 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5231 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5232 if (target <= 0.0) {
5235 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5236 target = (target * 0.15) + (current * 0.85);
5242 set_horizontal_position (current);
5251 Editor::session_going_away ()
5253 _have_idled = false;
5255 _session_connections.drop_connections ();
5257 super_rapid_screen_update_connection.disconnect ();
5259 selection->clear ();
5260 cut_buffer->clear ();
5262 clicked_regionview = 0;
5263 clicked_axisview = 0;
5264 clicked_routeview = 0;
5265 entered_regionview = 0;
5267 last_update_frame = 0;
5270 playhead_cursor->canvas_item.hide ();
5272 /* rip everything out of the list displays */
5276 _route_groups->clear ();
5278 /* do this first so that deleting a track doesn't reset cms to null
5279 and thus cause a leak.
5282 if (current_mixer_strip) {
5283 if (current_mixer_strip->get_parent() != 0) {
5284 global_hpacker.remove (*current_mixer_strip);
5286 delete current_mixer_strip;
5287 current_mixer_strip = 0;
5290 /* delete all trackviews */
5292 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5295 track_views.clear ();
5297 zoom_range_clock->set_session (0);
5298 nudge_clock->set_session (0);
5300 editor_list_button.set_active(false);
5301 editor_list_button.set_sensitive(false);
5303 /* clear tempo/meter rulers */
5304 remove_metric_marks ();
5306 clear_marker_display ();
5308 current_bbt_points_begin = current_bbt_points_end;
5310 /* get rid of any existing editor mixer strip */
5312 WindowTitle title(Glib::get_application_name());
5313 title += _("Editor");
5315 set_title (title.get_string());
5317 SessionHandlePtr::session_going_away ();
5322 Editor::show_editor_list (bool yn)
5325 _the_notebook.show ();
5327 _the_notebook.hide ();
5332 Editor::change_region_layering_order (bool from_context_menu)
5334 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5336 if (!clicked_routeview) {
5337 if (layering_order_editor) {
5338 layering_order_editor->hide ();
5343 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5349 boost::shared_ptr<Playlist> pl = track->playlist();
5355 if (layering_order_editor == 0) {
5356 layering_order_editor = new RegionLayeringOrderEditor (*this);
5357 layering_order_editor->set_position (WIN_POS_MOUSE);
5360 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5361 layering_order_editor->maybe_present ();
5365 Editor::update_region_layering_order_editor ()
5367 if (layering_order_editor && layering_order_editor->is_visible ()) {
5368 change_region_layering_order (true);
5373 Editor::setup_fade_images ()
5375 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5376 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5377 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5378 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5379 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5381 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5382 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5383 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5384 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5385 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5387 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5388 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5389 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5390 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5391 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5393 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5394 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5395 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5396 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5397 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5401 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5403 Editor::action_menu_item (std::string const & name)
5405 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5408 return *manage (a->create_menu_item ());
5412 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5414 EventBox* b = manage (new EventBox);
5415 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5416 Label* l = manage (new Label (name));
5420 _the_notebook.append_page (widget, *b);
5424 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5426 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5427 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5430 if (ev->type == GDK_2BUTTON_PRESS) {
5432 /* double-click on a notebook tab shrinks or expands the notebook */
5434 if (_notebook_shrunk) {
5435 if (pre_notebook_shrink_pane_width) {
5436 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5438 _notebook_shrunk = false;
5440 pre_notebook_shrink_pane_width = edit_pane.get_position();
5442 /* this expands the LHS of the edit pane to cover the notebook
5443 PAGE but leaves the tabs visible.
5445 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5446 _notebook_shrunk = true;
5454 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5456 using namespace Menu_Helpers;
5458 MenuList& items = _control_point_context_menu.items ();
5461 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5462 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5463 if (!can_remove_control_point (item)) {
5464 items.back().set_sensitive (false);
5467 _control_point_context_menu.popup (event->button.button, event->button.time);