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 cerr << "new empty Button node\n";
790 node = new XMLNode (X_("Buttons"));
797 Editor::add_toplevel_controls (Container& cont)
799 vpacker.pack_start (cont, false, false);
804 Editor::catch_vanishing_regionview (RegionView *rv)
806 /* note: the selection will take care of the vanishing
807 audioregionview by itself.
810 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
814 if (clicked_regionview == rv) {
815 clicked_regionview = 0;
818 if (entered_regionview == rv) {
819 set_entered_regionview (0);
822 if (!_all_region_actions_sensitized) {
823 sensitize_all_region_actions (true);
826 _over_region_trim_target = false;
830 Editor::set_entered_regionview (RegionView* rv)
832 if (rv == entered_regionview) {
836 if (entered_regionview) {
837 entered_regionview->exited ();
840 if ((entered_regionview = rv) != 0) {
841 entered_regionview->entered (internal_editing ());
844 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
845 /* This RegionView entry might have changed what region actions
846 are allowed, so sensitize them all in case a key is pressed.
848 sensitize_all_region_actions (true);
853 Editor::set_entered_track (TimeAxisView* tav)
856 entered_track->exited ();
859 if ((entered_track = tav) != 0) {
860 entered_track->entered ();
865 Editor::show_window ()
867 if (!is_visible ()) {
870 /* XXX: this is a bit unfortunate; it would probably
871 be nicer if we could just call show () above rather
872 than needing the show_all ()
875 /* re-hide stuff if necessary */
876 editor_list_button_toggled ();
877 parameter_changed ("show-summary");
878 parameter_changed ("show-group-tabs");
879 parameter_changed ("show-zoom-tools");
881 /* now reset all audio_time_axis heights, because widgets might need
887 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
888 tv = (static_cast<TimeAxisView*>(*i));
892 if (current_mixer_strip) {
893 current_mixer_strip->hide_things ();
894 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
902 Editor::instant_save ()
904 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
909 _session->add_instant_xml(get_state());
911 Config->add_instant_xml(get_state());
916 Editor::zoom_adjustment_changed ()
922 double fpu = zoom_range_clock->current_duration() / _canvas_width;
926 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
927 } else if (fpu > _session->current_end_frame() / _canvas_width) {
928 fpu = _session->current_end_frame() / _canvas_width;
929 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
936 Editor::control_vertical_zoom_in_all ()
938 tav_zoom_smooth (false, true);
942 Editor::control_vertical_zoom_out_all ()
944 tav_zoom_smooth (true, true);
948 Editor::control_vertical_zoom_in_selected ()
950 tav_zoom_smooth (false, false);
954 Editor::control_vertical_zoom_out_selected ()
956 tav_zoom_smooth (true, false);
960 Editor::control_view (uint32_t view)
962 goto_visual_state (view);
966 Editor::control_unselect ()
968 selection->clear_tracks ();
972 Editor::control_select (uint32_t rid, Selection::Operation op)
974 /* handles the (static) signal from the ControlProtocol class that
975 * requests setting the selected track to a given RID
982 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
988 TimeAxisView* tav = axis_view_from_route (r);
993 selection->add (tav);
995 case Selection::Toggle:
996 selection->toggle (tav);
998 case Selection::Extend:
1000 case Selection::Set:
1001 selection->set (tav);
1005 selection->clear_tracks ();
1010 Editor::control_step_tracks_up ()
1012 scroll_tracks_up_line ();
1016 Editor::control_step_tracks_down ()
1018 scroll_tracks_down_line ();
1022 Editor::control_scroll (float fraction)
1024 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1030 double step = fraction * current_page_frames();
1033 _control_scroll_target is an optional<T>
1035 it acts like a pointer to an framepos_t, with
1036 a operator conversion to boolean to check
1037 that it has a value could possibly use
1038 playhead_cursor->current_frame to store the
1039 value and a boolean in the class to know
1040 when it's out of date
1043 if (!_control_scroll_target) {
1044 _control_scroll_target = _session->transport_frame();
1045 _dragging_playhead = true;
1048 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1049 *_control_scroll_target = 0;
1050 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1051 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1053 *_control_scroll_target += (framepos_t) floor (step);
1056 /* move visuals, we'll catch up with it later */
1058 playhead_cursor->set_position (*_control_scroll_target);
1059 UpdateAllTransportClocks (*_control_scroll_target);
1061 if (*_control_scroll_target > (current_page_frames() / 2)) {
1062 /* try to center PH in window */
1063 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1069 Now we do a timeout to actually bring the session to the right place
1070 according to the playhead. This is to avoid reading disk buffers on every
1071 call to control_scroll, which is driven by ScrollTimeline and therefore
1072 probably by a control surface wheel which can generate lots of events.
1074 /* cancel the existing timeout */
1076 control_scroll_connection.disconnect ();
1078 /* add the next timeout */
1080 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1084 Editor::deferred_control_scroll (framepos_t /*target*/)
1086 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1087 // reset for next stream
1088 _control_scroll_target = boost::none;
1089 _dragging_playhead = false;
1094 Editor::access_action (std::string action_group, std::string action_item)
1100 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1103 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1111 Editor::on_realize ()
1113 Window::on_realize ();
1118 Editor::map_position_change (framepos_t frame)
1120 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1122 if (_session == 0) {
1126 if (_follow_playhead) {
1127 center_screen (frame);
1130 playhead_cursor->set_position (frame);
1134 Editor::center_screen (framepos_t frame)
1136 double page = _canvas_width * frames_per_unit;
1138 /* if we're off the page, then scroll.
1141 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1142 center_screen_internal (frame, page);
1147 Editor::center_screen_internal (framepos_t frame, float page)
1152 frame -= (framepos_t) page;
1157 reset_x_origin (frame);
1162 Editor::update_title ()
1164 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1167 bool dirty = _session->dirty();
1169 string session_name;
1171 if (_session->snap_name() != _session->name()) {
1172 session_name = _session->snap_name();
1174 session_name = _session->name();
1178 session_name = "*" + session_name;
1181 WindowTitle title(session_name);
1182 title += Glib::get_application_name();
1183 set_title (title.get_string());
1188 Editor::set_session (Session *t)
1190 SessionHandlePtr::set_session (t);
1196 zoom_range_clock->set_session (_session);
1197 _playlist_selector->set_session (_session);
1198 nudge_clock->set_session (_session);
1199 _summary->set_session (_session);
1200 _group_tabs->set_session (_session);
1201 _route_groups->set_session (_session);
1202 _regions->set_session (_session);
1203 _snapshots->set_session (_session);
1204 _routes->set_session (_session);
1205 _locations->set_session (_session);
1207 if (rhythm_ferret) {
1208 rhythm_ferret->set_session (_session);
1211 if (analysis_window) {
1212 analysis_window->set_session (_session);
1216 sfbrowser->set_session (_session);
1219 compute_fixed_ruler_scale ();
1221 /* Make sure we have auto loop and auto punch ranges */
1223 Location* loc = _session->locations()->auto_loop_location();
1225 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1227 if (loc->start() == loc->end()) {
1228 loc->set_end (loc->start() + 1);
1231 _session->locations()->add (loc, false);
1232 _session->set_auto_loop_location (loc);
1235 loc->set_name (_("Loop"));
1238 loc = _session->locations()->auto_punch_location();
1241 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1243 if (loc->start() == loc->end()) {
1244 loc->set_end (loc->start() + 1);
1247 _session->locations()->add (loc, false);
1248 _session->set_auto_punch_location (loc);
1251 loc->set_name (_("Punch"));
1254 refresh_location_display ();
1256 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1257 the selected Marker; this needs the LocationMarker list to be available.
1259 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1260 set_state (*node, Stateful::loading_state_version);
1262 /* catch up with the playhead */
1264 _session->request_locate (playhead_cursor->current_frame);
1265 _pending_initial_locate = true;
1269 /* These signals can all be emitted by a non-GUI thread. Therefore the
1270 handlers for them must not attempt to directly interact with the GUI,
1271 but use Gtkmm2ext::UI::instance()->call_slot();
1274 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1275 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1276 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1277 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::handle_new_route, this, _1), gui_context());
1278 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1279 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1280 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1281 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1282 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1283 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1284 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1285 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1286 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1287 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1289 playhead_cursor->canvas_item.show ();
1291 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1292 Config->map_parameters (pc);
1293 _session->config.map_parameters (pc);
1295 restore_ruler_visibility ();
1296 //tempo_map_changed (PropertyChange (0));
1297 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1299 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1300 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1303 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1304 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1307 switch (_snap_type) {
1308 case SnapToRegionStart:
1309 case SnapToRegionEnd:
1310 case SnapToRegionSync:
1311 case SnapToRegionBoundary:
1312 build_region_boundary_cache ();
1319 /* register for undo history */
1320 _session->register_with_memento_command_factory(id(), this);
1322 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1324 start_updating_meters ();
1328 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1330 if (a->get_name() == "RegionMenu") {
1331 /* When the main menu's region menu is opened, we setup the actions so that they look right
1332 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1333 so we resensitize all region actions when the entered regionview or the region selection
1334 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1335 happens after the region context menu is opened. So we set a flag here, too.
1339 sensitize_the_right_region_actions ();
1340 _last_region_menu_was_main = true;
1345 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1347 using namespace Menu_Helpers;
1349 void (Editor::*emf)(FadeShape);
1350 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1353 images = &_xfade_in_images;
1354 emf = &Editor::set_fade_in_shape;
1356 images = &_xfade_out_images;
1357 emf = &Editor::set_fade_out_shape;
1362 _("Linear (for highly correlated material)"),
1363 *(*images)[FadeLinear],
1364 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1368 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1373 *(*images)[FadeConstantPower],
1374 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1377 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1382 *(*images)[FadeSymmetric],
1383 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1387 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1392 *(*images)[FadeSlow],
1393 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1396 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1401 *(*images)[FadeFast],
1402 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1405 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1408 /** Pop up a context menu for when the user clicks on a start crossfade */
1410 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1412 using namespace Menu_Helpers;
1414 MenuList& items (xfade_in_context_menu.items());
1416 if (items.empty()) {
1417 fill_xfade_menu (items, true);
1420 xfade_in_context_menu.popup (button, time);
1423 /** Pop up a context menu for when the user clicks on an end crossfade */
1425 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1427 using namespace Menu_Helpers;
1429 MenuList& items (xfade_out_context_menu.items());
1431 if (items.empty()) {
1432 fill_xfade_menu (items, false);
1435 xfade_out_context_menu.popup (button, time);
1439 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1441 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1443 using namespace Menu_Helpers;
1444 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1447 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1451 MenuList& items (fade_context_menu.items());
1454 switch (item_type) {
1456 case FadeInHandleItem:
1457 if (arv->audio_region()->fade_in_active()) {
1458 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1460 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1463 items.push_back (SeparatorElem());
1465 if (Profile->get_sae()) {
1467 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1468 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1475 *_fade_in_images[FadeLinear],
1476 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1480 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1485 *_fade_in_images[FadeSlow],
1486 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1489 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1494 *_fade_in_images[FadeFast],
1495 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1498 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1503 *_fade_in_images[FadeSymmetric],
1504 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1509 _("Constant Power"),
1510 *_fade_in_images[FadeConstantPower],
1511 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1514 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1520 case FadeOutHandleItem:
1521 if (arv->audio_region()->fade_out_active()) {
1522 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1524 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1527 items.push_back (SeparatorElem());
1529 if (Profile->get_sae()) {
1530 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1531 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1537 *_fade_out_images[FadeLinear],
1538 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1542 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1547 *_fade_out_images[FadeSlow],
1548 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1551 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1556 *_fade_out_images[FadeFast],
1557 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1560 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1565 *_fade_out_images[FadeSymmetric],
1566 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1571 _("Constant Power"),
1572 *_fade_out_images[FadeConstantPower],
1573 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1576 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1582 fatal << _("programming error: ")
1583 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1588 fade_context_menu.popup (button, time);
1592 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1594 using namespace Menu_Helpers;
1595 Menu* (Editor::*build_menu_function)();
1598 switch (item_type) {
1600 case RegionViewName:
1601 case RegionViewNameHighlight:
1602 case LeftFrameHandle:
1603 case RightFrameHandle:
1604 if (with_selection) {
1605 build_menu_function = &Editor::build_track_selection_context_menu;
1607 build_menu_function = &Editor::build_track_region_context_menu;
1612 if (with_selection) {
1613 build_menu_function = &Editor::build_track_selection_context_menu;
1615 build_menu_function = &Editor::build_track_context_menu;
1620 if (clicked_routeview->track()) {
1621 build_menu_function = &Editor::build_track_context_menu;
1623 build_menu_function = &Editor::build_track_bus_context_menu;
1628 /* probably shouldn't happen but if it does, we don't care */
1632 menu = (this->*build_menu_function)();
1633 menu->set_name ("ArdourContextMenu");
1635 /* now handle specific situations */
1637 switch (item_type) {
1639 case RegionViewName:
1640 case RegionViewNameHighlight:
1641 case LeftFrameHandle:
1642 case RightFrameHandle:
1643 if (!with_selection) {
1644 if (region_edit_menu_split_item) {
1645 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1646 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1648 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1651 if (region_edit_menu_split_multichannel_item) {
1652 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1653 region_edit_menu_split_multichannel_item->set_sensitive (true);
1655 region_edit_menu_split_multichannel_item->set_sensitive (false);
1668 /* probably shouldn't happen but if it does, we don't care */
1672 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1674 /* Bounce to disk */
1676 using namespace Menu_Helpers;
1677 MenuList& edit_items = menu->items();
1679 edit_items.push_back (SeparatorElem());
1681 switch (clicked_routeview->audio_track()->freeze_state()) {
1682 case AudioTrack::NoFreeze:
1683 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1686 case AudioTrack::Frozen:
1687 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1690 case AudioTrack::UnFrozen:
1691 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1697 if (item_type == StreamItem && clicked_routeview) {
1698 clicked_routeview->build_underlay_menu(menu);
1701 /* When the region menu is opened, we setup the actions so that they look right
1704 sensitize_the_right_region_actions ();
1705 _last_region_menu_was_main = false;
1707 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1708 menu->popup (button, time);
1712 Editor::build_track_context_menu ()
1714 using namespace Menu_Helpers;
1716 MenuList& edit_items = track_context_menu.items();
1719 add_dstream_context_items (edit_items);
1720 return &track_context_menu;
1724 Editor::build_track_bus_context_menu ()
1726 using namespace Menu_Helpers;
1728 MenuList& edit_items = track_context_menu.items();
1731 add_bus_context_items (edit_items);
1732 return &track_context_menu;
1736 Editor::build_track_region_context_menu ()
1738 using namespace Menu_Helpers;
1739 MenuList& edit_items = track_region_context_menu.items();
1742 /* we've just cleared the track region context menu, so the menu that these
1743 two items were on will have disappeared; stop them dangling.
1745 region_edit_menu_split_item = 0;
1746 region_edit_menu_split_multichannel_item = 0;
1748 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1751 boost::shared_ptr<Track> tr;
1752 boost::shared_ptr<Playlist> pl;
1754 if ((tr = rtv->track())) {
1755 add_region_context_items (edit_items, tr);
1759 add_dstream_context_items (edit_items);
1761 return &track_region_context_menu;
1765 Editor::analyze_region_selection ()
1767 if (analysis_window == 0) {
1768 analysis_window = new AnalysisWindow();
1771 analysis_window->set_session(_session);
1773 analysis_window->show_all();
1776 analysis_window->set_regionmode();
1777 analysis_window->analyze();
1779 analysis_window->present();
1783 Editor::analyze_range_selection()
1785 if (analysis_window == 0) {
1786 analysis_window = new AnalysisWindow();
1789 analysis_window->set_session(_session);
1791 analysis_window->show_all();
1794 analysis_window->set_rangemode();
1795 analysis_window->analyze();
1797 analysis_window->present();
1801 Editor::build_track_selection_context_menu ()
1803 using namespace Menu_Helpers;
1804 MenuList& edit_items = track_selection_context_menu.items();
1805 edit_items.clear ();
1807 add_selection_context_items (edit_items);
1808 // edit_items.push_back (SeparatorElem());
1809 // add_dstream_context_items (edit_items);
1811 return &track_selection_context_menu;
1815 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1817 using namespace Menu_Helpers;
1819 /* OK, stick the region submenu at the top of the list, and then add
1823 RegionSelection rs = get_regions_from_selection_and_entered ();
1825 string::size_type pos = 0;
1826 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1828 /* we have to hack up the region name because "_" has a special
1829 meaning for menu titles.
1832 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1833 menu_item_name.replace (pos, 1, "__");
1837 if (_popup_region_menu_item == 0) {
1838 _popup_region_menu_item = new MenuItem (menu_item_name);
1839 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1840 _popup_region_menu_item->show ();
1842 _popup_region_menu_item->set_label (menu_item_name);
1845 const framepos_t position = get_preferred_edit_position (false, true);
1847 edit_items.push_back (*_popup_region_menu_item);
1848 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1849 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1851 edit_items.push_back (SeparatorElem());
1854 /** Add context menu items relevant to selection ranges.
1855 * @param edit_items List to add the items to.
1858 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1860 using namespace Menu_Helpers;
1862 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1863 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1865 edit_items.push_back (SeparatorElem());
1866 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1868 edit_items.push_back (SeparatorElem());
1870 edit_items.push_back (
1872 _("Move Range Start to Previous Region Boundary"),
1873 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1877 edit_items.push_back (
1879 _("Move Range Start to Next Region Boundary"),
1880 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1884 edit_items.push_back (
1886 _("Move Range End to Previous Region Boundary"),
1887 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1891 edit_items.push_back (
1893 _("Move Range End to Next Region Boundary"),
1894 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1898 edit_items.push_back (SeparatorElem());
1899 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1900 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1905 edit_items.push_back (SeparatorElem());
1906 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1907 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1909 edit_items.push_back (SeparatorElem());
1910 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1912 edit_items.push_back (SeparatorElem());
1913 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1914 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1915 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1917 edit_items.push_back (SeparatorElem());
1918 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1919 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1920 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1921 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1922 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1927 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1929 using namespace Menu_Helpers;
1933 Menu *play_menu = manage (new Menu);
1934 MenuList& play_items = play_menu->items();
1935 play_menu->set_name ("ArdourContextMenu");
1937 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1938 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1939 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1940 play_items.push_back (SeparatorElem());
1941 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1943 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1947 Menu *select_menu = manage (new Menu);
1948 MenuList& select_items = select_menu->items();
1949 select_menu->set_name ("ArdourContextMenu");
1951 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1952 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1953 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1954 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1955 select_items.push_back (SeparatorElem());
1956 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1957 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1958 select_items.push_back (SeparatorElem());
1959 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1960 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1961 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1962 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1963 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1964 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1965 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1967 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1971 Menu *cutnpaste_menu = manage (new Menu);
1972 MenuList& cutnpaste_items = cutnpaste_menu->items();
1973 cutnpaste_menu->set_name ("ArdourContextMenu");
1975 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1976 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1977 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1979 cutnpaste_items.push_back (SeparatorElem());
1981 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1982 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1984 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1986 /* Adding new material */
1988 edit_items.push_back (SeparatorElem());
1989 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1990 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1994 Menu *nudge_menu = manage (new Menu());
1995 MenuList& nudge_items = nudge_menu->items();
1996 nudge_menu->set_name ("ArdourContextMenu");
1998 edit_items.push_back (SeparatorElem());
1999 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2000 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2001 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2002 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2004 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2008 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2010 using namespace Menu_Helpers;
2014 Menu *play_menu = manage (new Menu);
2015 MenuList& play_items = play_menu->items();
2016 play_menu->set_name ("ArdourContextMenu");
2018 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2019 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2020 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2024 Menu *select_menu = manage (new Menu);
2025 MenuList& select_items = select_menu->items();
2026 select_menu->set_name ("ArdourContextMenu");
2028 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2029 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2030 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2031 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2032 select_items.push_back (SeparatorElem());
2033 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2034 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2035 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2036 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2038 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2042 Menu *cutnpaste_menu = manage (new Menu);
2043 MenuList& cutnpaste_items = cutnpaste_menu->items();
2044 cutnpaste_menu->set_name ("ArdourContextMenu");
2046 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2047 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2048 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2050 Menu *nudge_menu = manage (new Menu());
2051 MenuList& nudge_items = nudge_menu->items();
2052 nudge_menu->set_name ("ArdourContextMenu");
2054 edit_items.push_back (SeparatorElem());
2055 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2056 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2057 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2058 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2060 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2064 Editor::snap_type() const
2070 Editor::snap_mode() const
2076 Editor::set_snap_to (SnapType st)
2078 unsigned int snap_ind = (unsigned int)st;
2082 if (snap_ind > snap_type_strings.size() - 1) {
2084 _snap_type = (SnapType)snap_ind;
2087 string str = snap_type_strings[snap_ind];
2089 if (str != snap_type_selector.get_active_text()) {
2090 snap_type_selector.set_active_text (str);
2095 switch (_snap_type) {
2096 case SnapToBeatDiv128:
2097 case SnapToBeatDiv64:
2098 case SnapToBeatDiv32:
2099 case SnapToBeatDiv28:
2100 case SnapToBeatDiv24:
2101 case SnapToBeatDiv20:
2102 case SnapToBeatDiv16:
2103 case SnapToBeatDiv14:
2104 case SnapToBeatDiv12:
2105 case SnapToBeatDiv10:
2106 case SnapToBeatDiv8:
2107 case SnapToBeatDiv7:
2108 case SnapToBeatDiv6:
2109 case SnapToBeatDiv5:
2110 case SnapToBeatDiv4:
2111 case SnapToBeatDiv3:
2112 case SnapToBeatDiv2:
2113 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2114 update_tempo_based_rulers ();
2117 case SnapToRegionStart:
2118 case SnapToRegionEnd:
2119 case SnapToRegionSync:
2120 case SnapToRegionBoundary:
2121 build_region_boundary_cache ();
2129 SnapChanged (); /* EMIT SIGNAL */
2133 Editor::set_snap_mode (SnapMode mode)
2136 string str = snap_mode_strings[(int)mode];
2138 if (str != snap_mode_selector.get_active_text ()) {
2139 snap_mode_selector.set_active_text (str);
2145 Editor::set_edit_point_preference (EditPoint ep, bool force)
2147 bool changed = (_edit_point != ep);
2150 string str = edit_point_strings[(int)ep];
2152 if (str != edit_point_selector.get_active_text ()) {
2153 edit_point_selector.set_active_text (str);
2156 set_canvas_cursor ();
2158 if (!force && !changed) {
2162 const char* action=NULL;
2164 switch (_edit_point) {
2165 case EditAtPlayhead:
2166 action = "edit-at-playhead";
2168 case EditAtSelectedMarker:
2169 action = "edit-at-marker";
2172 action = "edit-at-mouse";
2176 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2178 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2182 bool in_track_canvas;
2184 if (!mouse_frame (foo, in_track_canvas)) {
2185 in_track_canvas = false;
2188 reset_canvas_action_sensitivity (in_track_canvas);
2194 Editor::set_state (const XMLNode& node, int /*version*/)
2196 const XMLProperty* prop;
2203 g.base_width = default_width;
2204 g.base_height = default_height;
2208 if ((geometry = find_named_node (node, "geometry")) != 0) {
2212 if ((prop = geometry->property("x_size")) == 0) {
2213 prop = geometry->property ("x-size");
2216 g.base_width = atoi(prop->value());
2218 if ((prop = geometry->property("y_size")) == 0) {
2219 prop = geometry->property ("y-size");
2222 g.base_height = atoi(prop->value());
2225 if ((prop = geometry->property ("x_pos")) == 0) {
2226 prop = geometry->property ("x-pos");
2229 x = atoi (prop->value());
2232 if ((prop = geometry->property ("y_pos")) == 0) {
2233 prop = geometry->property ("y-pos");
2236 y = atoi (prop->value());
2240 set_default_size (g.base_width, g.base_height);
2243 if (_session && (prop = node.property ("playhead"))) {
2245 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2246 playhead_cursor->set_position (pos);
2248 playhead_cursor->set_position (0);
2251 if ((prop = node.property ("mixer-width"))) {
2252 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2255 if ((prop = node.property ("zoom-focus"))) {
2256 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2259 if ((prop = node.property ("zoom"))) {
2260 reset_zoom (PBD::atof (prop->value()));
2262 reset_zoom (frames_per_unit);
2265 if ((prop = node.property ("snap-to"))) {
2266 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2269 if ((prop = node.property ("snap-mode"))) {
2270 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2273 if ((prop = node.property ("internal-snap-to"))) {
2274 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2277 if ((prop = node.property ("internal-snap-mode"))) {
2278 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2281 if ((prop = node.property ("pre-internal-snap-to"))) {
2282 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2285 if ((prop = node.property ("pre-internal-snap-mode"))) {
2286 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2289 if ((prop = node.property ("mouse-mode"))) {
2290 MouseMode m = str2mousemode(prop->value());
2291 set_mouse_mode (m, true);
2293 set_mouse_mode (MouseObject, true);
2296 if ((prop = node.property ("left-frame")) != 0) {
2298 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2302 reset_x_origin (pos);
2306 if ((prop = node.property ("y-origin")) != 0) {
2307 reset_y_origin (atof (prop->value ()));
2310 if ((prop = node.property ("internal-edit"))) {
2311 bool yn = string_is_affirmative (prop->value());
2312 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2314 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2315 tact->set_active (!yn);
2316 tact->set_active (yn);
2320 if ((prop = node.property ("join-object-range"))) {
2321 ActionManager::set_toggle_action ("MouseMode", "set-mouse-mode-object-range", string_is_affirmative (prop->value ()));
2324 if ((prop = node.property ("edit-point"))) {
2325 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2328 if ((prop = node.property ("show-measures"))) {
2329 bool yn = string_is_affirmative (prop->value());
2330 _show_measures = yn;
2331 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2333 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2334 /* do it twice to force the change */
2335 tact->set_active (!yn);
2336 tact->set_active (yn);
2340 if ((prop = node.property ("follow-playhead"))) {
2341 bool yn = string_is_affirmative (prop->value());
2342 set_follow_playhead (yn);
2343 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2345 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2346 if (tact->get_active() != yn) {
2347 tact->set_active (yn);
2352 if ((prop = node.property ("stationary-playhead"))) {
2353 bool yn = string_is_affirmative (prop->value());
2354 set_stationary_playhead (yn);
2355 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2357 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2358 if (tact->get_active() != yn) {
2359 tact->set_active (yn);
2364 if ((prop = node.property ("region-list-sort-type"))) {
2365 RegionListSortType st;
2366 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2369 if ((prop = node.property ("show-editor-mixer"))) {
2371 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2374 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2375 bool yn = string_is_affirmative (prop->value());
2377 /* do it twice to force the change */
2379 tact->set_active (!yn);
2380 tact->set_active (yn);
2383 if ((prop = node.property ("show-editor-list"))) {
2385 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2388 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2389 bool yn = string_is_affirmative (prop->value());
2391 /* do it twice to force the change */
2393 tact->set_active (!yn);
2394 tact->set_active (yn);
2397 if ((prop = node.property (X_("editor-list-page")))) {
2398 _the_notebook.set_current_page (atoi (prop->value ()));
2401 if ((prop = node.property (X_("show-marker-lines")))) {
2402 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2404 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2405 bool yn = string_is_affirmative (prop->value ());
2407 tact->set_active (!yn);
2408 tact->set_active (yn);
2411 XMLNodeList children = node.children ();
2412 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2413 selection->set_state (**i, Stateful::current_state_version);
2414 _regions->set_state (**i);
2417 if ((prop = node.property ("maximised"))) {
2418 bool yn = string_is_affirmative (prop->value());
2420 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2424 if ((prop = node.property ("nudge-clock-value"))) {
2426 sscanf (prop->value().c_str(), "%" PRId64, &f);
2427 nudge_clock->set (f);
2429 nudge_clock->set_mode (AudioClock::Timecode);
2430 nudge_clock->set (_session->frame_rate() * 5, true);
2437 Editor::get_state ()
2439 XMLNode* node = new XMLNode ("Editor");
2442 id().print (buf, sizeof (buf));
2443 node->add_property ("id", buf);
2445 if (is_realized()) {
2446 Glib::RefPtr<Gdk::Window> win = get_window();
2448 int x, y, width, height;
2449 win->get_root_origin(x, y);
2450 win->get_size(width, height);
2452 XMLNode* geometry = new XMLNode ("geometry");
2454 snprintf(buf, sizeof(buf), "%d", width);
2455 geometry->add_property("x-size", string(buf));
2456 snprintf(buf, sizeof(buf), "%d", height);
2457 geometry->add_property("y-size", string(buf));
2458 snprintf(buf, sizeof(buf), "%d", x);
2459 geometry->add_property("x-pos", string(buf));
2460 snprintf(buf, sizeof(buf), "%d", y);
2461 geometry->add_property("y-pos", string(buf));
2462 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2463 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2464 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2465 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2466 geometry->add_property("edit-vertical-pane-pos", string(buf));
2468 node->add_child_nocopy (*geometry);
2471 maybe_add_mixer_strip_width (*node);
2473 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2474 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2475 node->add_property ("zoom", buf);
2476 node->add_property ("snap-to", enum_2_string (_snap_type));
2477 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2478 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2479 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2480 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2481 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2482 node->add_property ("edit-point", enum_2_string (_edit_point));
2484 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2485 node->add_property ("playhead", buf);
2486 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2487 node->add_property ("left-frame", buf);
2488 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2489 node->add_property ("y-origin", buf);
2491 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2492 node->add_property ("maximised", _maximised ? "yes" : "no");
2493 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2494 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2495 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2496 node->add_property ("mouse-mode", enum2str(mouse_mode));
2497 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2498 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2500 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2502 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2503 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2506 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2508 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2509 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2512 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2513 node->add_property (X_("editor-list-page"), buf);
2515 if (button_bindings) {
2516 XMLNode* bb = new XMLNode (X_("Buttons"));
2517 button_bindings->save (*bb);
2518 node->add_child_nocopy (*bb);
2521 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2523 node->add_child_nocopy (selection->get_state ());
2524 node->add_child_nocopy (_regions->get_state ());
2526 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2527 node->add_property ("nudge-clock-value", buf);
2534 /** @param y y offset from the top of all trackviews.
2535 * @return pair: TimeAxisView that y is over, layer index.
2536 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2537 * in stacked or expanded region display mode, otherwise 0.
2539 std::pair<TimeAxisView *, double>
2540 Editor::trackview_by_y_position (double y)
2542 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2544 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2550 return std::make_pair ( (TimeAxisView *) 0, 0);
2553 /** Snap a position to the grid, if appropriate, taking into account current
2554 * grid settings and also the state of any snap modifier keys that may be pressed.
2555 * @param start Position to snap.
2556 * @param event Event to get current key modifier information from, or 0.
2559 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2561 if (!_session || !event) {
2565 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2566 if (_snap_mode == SnapOff) {
2567 snap_to_internal (start, direction, for_mark);
2570 if (_snap_mode != SnapOff) {
2571 snap_to_internal (start, direction, for_mark);
2577 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2579 if (!_session || _snap_mode == SnapOff) {
2583 snap_to_internal (start, direction, for_mark);
2587 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2589 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2590 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2592 switch (_snap_type) {
2593 case SnapToTimecodeFrame:
2594 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2595 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2597 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2601 case SnapToTimecodeSeconds:
2602 if (_session->config.get_timecode_offset_negative()) {
2603 start += _session->config.get_timecode_offset ();
2605 start -= _session->config.get_timecode_offset ();
2607 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2608 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2610 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2613 if (_session->config.get_timecode_offset_negative()) {
2614 start -= _session->config.get_timecode_offset ();
2616 start += _session->config.get_timecode_offset ();
2620 case SnapToTimecodeMinutes:
2621 if (_session->config.get_timecode_offset_negative()) {
2622 start += _session->config.get_timecode_offset ();
2624 start -= _session->config.get_timecode_offset ();
2626 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2627 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2629 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2631 if (_session->config.get_timecode_offset_negative()) {
2632 start -= _session->config.get_timecode_offset ();
2634 start += _session->config.get_timecode_offset ();
2638 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2644 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2646 const framepos_t one_second = _session->frame_rate();
2647 const framepos_t one_minute = _session->frame_rate() * 60;
2648 framepos_t presnap = start;
2652 switch (_snap_type) {
2653 case SnapToTimecodeFrame:
2654 case SnapToTimecodeSeconds:
2655 case SnapToTimecodeMinutes:
2656 return timecode_snap_to_internal (start, direction, for_mark);
2659 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2660 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2662 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2667 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2668 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2670 start = (framepos_t) floor ((double) start / one_second) * one_second;
2675 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2676 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2678 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2683 start = _session->tempo_map().round_to_bar (start, direction);
2687 start = _session->tempo_map().round_to_beat (start, direction);
2690 case SnapToBeatDiv128:
2691 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2693 case SnapToBeatDiv64:
2694 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2696 case SnapToBeatDiv32:
2697 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2699 case SnapToBeatDiv28:
2700 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2702 case SnapToBeatDiv24:
2703 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2705 case SnapToBeatDiv20:
2706 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2708 case SnapToBeatDiv16:
2709 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2711 case SnapToBeatDiv14:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2714 case SnapToBeatDiv12:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2717 case SnapToBeatDiv10:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2720 case SnapToBeatDiv8:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2723 case SnapToBeatDiv7:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2726 case SnapToBeatDiv6:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2729 case SnapToBeatDiv5:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2732 case SnapToBeatDiv4:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2735 case SnapToBeatDiv3:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2738 case SnapToBeatDiv2:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2747 _session->locations()->marks_either_side (start, before, after);
2749 if (before == max_framepos) {
2751 } else if (after == max_framepos) {
2753 } else if (before != max_framepos && after != max_framepos) {
2754 /* have before and after */
2755 if ((start - before) < (after - start)) {
2764 case SnapToRegionStart:
2765 case SnapToRegionEnd:
2766 case SnapToRegionSync:
2767 case SnapToRegionBoundary:
2768 if (!region_boundary_cache.empty()) {
2770 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2771 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2773 if (direction > 0) {
2774 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2776 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2779 if (next != region_boundary_cache.begin ()) {
2784 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2785 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2787 if (start > (p + n) / 2) {
2796 switch (_snap_mode) {
2802 if (presnap > start) {
2803 if (presnap > (start + unit_to_frame(snap_threshold))) {
2807 } else if (presnap < start) {
2808 if (presnap < (start - unit_to_frame(snap_threshold))) {
2814 /* handled at entry */
2822 Editor::setup_toolbar ()
2824 HBox* mode_box = manage(new HBox);
2825 mode_box->set_border_width (2);
2826 mode_box->set_spacing(4);
2828 HBox* mouse_mode_box = manage (new HBox);
2829 HBox* mouse_mode_hbox1 = manage (new HBox);
2830 HBox* mouse_mode_hbox2 = manage (new HBox);
2831 VBox* mouse_mode_vbox1 = manage (new VBox);
2832 VBox* mouse_mode_vbox2 = manage (new VBox);
2833 Alignment* mouse_mode_align1 = manage (new Alignment);
2834 Alignment* mouse_mode_align2 = manage (new Alignment);
2836 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2837 mouse_mode_size_group->add_widget (mouse_move_button);
2838 mouse_mode_size_group->add_widget (mouse_select_button);
2839 mouse_mode_size_group->add_widget (mouse_zoom_button);
2840 mouse_mode_size_group->add_widget (mouse_gain_button);
2841 mouse_mode_size_group->add_widget (mouse_timefx_button);
2842 mouse_mode_size_group->add_widget (mouse_audition_button);
2843 mouse_mode_size_group->add_widget (mouse_draw_button);
2844 mouse_mode_size_group->add_widget (internal_edit_button);
2846 /* make them just a bit bigger */
2847 mouse_move_button.set_size_request (-1, 25);
2849 smart_mode_joiner = manage (new ButtonJoiner ("mouse mode button", mouse_move_button, mouse_select_button, true));
2850 smart_mode_joiner->set_related_action (smart_mode_action);
2852 mouse_mode_hbox2->set_spacing (2);
2853 mouse_mode_box->set_spacing (2);
2855 mouse_mode_hbox1->pack_start (*smart_mode_joiner, false, false);
2856 mouse_mode_hbox2->pack_start (mouse_zoom_button, false, false);
2857 mouse_mode_hbox2->pack_start (mouse_gain_button, false, false);
2858 mouse_mode_hbox2->pack_start (mouse_timefx_button, false, false);
2859 mouse_mode_hbox2->pack_start (mouse_audition_button, false, false);
2860 mouse_mode_hbox2->pack_start (mouse_draw_button, false, false);
2861 mouse_mode_hbox2->pack_start (internal_edit_button, false, false);
2863 mouse_mode_vbox1->pack_start (*mouse_mode_hbox1, false, false);
2864 mouse_mode_vbox2->pack_start (*mouse_mode_hbox2, false, false);
2866 mouse_mode_align1->add (*mouse_mode_vbox1);
2867 mouse_mode_align1->set (0.5, 1.0, 0.0, 0.0);
2868 mouse_mode_align2->add (*mouse_mode_vbox2);
2869 mouse_mode_align2->set (0.5, 1.0, 0.0, 0.0);
2871 mouse_mode_box->pack_start (*mouse_mode_align1, false, false);
2872 mouse_mode_box->pack_start (*mouse_mode_align2, false, false);
2874 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2875 if (!Profile->get_sae()) {
2876 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2878 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2880 edit_mode_selector.set_name ("EditModeSelector");
2881 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2882 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2884 mode_box->pack_start (edit_mode_selector, false, false);
2885 mode_box->pack_start (*mouse_mode_box, false, false);
2887 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2888 _mouse_mode_tearoff->set_name ("MouseModeBase");
2889 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2891 if (Profile->get_sae()) {
2892 _mouse_mode_tearoff->set_can_be_torn_off (false);
2895 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2896 &_mouse_mode_tearoff->tearoff_window()));
2897 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2898 &_mouse_mode_tearoff->tearoff_window(), 1));
2899 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2900 &_mouse_mode_tearoff->tearoff_window()));
2901 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2902 &_mouse_mode_tearoff->tearoff_window(), 1));
2906 _zoom_box.set_spacing (2);
2907 _zoom_box.set_border_width (2);
2911 zoom_in_button.set_name ("zoom button");
2912 zoom_in_button.set_image (::get_icon ("zoom_in"));
2913 zoom_in_button.set_tweaks (ArdourButton::ShowClick);
2914 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2915 zoom_in_button.set_related_action (act);
2917 zoom_out_button.set_name ("zoom button");
2918 zoom_out_button.set_image (::get_icon ("zoom_out"));
2919 zoom_out_button.set_tweaks (ArdourButton::ShowClick);
2920 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2921 zoom_out_button.set_related_action (act);
2923 zoom_out_full_button.set_name ("zoom button");
2924 zoom_out_full_button.set_image (::get_icon ("zoom_full"));
2925 zoom_out_full_button.set_tweaks (ArdourButton::ShowClick);
2926 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2927 zoom_out_full_button.set_related_action (act);
2929 zoom_focus_selector.set_name ("ZoomFocusSelector");
2930 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2931 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2933 _zoom_box.pack_start (zoom_out_button, false, false);
2934 _zoom_box.pack_start (zoom_in_button, false, false);
2935 _zoom_box.pack_start (zoom_out_full_button, false, false);
2937 _zoom_box.pack_start (zoom_focus_selector, false, false);
2939 /* Track zoom buttons */
2940 tav_expand_button.set_name ("TrackHeightButton");
2941 tav_expand_button.set_size_request (-1, 20);
2942 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2943 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2944 act->connect_proxy (tav_expand_button);
2946 tav_shrink_button.set_name ("TrackHeightButton");
2947 tav_shrink_button.set_size_request (-1, 20);
2948 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2949 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2950 act->connect_proxy (tav_shrink_button);
2952 _zoom_box.pack_start (tav_shrink_button);
2953 _zoom_box.pack_start (tav_expand_button);
2955 _zoom_tearoff = manage (new TearOff (_zoom_box));
2957 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2958 &_zoom_tearoff->tearoff_window()));
2959 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2960 &_zoom_tearoff->tearoff_window(), 0));
2961 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2962 &_zoom_tearoff->tearoff_window()));
2963 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2964 &_zoom_tearoff->tearoff_window(), 0));
2966 snap_box.set_spacing (1);
2967 snap_box.set_border_width (2);
2969 snap_type_selector.set_name ("SnapTypeSelector");
2970 set_popdown_strings (snap_type_selector, snap_type_strings);
2971 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2973 snap_mode_selector.set_name ("SnapModeSelector");
2974 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2975 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2977 edit_point_selector.set_name ("EditPointSelector");
2978 set_popdown_strings (edit_point_selector, edit_point_strings);
2979 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2981 snap_box.pack_start (snap_mode_selector, false, false);
2982 snap_box.pack_start (snap_type_selector, false, false);
2983 snap_box.pack_start (edit_point_selector, false, false);
2987 HBox *nudge_box = manage (new HBox);
2988 nudge_box->set_spacing (2);
2989 nudge_box->set_border_width (2);
2991 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2992 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2994 nudge_box->pack_start (nudge_backward_button, false, false);
2995 nudge_box->pack_start (nudge_forward_button, false, false);
2996 nudge_box->pack_start (*nudge_clock, false, false);
2999 /* Pack everything in... */
3001 HBox* hbox = manage (new HBox);
3002 hbox->set_spacing(10);
3004 _tools_tearoff = manage (new TearOff (*hbox));
3005 _tools_tearoff->set_name ("MouseModeBase");
3006 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3008 if (Profile->get_sae()) {
3009 _tools_tearoff->set_can_be_torn_off (false);
3012 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3013 &_tools_tearoff->tearoff_window()));
3014 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3015 &_tools_tearoff->tearoff_window(), 0));
3016 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3017 &_tools_tearoff->tearoff_window()));
3018 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3019 &_tools_tearoff->tearoff_window(), 0));
3021 toolbar_hbox.set_spacing (10);
3022 toolbar_hbox.set_border_width (1);
3024 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3025 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3026 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3028 hbox->pack_start (snap_box, false, false);
3029 if (!Profile->get_small_screen()) {
3030 hbox->pack_start (*nudge_box, false, false);
3032 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3034 hbox->pack_start (panic_box, false, false);
3038 toolbar_base.set_name ("ToolBarBase");
3039 toolbar_base.add (toolbar_hbox);
3041 _toolbar_viewport.add (toolbar_base);
3042 /* stick to the required height but allow width to vary if there's not enough room */
3043 _toolbar_viewport.set_size_request (1, -1);
3045 toolbar_frame.set_shadow_type (SHADOW_OUT);
3046 toolbar_frame.set_name ("BaseFrame");
3047 toolbar_frame.add (_toolbar_viewport);
3051 Editor::setup_tooltips ()
3053 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
3054 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Select/Move Ranges"));
3055 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3056 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3057 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3058 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3059 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3060 ARDOUR_UI::instance()->set_tip (smart_mode_joiner, _("Smart Mode (Select/Move Objects + Ranges)"));
3061 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
3062 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3063 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3064 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3065 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3066 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3067 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3068 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3069 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3070 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3071 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3072 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3073 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3074 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3075 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3079 Editor::convert_drop_to_paths (
3080 vector<string>& paths,
3081 const RefPtr<Gdk::DragContext>& /*context*/,
3084 const SelectionData& data,
3088 if (_session == 0) {
3092 vector<string> uris = data.get_uris();
3096 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3097 are actually URI lists. So do it by hand.
3100 if (data.get_target() != "text/plain") {
3104 /* Parse the "uri-list" format that Nautilus provides,
3105 where each pathname is delimited by \r\n.
3107 THERE MAY BE NO NULL TERMINATING CHAR!!!
3110 string txt = data.get_text();
3114 p = (const char *) malloc (txt.length() + 1);
3115 txt.copy ((char *) p, txt.length(), 0);
3116 ((char*)p)[txt.length()] = '\0';
3122 while (g_ascii_isspace (*p))
3126 while (*q && (*q != '\n') && (*q != '\r')) {
3133 while (q > p && g_ascii_isspace (*q))
3138 uris.push_back (string (p, q - p + 1));
3142 p = strchr (p, '\n');
3154 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3156 if ((*i).substr (0,7) == "file://") {
3158 string const p = PBD::url_decode (*i);
3160 // scan forward past three slashes
3162 string::size_type slashcnt = 0;
3163 string::size_type n = 0;
3164 string::const_iterator x = p.begin();
3166 while (slashcnt < 3 && x != p.end()) {
3169 } else if (slashcnt == 3) {
3176 if (slashcnt != 3 || x == p.end()) {
3177 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3181 paths.push_back (p.substr (n - 1));
3189 Editor::new_tempo_section ()
3195 Editor::map_transport_state ()
3197 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3199 if (_session && _session->transport_stopped()) {
3200 have_pending_keyboard_selection = false;
3203 update_loop_range_view (true);
3209 Editor::begin_reversible_command (string name)
3212 _session->begin_reversible_command (name);
3217 Editor::begin_reversible_command (GQuark q)
3220 _session->begin_reversible_command (q);
3225 Editor::commit_reversible_command ()
3228 _session->commit_reversible_command ();
3233 Editor::history_changed ()
3237 if (undo_action && _session) {
3238 if (_session->undo_depth() == 0) {
3239 label = S_("Command|Undo");
3241 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3243 undo_action->property_label() = label;
3246 if (redo_action && _session) {
3247 if (_session->redo_depth() == 0) {
3250 label = string_compose(_("Redo (%1)"), _session->next_redo());
3252 redo_action->property_label() = label;
3257 Editor::duplicate_dialog (bool with_dialog)
3261 if (mouse_mode == MouseRange) {
3262 if (selection->time.length() == 0) {
3267 RegionSelection rs = get_regions_from_selection_and_entered ();
3269 if (mouse_mode != MouseRange && rs.empty()) {
3275 ArdourDialog win (_("Duplicate"));
3276 Label label (_("Number of duplications:"));
3277 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3278 SpinButton spinner (adjustment, 0.0, 1);
3281 win.get_vbox()->set_spacing (12);
3282 win.get_vbox()->pack_start (hbox);
3283 hbox.set_border_width (6);
3284 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3286 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3287 place, visually. so do this by hand.
3290 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3291 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3292 spinner.grab_focus();
3298 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3299 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3300 win.set_default_response (RESPONSE_ACCEPT);
3302 win.set_position (WIN_POS_MOUSE);
3304 spinner.grab_focus ();
3306 switch (win.run ()) {
3307 case RESPONSE_ACCEPT:
3313 times = adjustment.get_value();
3316 if (mouse_mode == MouseRange) {
3317 duplicate_selection (times);
3319 duplicate_some_regions (rs, times);
3324 Editor::set_edit_mode (EditMode m)
3326 Config->set_edit_mode (m);
3330 Editor::cycle_edit_mode ()
3332 switch (Config->get_edit_mode()) {
3334 if (Profile->get_sae()) {
3335 Config->set_edit_mode (Lock);
3337 Config->set_edit_mode (Splice);
3341 Config->set_edit_mode (Lock);
3344 Config->set_edit_mode (Slide);
3350 Editor::edit_mode_selection_done ()
3352 string s = edit_mode_selector.get_active_text ();
3355 Config->set_edit_mode (string_to_edit_mode (s));
3360 Editor::snap_type_selection_done ()
3362 string choice = snap_type_selector.get_active_text();
3363 SnapType snaptype = SnapToBeat;
3365 if (choice == _("Beats/2")) {
3366 snaptype = SnapToBeatDiv2;
3367 } else if (choice == _("Beats/3")) {
3368 snaptype = SnapToBeatDiv3;
3369 } else if (choice == _("Beats/4")) {
3370 snaptype = SnapToBeatDiv4;
3371 } else if (choice == _("Beats/5")) {
3372 snaptype = SnapToBeatDiv5;
3373 } else if (choice == _("Beats/6")) {
3374 snaptype = SnapToBeatDiv6;
3375 } else if (choice == _("Beats/7")) {
3376 snaptype = SnapToBeatDiv7;
3377 } else if (choice == _("Beats/8")) {
3378 snaptype = SnapToBeatDiv8;
3379 } else if (choice == _("Beats/10")) {
3380 snaptype = SnapToBeatDiv10;
3381 } else if (choice == _("Beats/12")) {
3382 snaptype = SnapToBeatDiv12;
3383 } else if (choice == _("Beats/14")) {
3384 snaptype = SnapToBeatDiv14;
3385 } else if (choice == _("Beats/16")) {
3386 snaptype = SnapToBeatDiv16;
3387 } else if (choice == _("Beats/20")) {
3388 snaptype = SnapToBeatDiv20;
3389 } else if (choice == _("Beats/24")) {
3390 snaptype = SnapToBeatDiv24;
3391 } else if (choice == _("Beats/28")) {
3392 snaptype = SnapToBeatDiv28;
3393 } else if (choice == _("Beats/32")) {
3394 snaptype = SnapToBeatDiv32;
3395 } else if (choice == _("Beats/64")) {
3396 snaptype = SnapToBeatDiv64;
3397 } else if (choice == _("Beats/128")) {
3398 snaptype = SnapToBeatDiv128;
3399 } else if (choice == _("Beats")) {
3400 snaptype = SnapToBeat;
3401 } else if (choice == _("Bars")) {
3402 snaptype = SnapToBar;
3403 } else if (choice == _("Marks")) {
3404 snaptype = SnapToMark;
3405 } else if (choice == _("Region starts")) {
3406 snaptype = SnapToRegionStart;
3407 } else if (choice == _("Region ends")) {
3408 snaptype = SnapToRegionEnd;
3409 } else if (choice == _("Region bounds")) {
3410 snaptype = SnapToRegionBoundary;
3411 } else if (choice == _("Region syncs")) {
3412 snaptype = SnapToRegionSync;
3413 } else if (choice == _("CD Frames")) {
3414 snaptype = SnapToCDFrame;
3415 } else if (choice == _("Timecode Frames")) {
3416 snaptype = SnapToTimecodeFrame;
3417 } else if (choice == _("Timecode Seconds")) {
3418 snaptype = SnapToTimecodeSeconds;
3419 } else if (choice == _("Timecode Minutes")) {
3420 snaptype = SnapToTimecodeMinutes;
3421 } else if (choice == _("Seconds")) {
3422 snaptype = SnapToSeconds;
3423 } else if (choice == _("Minutes")) {
3424 snaptype = SnapToMinutes;
3427 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3429 ract->set_active ();
3434 Editor::snap_mode_selection_done ()
3436 string choice = snap_mode_selector.get_active_text();
3437 SnapMode mode = SnapNormal;
3439 if (choice == _("No Grid")) {
3441 } else if (choice == _("Grid")) {
3443 } else if (choice == _("Magnetic")) {
3444 mode = SnapMagnetic;
3447 RefPtr<RadioAction> ract = snap_mode_action (mode);
3450 ract->set_active (true);
3455 Editor::cycle_edit_point (bool with_marker)
3457 switch (_edit_point) {
3459 set_edit_point_preference (EditAtPlayhead);
3461 case EditAtPlayhead:
3463 set_edit_point_preference (EditAtSelectedMarker);
3465 set_edit_point_preference (EditAtMouse);
3468 case EditAtSelectedMarker:
3469 set_edit_point_preference (EditAtMouse);
3475 Editor::edit_point_selection_done ()
3477 string choice = edit_point_selector.get_active_text();
3478 EditPoint ep = EditAtSelectedMarker;
3480 if (choice == _("Marker")) {
3481 set_edit_point_preference (EditAtSelectedMarker);
3482 } else if (choice == _("Playhead")) {
3483 set_edit_point_preference (EditAtPlayhead);
3485 set_edit_point_preference (EditAtMouse);
3488 RefPtr<RadioAction> ract = edit_point_action (ep);
3491 ract->set_active (true);
3496 Editor::zoom_focus_selection_done ()
3498 string choice = zoom_focus_selector.get_active_text();
3499 ZoomFocus focus_type = ZoomFocusLeft;
3501 if (choice == _("Left")) {
3502 focus_type = ZoomFocusLeft;
3503 } else if (choice == _("Right")) {
3504 focus_type = ZoomFocusRight;
3505 } else if (choice == _("Center")) {
3506 focus_type = ZoomFocusCenter;
3507 } else if (choice == _("Playhead")) {
3508 focus_type = ZoomFocusPlayhead;
3509 } else if (choice == _("Mouse")) {
3510 focus_type = ZoomFocusMouse;
3511 } else if (choice == _("Edit point")) {
3512 focus_type = ZoomFocusEdit;
3515 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3518 ract->set_active ();
3523 Editor::edit_controls_button_release (GdkEventButton* ev)
3525 if (Keyboard::is_context_menu_event (ev)) {
3526 ARDOUR_UI::instance()->add_route (this);
3527 } else if (ev->button == 1) {
3528 selection->clear_tracks ();
3535 Editor::mouse_select_button_release (GdkEventButton* ev)
3537 /* this handles just right-clicks */
3539 if (ev->button != 3) {
3547 Editor::set_zoom_focus (ZoomFocus f)
3549 string str = zoom_focus_strings[(int)f];
3551 if (str != zoom_focus_selector.get_active_text()) {
3552 zoom_focus_selector.set_active_text (str);
3555 if (zoom_focus != f) {
3562 Editor::ensure_float (Window& win)
3564 win.set_transient_for (*this);
3568 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3570 /* recover or initialize pane positions. do this here rather than earlier because
3571 we don't want the positions to change the child allocations, which they seem to do.
3577 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3586 XMLNode* geometry = find_named_node (*node, "geometry");
3588 if (which == static_cast<Paned*> (&edit_pane)) {
3590 if (done & Horizontal) {
3594 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3595 _notebook_shrunk = string_is_affirmative (prop->value ());
3598 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3599 /* initial allocation is 90% to canvas, 10% to notebook */
3600 pos = (int) floor (alloc.get_width() * 0.90f);
3601 snprintf (buf, sizeof(buf), "%d", pos);
3603 pos = atoi (prop->value());
3606 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3607 edit_pane.set_position (pos);
3610 done = (Pane) (done | Horizontal);
3612 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3614 if (done & Vertical) {
3618 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3619 /* initial allocation is 90% to canvas, 10% to summary */
3620 pos = (int) floor (alloc.get_height() * 0.90f);
3621 snprintf (buf, sizeof(buf), "%d", pos);
3624 pos = atoi (prop->value());
3627 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3628 editor_summary_pane.set_position (pos);
3631 done = (Pane) (done | Vertical);
3636 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3638 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3639 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3640 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3641 top_hbox.remove (toolbar_frame);
3646 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3648 if (toolbar_frame.get_parent() == 0) {
3649 top_hbox.pack_end (toolbar_frame);
3654 Editor::set_show_measures (bool yn)
3656 if (_show_measures != yn) {
3659 if ((_show_measures = yn) == true) {
3661 tempo_lines->show();
3669 Editor::toggle_follow_playhead ()
3671 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3673 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3674 set_follow_playhead (tact->get_active());
3678 /** @param yn true to follow playhead, otherwise false.
3679 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3682 Editor::set_follow_playhead (bool yn, bool catch_up)
3684 if (_follow_playhead != yn) {
3685 if ((_follow_playhead = yn) == true && catch_up) {
3687 reset_x_origin_to_follow_playhead ();
3694 Editor::toggle_stationary_playhead ()
3696 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3698 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3699 set_stationary_playhead (tact->get_active());
3704 Editor::set_stationary_playhead (bool yn)
3706 if (_stationary_playhead != yn) {
3707 if ((_stationary_playhead = yn) == true) {
3709 // FIXME need a 3.0 equivalent of this 2.X call
3710 // update_current_screen ();
3717 Editor::playlist_selector () const
3719 return *_playlist_selector;
3723 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3727 switch (_snap_type) {
3732 case SnapToBeatDiv128:
3735 case SnapToBeatDiv64:
3738 case SnapToBeatDiv32:
3741 case SnapToBeatDiv28:
3744 case SnapToBeatDiv24:
3747 case SnapToBeatDiv20:
3750 case SnapToBeatDiv16:
3753 case SnapToBeatDiv14:
3756 case SnapToBeatDiv12:
3759 case SnapToBeatDiv10:
3762 case SnapToBeatDiv8:
3765 case SnapToBeatDiv7:
3768 case SnapToBeatDiv6:
3771 case SnapToBeatDiv5:
3774 case SnapToBeatDiv4:
3777 case SnapToBeatDiv3:
3780 case SnapToBeatDiv2:
3786 return _session->tempo_map().meter_at (position).divisions_per_bar();
3791 case SnapToTimecodeFrame:
3792 case SnapToTimecodeSeconds:
3793 case SnapToTimecodeMinutes:
3796 case SnapToRegionStart:
3797 case SnapToRegionEnd:
3798 case SnapToRegionSync:
3799 case SnapToRegionBoundary:
3809 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3813 ret = nudge_clock->current_duration (pos);
3814 next = ret + 1; /* XXXX fix me */
3820 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3822 ArdourDialog dialog (_("Playlist Deletion"));
3823 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3824 "If it is kept, its audio files will not be cleaned.\n"
3825 "If it is deleted, audio files used by it alone will be cleaned."),
3828 dialog.set_position (WIN_POS_CENTER);
3829 dialog.get_vbox()->pack_start (label);
3833 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3834 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3835 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3837 switch (dialog.run ()) {
3838 case RESPONSE_ACCEPT:
3839 /* delete the playlist */
3843 case RESPONSE_REJECT:
3844 /* keep the playlist */
3856 Editor::audio_region_selection_covers (framepos_t where)
3858 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3859 if ((*a)->region()->covers (where)) {
3868 Editor::prepare_for_cleanup ()
3870 cut_buffer->clear_regions ();
3871 cut_buffer->clear_playlists ();
3873 selection->clear_regions ();
3874 selection->clear_playlists ();
3876 _regions->suspend_redisplay ();
3880 Editor::finish_cleanup ()
3882 _regions->resume_redisplay ();
3886 Editor::transport_loop_location()
3889 return _session->locations()->auto_loop_location();
3896 Editor::transport_punch_location()
3899 return _session->locations()->auto_punch_location();
3906 Editor::control_layout_scroll (GdkEventScroll* ev)
3908 if (Keyboard::some_magic_widget_has_focus()) {
3912 switch (ev->direction) {
3914 scroll_tracks_up_line ();
3918 case GDK_SCROLL_DOWN:
3919 scroll_tracks_down_line ();
3923 /* no left/right handling yet */
3931 Editor::session_state_saved (string)
3934 _snapshots->redisplay ();
3938 Editor::maximise_editing_space ()
3946 if (!Config->get_keep_tearoffs()) {
3947 /* these calls will leave each tearoff visible *if* it is torn off,
3948 but invisible otherwise.
3950 _mouse_mode_tearoff->set_visible (false);
3951 _tools_tearoff->set_visible (false);
3952 _zoom_tearoff->set_visible (false);
3959 Editor::restore_editing_space ()
3967 if (!Config->get_keep_tearoffs()) {
3968 _mouse_mode_tearoff->set_visible (true);
3969 _tools_tearoff->set_visible (true);
3970 _zoom_tearoff->set_visible (true);
3977 * Make new playlists for a given track and also any others that belong
3978 * to the same active route group with the `edit' property.
3983 Editor::new_playlists (TimeAxisView* v)
3985 begin_reversible_command (_("new playlists"));
3986 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
3987 _session->playlists->get (playlists);
3988 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
3989 commit_reversible_command ();
3993 * Use a copy of the current playlist for a given track and also any others that belong
3994 * to the same active route group with the `edit' property.
3999 Editor::copy_playlists (TimeAxisView* v)
4001 begin_reversible_command (_("copy playlists"));
4002 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4003 _session->playlists->get (playlists);
4004 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4005 commit_reversible_command ();
4008 /** Clear the current playlist for a given track and also any others that belong
4009 * to the same active route group with the `edit' property.
4014 Editor::clear_playlists (TimeAxisView* v)
4016 begin_reversible_command (_("clear playlists"));
4017 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4018 _session->playlists->get (playlists);
4019 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4020 commit_reversible_command ();
4024 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4026 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4030 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4032 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4036 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4038 atv.clear_playlist ();
4042 Editor::on_key_press_event (GdkEventKey* ev)
4044 return key_press_focus_accelerator_handler (*this, ev);
4048 Editor::on_key_release_event (GdkEventKey* ev)
4050 return Gtk::Window::on_key_release_event (ev);
4051 // return key_press_focus_accelerator_handler (*this, ev);
4054 /** Queue up a change to the viewport x origin.
4055 * @param frame New x origin.
4058 Editor::reset_x_origin (framepos_t frame)
4060 queue_visual_change (frame);
4064 Editor::reset_y_origin (double y)
4066 queue_visual_change_y (y);
4070 Editor::reset_zoom (double fpu)
4072 queue_visual_change (fpu);
4076 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4078 reset_x_origin (frame);
4081 if (!no_save_visual) {
4082 undo_visual_stack.push_back (current_visual_state(false));
4086 Editor::VisualState::VisualState (bool with_tracks)
4087 : gui_state (with_tracks ? new GUIObjectState : 0)
4091 Editor::VisualState::~VisualState ()
4096 Editor::VisualState*
4097 Editor::current_visual_state (bool with_tracks)
4099 VisualState* vs = new VisualState (with_tracks);
4100 vs->y_position = vertical_adjustment.get_value();
4101 vs->frames_per_unit = frames_per_unit;
4102 vs->leftmost_frame = leftmost_frame;
4103 vs->zoom_focus = zoom_focus;
4106 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4113 Editor::undo_visual_state ()
4115 if (undo_visual_stack.empty()) {
4119 VisualState* vs = undo_visual_stack.back();
4120 undo_visual_stack.pop_back();
4123 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4125 use_visual_state (*vs);
4129 Editor::redo_visual_state ()
4131 if (redo_visual_stack.empty()) {
4135 VisualState* vs = redo_visual_stack.back();
4136 redo_visual_stack.pop_back();
4138 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4140 use_visual_state (*vs);
4144 Editor::swap_visual_state ()
4146 if (undo_visual_stack.empty()) {
4147 redo_visual_state ();
4149 undo_visual_state ();
4154 Editor::use_visual_state (VisualState& vs)
4156 PBD::Unwinder<bool> nsv (no_save_visual, true);
4158 _routes->suspend_redisplay ();
4160 vertical_adjustment.set_value (vs.y_position);
4162 set_zoom_focus (vs.zoom_focus);
4163 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4166 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4168 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4169 (*i)->reset_visual_state ();
4173 _routes->update_visibility ();
4174 _routes->resume_redisplay ();
4178 Editor::set_frames_per_unit (double fpu)
4180 /* this is the core function that controls the zoom level of the canvas. it is called
4181 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4184 if (fpu == frames_per_unit) {
4193 /* don't allow zooms that fit more than the maximum number
4194 of frames into an 800 pixel wide space.
4197 if (max_framepos / fpu < 800.0) {
4202 tempo_lines->tempo_map_changed();
4204 frames_per_unit = fpu;
4209 Editor::post_zoom ()
4211 // convert fpu to frame count
4213 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4215 if (frames_per_unit != zoom_range_clock->current_duration()) {
4216 zoom_range_clock->set (frames);
4219 bool const showing_time_selection =
4220 mouse_mode == MouseRange ||
4221 (mouse_mode == MouseObject && _join_object_range_state != JOIN_OBJECT_RANGE_NONE);
4223 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4224 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4225 (*i)->reshow_selection (selection->time);
4229 ZoomChanged (); /* EMIT_SIGNAL */
4231 //reset_scrolling_region ();
4233 if (playhead_cursor) {
4234 playhead_cursor->set_position (playhead_cursor->current_frame);
4237 refresh_location_display();
4238 _summary->set_overlays_dirty ();
4240 update_marker_labels ();
4246 Editor::queue_visual_change (framepos_t where)
4248 pending_visual_change.add (VisualChange::TimeOrigin);
4249 pending_visual_change.time_origin = where;
4250 ensure_visual_change_idle_handler ();
4254 Editor::queue_visual_change (double fpu)
4256 pending_visual_change.add (VisualChange::ZoomLevel);
4257 pending_visual_change.frames_per_unit = fpu;
4259 ensure_visual_change_idle_handler ();
4263 Editor::queue_visual_change_y (double y)
4265 pending_visual_change.add (VisualChange::YOrigin);
4266 pending_visual_change.y_origin = y;
4268 ensure_visual_change_idle_handler ();
4272 Editor::ensure_visual_change_idle_handler ()
4274 if (pending_visual_change.idle_handler_id < 0) {
4275 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4280 Editor::_idle_visual_changer (void* arg)
4282 return static_cast<Editor*>(arg)->idle_visual_changer ();
4286 Editor::idle_visual_changer ()
4288 VisualChange::Type p = pending_visual_change.pending;
4289 pending_visual_change.pending = (VisualChange::Type) 0;
4291 double const last_time_origin = horizontal_position ();
4293 if (p & VisualChange::ZoomLevel) {
4294 set_frames_per_unit (pending_visual_change.frames_per_unit);
4296 compute_fixed_ruler_scale ();
4297 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4298 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4299 update_tempo_based_rulers ();
4301 if (p & VisualChange::TimeOrigin) {
4302 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4304 if (p & VisualChange::YOrigin) {
4305 vertical_adjustment.set_value (pending_visual_change.y_origin);
4308 if (last_time_origin == horizontal_position ()) {
4309 /* changed signal not emitted */
4310 update_fixed_rulers ();
4311 redisplay_tempo (true);
4314 _summary->set_overlays_dirty ();
4316 pending_visual_change.idle_handler_id = -1;
4317 return 0; /* this is always a one-shot call */
4320 struct EditorOrderTimeAxisSorter {
4321 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4322 return a->order () < b->order ();
4327 Editor::sort_track_selection (TrackViewList& sel)
4329 EditorOrderTimeAxisSorter cmp;
4334 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4337 framepos_t where = 0;
4338 EditPoint ep = _edit_point;
4340 if (from_context_menu && (ep == EditAtMouse)) {
4341 return event_frame (&context_click_event, 0, 0);
4344 if (entered_marker) {
4345 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4346 return entered_marker->position();
4349 if (ignore_playhead && ep == EditAtPlayhead) {
4350 ep = EditAtSelectedMarker;
4354 case EditAtPlayhead:
4355 where = _session->audible_frame();
4356 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4359 case EditAtSelectedMarker:
4360 if (!selection->markers.empty()) {
4362 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4365 where = loc->start();
4369 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4377 if (!mouse_frame (where, ignored)) {
4378 /* XXX not right but what can we do ? */
4382 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4390 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4392 if (!_session) return;
4394 begin_reversible_command (cmd);
4398 if ((tll = transport_loop_location()) == 0) {
4399 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4400 XMLNode &before = _session->locations()->get_state();
4401 _session->locations()->add (loc, true);
4402 _session->set_auto_loop_location (loc);
4403 XMLNode &after = _session->locations()->get_state();
4404 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4406 XMLNode &before = tll->get_state();
4407 tll->set_hidden (false, this);
4408 tll->set (start, end);
4409 XMLNode &after = tll->get_state();
4410 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4413 commit_reversible_command ();
4417 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4419 if (!_session) return;
4421 begin_reversible_command (cmd);
4425 if ((tpl = transport_punch_location()) == 0) {
4426 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4427 XMLNode &before = _session->locations()->get_state();
4428 _session->locations()->add (loc, true);
4429 _session->set_auto_loop_location (loc);
4430 XMLNode &after = _session->locations()->get_state();
4431 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4434 XMLNode &before = tpl->get_state();
4435 tpl->set_hidden (false, this);
4436 tpl->set (start, end);
4437 XMLNode &after = tpl->get_state();
4438 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4441 commit_reversible_command ();
4444 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4445 * @param rs List to which found regions are added.
4446 * @param where Time to look at.
4447 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4450 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4452 const TrackViewList* tracks;
4455 tracks = &track_views;
4460 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4462 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4465 boost::shared_ptr<Track> tr;
4466 boost::shared_ptr<Playlist> pl;
4468 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4470 boost::shared_ptr<RegionList> regions = pl->regions_at (
4471 (framepos_t) floor ( (double) where * tr->speed()));
4473 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4474 RegionView* rv = rtv->view()->find_view (*i);
4485 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4487 const TrackViewList* tracks;
4490 tracks = &track_views;
4495 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4496 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4498 boost::shared_ptr<Track> tr;
4499 boost::shared_ptr<Playlist> pl;
4501 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4503 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4504 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4506 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4508 RegionView* rv = rtv->view()->find_view (*i);
4519 /** Start with regions that are selected. Then add equivalent regions
4520 * on tracks in the same active edit-enabled route group as any of
4521 * the regions that we started with.
4525 Editor::get_regions_from_selection ()
4527 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4530 /** Get regions using the following method:
4532 * Make an initial region list using the selected regions, unless
4533 * the edit point is `mouse' and the mouse is over an unselected
4534 * region. In this case, start with just that region.
4536 * Then, make an initial track list of the tracks that these
4537 * regions are on, and if the edit point is not `mouse', add the
4540 * Look at this track list and add any other tracks that are on the
4541 * same active edit-enabled route group as one of the initial tracks.
4543 * Finally take the initial region list and add any regions that are
4544 * under the edit point on one of the tracks on the track list to get
4545 * the returned region list.
4547 * The rationale here is that the mouse edit point is special in that
4548 * its position describes both a time and a track; the other edit
4549 * modes only describe a time. Hence if the edit point is `mouse' we
4550 * ignore selected tracks, as we assume the user means something by
4551 * pointing at a particular track. Also in this case we take note of
4552 * the region directly under the edit point, as there is always just one
4553 * (rather than possibly several with non-mouse edit points).
4557 Editor::get_regions_from_selection_and_edit_point ()
4559 RegionSelection regions;
4561 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4562 regions.add (entered_regionview);
4564 regions = selection->regions;
4567 TrackViewList tracks;
4569 if (_edit_point != EditAtMouse) {
4570 tracks = selection->tracks;
4573 /* Add any other tracks that have regions that are in the same
4574 edit-activated route group as one of our regions.
4576 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4578 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4580 if (g && g->is_active() && g->is_edit()) {
4581 tracks.add (axis_views_from_routes (g->route_list()));
4585 if (!tracks.empty()) {
4586 /* now find regions that are at the edit position on those tracks */
4587 framepos_t const where = get_preferred_edit_position ();
4588 get_regions_at (regions, where, tracks);
4594 /** Start with regions that are selected, or the entered regionview if none are selected.
4595 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4596 * of the regions that we started with.
4600 Editor::get_regions_from_selection_and_entered ()
4602 RegionSelection regions = selection->regions;
4604 if (regions.empty() && entered_regionview) {
4605 regions.add (entered_regionview);
4608 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4612 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4614 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4616 RouteTimeAxisView* tatv;
4618 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4620 boost::shared_ptr<Playlist> pl;
4621 vector<boost::shared_ptr<Region> > results;
4623 boost::shared_ptr<Track> tr;
4625 if ((tr = tatv->track()) == 0) {
4630 if ((pl = (tr->playlist())) != 0) {
4631 pl->get_region_list_equivalent_regions (region, results);
4634 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4635 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4636 regions.push_back (marv);
4645 Editor::show_rhythm_ferret ()
4647 if (rhythm_ferret == 0) {
4648 rhythm_ferret = new RhythmFerret(*this);
4651 rhythm_ferret->set_session (_session);
4652 rhythm_ferret->show ();
4653 rhythm_ferret->present ();
4657 Editor::first_idle ()
4659 MessageDialog* dialog = 0;
4661 if (track_views.size() > 1) {
4662 dialog = new MessageDialog (
4664 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4668 ARDOUR_UI::instance()->flush_pending ();
4671 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4675 // first idle adds route children (automation tracks), so we need to redisplay here
4676 _routes->redisplay ();
4683 Editor::_idle_resize (gpointer arg)
4685 return ((Editor*)arg)->idle_resize ();
4689 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4691 if (resize_idle_id < 0) {
4692 resize_idle_id = g_idle_add (_idle_resize, this);
4693 _pending_resize_amount = 0;
4696 /* make a note of the smallest resulting height, so that we can clamp the
4697 lower limit at TimeAxisView::hSmall */
4699 int32_t min_resulting = INT32_MAX;
4701 _pending_resize_amount += h;
4702 _pending_resize_view = view;
4704 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4706 if (selection->tracks.contains (_pending_resize_view)) {
4707 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4708 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4712 if (min_resulting < 0) {
4717 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4718 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4722 /** Handle pending resizing of tracks */
4724 Editor::idle_resize ()
4726 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4728 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4729 selection->tracks.contains (_pending_resize_view)) {
4731 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4732 if (*i != _pending_resize_view) {
4733 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4738 _pending_resize_amount = 0;
4740 _group_tabs->set_dirty ();
4741 resize_idle_id = -1;
4749 ENSURE_GUI_THREAD (*this, &Editor::located);
4751 playhead_cursor->set_position (_session->audible_frame ());
4752 if (_follow_playhead && !_pending_initial_locate) {
4753 reset_x_origin_to_follow_playhead ();
4756 _pending_locate_request = false;
4757 _pending_initial_locate = false;
4761 Editor::region_view_added (RegionView *)
4763 _summary->set_dirty ();
4767 Editor::region_view_removed ()
4769 _summary->set_dirty ();
4773 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4775 TrackViewList::const_iterator j = track_views.begin ();
4776 while (j != track_views.end()) {
4777 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4778 if (rtv && rtv->route() == r) {
4789 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4793 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4794 TimeAxisView* tv = axis_view_from_route (*i);
4805 Editor::handle_new_route (RouteList& routes)
4807 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4809 RouteTimeAxisView *rtv;
4810 list<RouteTimeAxisView*> new_views;
4812 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4813 boost::shared_ptr<Route> route = (*x);
4815 if (route->is_hidden() || route->is_monitor()) {
4819 DataType dt = route->input()->default_type();
4821 if (dt == ARDOUR::DataType::AUDIO) {
4822 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4823 rtv->set_route (route);
4824 } else if (dt == ARDOUR::DataType::MIDI) {
4825 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4826 rtv->set_route (route);
4828 throw unknown_type();
4831 new_views.push_back (rtv);
4832 track_views.push_back (rtv);
4834 rtv->effective_gain_display ();
4836 if (internal_editing()) {
4837 rtv->enter_internal_edit_mode ();
4839 rtv->leave_internal_edit_mode ();
4842 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4843 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4846 _routes->routes_added (new_views);
4847 _summary->routes_added (new_views);
4849 if (show_editor_mixer_when_tracks_arrive) {
4850 show_editor_mixer (true);
4853 editor_list_button.set_sensitive (true);
4857 Editor::timeaxisview_deleted (TimeAxisView *tv)
4859 if (_session && _session->deletion_in_progress()) {
4860 /* the situation is under control */
4864 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4866 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4868 _routes->route_removed (tv);
4870 if (tv == entered_track) {
4874 TimeAxisView::Children c = tv->get_child_list ();
4875 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4876 if (entered_track == i->get()) {
4881 /* remove it from the list of track views */
4883 TrackViewList::iterator i;
4885 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4886 i = track_views.erase (i);
4889 /* update whatever the current mixer strip is displaying, if revelant */
4891 boost::shared_ptr<Route> route;
4894 route = rtav->route ();
4897 if (current_mixer_strip && current_mixer_strip->route() == route) {
4899 TimeAxisView* next_tv;
4901 if (track_views.empty()) {
4903 } else if (i == track_views.end()) {
4904 next_tv = track_views.front();
4911 set_selected_mixer_strip (*next_tv);
4913 /* make the editor mixer strip go away setting the
4914 * button to inactive (which also unticks the menu option)
4917 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4923 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4925 if (apply_to_selection) {
4926 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4928 TrackSelection::iterator j = i;
4931 hide_track_in_display (*i, false);
4936 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4938 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4939 // this will hide the mixer strip
4940 set_selected_mixer_strip (*tv);
4943 _routes->hide_track_in_display (*tv);
4948 Editor::sync_track_view_list_and_routes ()
4950 track_views = TrackViewList (_routes->views ());
4952 _summary->set_dirty ();
4953 _group_tabs->set_dirty ();
4955 return false; // do not call again (until needed)
4959 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
4961 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4966 /** Find a RouteTimeAxisView by the ID of its route */
4968 Editor::get_route_view_by_route_id (const PBD::ID& id) const
4970 RouteTimeAxisView* v;
4972 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
4973 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
4974 if(v->route()->id() == id) {
4984 Editor::fit_route_group (RouteGroup *g)
4986 TrackViewList ts = axis_views_from_routes (g->route_list ());
4991 Editor::consider_auditioning (boost::shared_ptr<Region> region)
4993 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
4996 _session->cancel_audition ();
5000 if (_session->is_auditioning()) {
5001 _session->cancel_audition ();
5002 if (r == last_audition_region) {
5007 _session->audition_region (r);
5008 last_audition_region = r;
5013 Editor::hide_a_region (boost::shared_ptr<Region> r)
5015 r->set_hidden (true);
5019 Editor::show_a_region (boost::shared_ptr<Region> r)
5021 r->set_hidden (false);
5025 Editor::audition_region_from_region_list ()
5027 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5031 Editor::hide_region_from_region_list ()
5033 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5037 Editor::show_region_in_region_list ()
5039 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5043 Editor::step_edit_status_change (bool yn)
5046 start_step_editing ();
5048 stop_step_editing ();
5053 Editor::start_step_editing ()
5055 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5059 Editor::stop_step_editing ()
5061 step_edit_connection.disconnect ();
5065 Editor::check_step_edit ()
5067 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5068 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5070 mtv->check_step_edit ();
5074 return true; // do it again, till we stop
5078 Editor::scroll_press (Direction dir)
5080 ++_scroll_callbacks;
5082 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5083 /* delay the first auto-repeat */
5089 scroll_backward (1);
5097 scroll_tracks_up_line ();
5101 scroll_tracks_down_line ();
5105 /* do hacky auto-repeat */
5106 if (!_scroll_connection.connected ()) {
5108 _scroll_connection = Glib::signal_timeout().connect (
5109 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5112 _scroll_callbacks = 0;
5119 Editor::scroll_release ()
5121 _scroll_connection.disconnect ();
5124 /** Queue a change for the Editor viewport x origin to follow the playhead */
5126 Editor::reset_x_origin_to_follow_playhead ()
5128 framepos_t const frame = playhead_cursor->current_frame;
5130 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5132 if (_session->transport_speed() < 0) {
5134 if (frame > (current_page_frames() / 2)) {
5135 center_screen (frame-(current_page_frames()/2));
5137 center_screen (current_page_frames()/2);
5144 if (frame < leftmost_frame) {
5146 if (_session->transport_rolling()) {
5147 /* rolling; end up with the playhead at the right of the page */
5148 l = frame - current_page_frames ();
5150 /* not rolling: end up with the playhead 1/4 of the way along the page */
5151 l = frame - current_page_frames() / 4;
5155 if (_session->transport_rolling()) {
5156 /* rolling: end up with the playhead on the left of the page */
5159 /* not rolling: end up with the playhead 3/4 of the way along the page */
5160 l = frame - 3 * current_page_frames() / 4;
5168 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5174 Editor::super_rapid_screen_update ()
5176 if (!_session || !_session->engine().running()) {
5180 /* METERING / MIXER STRIPS */
5182 /* update track meters, if required */
5183 if (is_mapped() && meters_running) {
5184 RouteTimeAxisView* rtv;
5185 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5186 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5187 rtv->fast_update ();
5192 /* and any current mixer strip */
5193 if (current_mixer_strip) {
5194 current_mixer_strip->fast_update ();
5197 /* PLAYHEAD AND VIEWPORT */
5199 framepos_t const frame = _session->audible_frame();
5201 /* There are a few reasons why we might not update the playhead / viewport stuff:
5203 * 1. we don't update things when there's a pending locate request, otherwise
5204 * when the editor requests a locate there is a chance that this method
5205 * will move the playhead before the locate request is processed, causing
5207 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5208 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5211 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5213 last_update_frame = frame;
5215 if (!_dragging_playhead) {
5216 playhead_cursor->set_position (frame);
5219 if (!_stationary_playhead) {
5221 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5222 reset_x_origin_to_follow_playhead ();
5227 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5231 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5232 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5233 if (target <= 0.0) {
5236 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5237 target = (target * 0.15) + (current * 0.85);
5243 set_horizontal_position (current);
5252 Editor::session_going_away ()
5254 _have_idled = false;
5256 _session_connections.drop_connections ();
5258 super_rapid_screen_update_connection.disconnect ();
5260 selection->clear ();
5261 cut_buffer->clear ();
5263 clicked_regionview = 0;
5264 clicked_axisview = 0;
5265 clicked_routeview = 0;
5266 entered_regionview = 0;
5268 last_update_frame = 0;
5271 playhead_cursor->canvas_item.hide ();
5273 /* rip everything out of the list displays */
5277 _route_groups->clear ();
5279 /* do this first so that deleting a track doesn't reset cms to null
5280 and thus cause a leak.
5283 if (current_mixer_strip) {
5284 if (current_mixer_strip->get_parent() != 0) {
5285 global_hpacker.remove (*current_mixer_strip);
5287 delete current_mixer_strip;
5288 current_mixer_strip = 0;
5291 /* delete all trackviews */
5293 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5296 track_views.clear ();
5298 zoom_range_clock->set_session (0);
5299 nudge_clock->set_session (0);
5301 editor_list_button.set_active(false);
5302 editor_list_button.set_sensitive(false);
5304 /* clear tempo/meter rulers */
5305 remove_metric_marks ();
5307 clear_marker_display ();
5309 current_bbt_points_begin = current_bbt_points_end;
5311 /* get rid of any existing editor mixer strip */
5313 WindowTitle title(Glib::get_application_name());
5314 title += _("Editor");
5316 set_title (title.get_string());
5318 SessionHandlePtr::session_going_away ();
5323 Editor::show_editor_list (bool yn)
5326 _the_notebook.show ();
5328 _the_notebook.hide ();
5333 Editor::change_region_layering_order (bool from_context_menu)
5335 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5337 if (!clicked_routeview) {
5338 if (layering_order_editor) {
5339 layering_order_editor->hide ();
5344 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5350 boost::shared_ptr<Playlist> pl = track->playlist();
5356 if (layering_order_editor == 0) {
5357 layering_order_editor = new RegionLayeringOrderEditor (*this);
5358 layering_order_editor->set_position (WIN_POS_MOUSE);
5361 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5362 layering_order_editor->maybe_present ();
5366 Editor::update_region_layering_order_editor ()
5368 if (layering_order_editor && layering_order_editor->is_visible ()) {
5369 change_region_layering_order (true);
5374 Editor::setup_fade_images ()
5376 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5377 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5378 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5379 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5380 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5382 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5383 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5384 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5385 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5386 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5388 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5389 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5390 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5391 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5392 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5394 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5395 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5396 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5397 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5398 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5402 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5404 Editor::action_menu_item (std::string const & name)
5406 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5409 return *manage (a->create_menu_item ());
5413 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5415 EventBox* b = manage (new EventBox);
5416 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5417 Label* l = manage (new Label (name));
5421 _the_notebook.append_page (widget, *b);
5425 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5427 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5428 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5431 if (ev->type == GDK_2BUTTON_PRESS) {
5433 /* double-click on a notebook tab shrinks or expands the notebook */
5435 if (_notebook_shrunk) {
5436 if (pre_notebook_shrink_pane_width) {
5437 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5439 _notebook_shrunk = false;
5441 pre_notebook_shrink_pane_width = edit_pane.get_position();
5443 /* this expands the LHS of the edit pane to cover the notebook
5444 PAGE but leaves the tabs visible.
5446 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5447 _notebook_shrunk = true;
5455 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5457 using namespace Menu_Helpers;
5459 MenuList& items = _control_point_context_menu.items ();
5462 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5463 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5464 if (!can_remove_control_point (item)) {
5465 items.back().set_sensitive (false);
5468 _control_point_context_menu.popup (event->button.button, event->button.time);