2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
47 #include <glibmm/miscutils.h>
48 #include <gtkmm/image.h>
49 #include <gdkmm/color.h>
50 #include <gdkmm/bitmap.h>
52 #include "gtkmm2ext/bindings.h"
53 #include "gtkmm2ext/grouped_buttons.h"
54 #include "gtkmm2ext/gtk_ui.h"
55 #include "gtkmm2ext/tearoff.h"
56 #include "gtkmm2ext/utils.h"
57 #include "gtkmm2ext/window_title.h"
58 #include "gtkmm2ext/choice.h"
59 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
61 #include "ardour/audio_diskstream.h"
62 #include "ardour/audio_track.h"
63 #include "ardour/audioplaylist.h"
64 #include "ardour/audioregion.h"
65 #include "ardour/location.h"
66 #include "ardour/midi_region.h"
67 #include "ardour/plugin_manager.h"
68 #include "ardour/profile.h"
69 #include "ardour/route_group.h"
70 #include "ardour/session_directory.h"
71 #include "ardour/session_route.h"
72 #include "ardour/session_state_utils.h"
73 #include "ardour/tempo.h"
74 #include "ardour/utils.h"
75 #include "ardour/session_playlists.h"
76 #include "ardour/audioengine.h"
78 #include "control_protocol/control_protocol.h"
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 "canvas-noevent-text.h"
90 #include "canvas_impl.h"
91 #include "crossfade_edit.h"
92 #include "crossfade_view.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 "mouse_cursors.h"
113 #include "playlist_selector.h"
114 #include "public_editor.h"
115 #include "region_layering_order_editor.h"
116 #include "rgb_macros.h"
117 #include "rhythm_ferret.h"
118 #include "selection.h"
120 #include "simpleline.h"
121 #include "tempo_lines.h"
122 #include "time_axis_view.h"
128 #include "imageframe_socket_handler.h"
132 using namespace ARDOUR;
135 using namespace Glib;
136 using namespace Gtkmm2ext;
137 using namespace Editing;
139 using PBD::internationalize;
141 using Gtkmm2ext::Keyboard;
143 const double Editor::timebar_height = 15.0;
145 static const gchar *_snap_type_strings[] = {
147 N_("Timecode Frames"),
148 N_("Timecode Seconds"),
149 N_("Timecode Minutes"),
177 static const gchar *_snap_mode_strings[] = {
184 static const gchar *_edit_point_strings[] = {
191 static const gchar *_zoom_focus_strings[] = {
201 #ifdef USE_RUBBERBAND
202 static const gchar *_rb_opt_strings[] = {
205 N_("Balanced multitimbral mixture"),
206 N_("Unpitched percussion with stable notes"),
207 N_("Crisp monophonic instrumental"),
208 N_("Unpitched solo percussion"),
209 N_("Resample without preserving pitch"),
215 show_me_the_size (Requisition* r, const char* what)
217 cerr << "size of " << what << " = " << r->width << " x " << r->height << endl;
222 pane_size_watcher (Paned* pane)
224 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
225 it is no longer accessible. so stop that. this doesn't happen on X11,
226 just the quartz backend.
231 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 25;
233 gint pos = pane->get_position ();
235 if (pos > max_width_of_lhs) {
236 pane->set_position (max_width_of_lhs);
242 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
244 /* time display buttons */
245 , minsec_label (_("Mins:Secs"))
246 , bbt_label (_("Bars:Beats"))
247 , timecode_label (_("Timecode"))
248 , samples_label (_("Samples"))
249 , tempo_label (_("Tempo"))
250 , meter_label (_("Meter"))
251 , mark_label (_("Location Markers"))
252 , range_mark_label (_("Range Markers"))
253 , transport_mark_label (_("Loop/Punch Ranges"))
254 , cd_mark_label (_("CD Markers"))
255 , edit_packer (4, 4, true)
257 /* the values here don't matter: layout widgets
258 reset them as needed.
261 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
263 /* tool bar related */
265 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("ZoomRangeClock"), true, false, true))
267 , toolbar_selection_clock_table (2,3)
269 , automation_mode_button (_("mode"))
271 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
272 , midi_panic_button (_("Panic"))
275 , image_socket_listener(0)
280 , nudge_clock (new AudioClock (X_("nudge"), false, X_("NudgeClock"), true, false, true))
281 , meters_running(false)
282 , _pending_locate_request (false)
283 , _pending_initial_locate (false)
284 , _last_cut_copy_source_track (0)
286 , _region_selection_change_updates_region_list (true)
290 /* we are a singleton */
292 PublicEditor::_instance = this;
296 selection = new Selection (this);
297 cut_buffer = new Selection (this);
299 clicked_regionview = 0;
300 clicked_axisview = 0;
301 clicked_routeview = 0;
302 clicked_crossfadeview = 0;
303 clicked_control_point = 0;
304 last_update_frame = 0;
305 pre_press_cursor = 0;
306 _drags = new DragManager (this);
307 current_mixer_strip = 0;
308 current_bbt_points = 0;
311 snap_type_strings = I18N (_snap_type_strings);
312 snap_mode_strings = I18N (_snap_mode_strings);
313 zoom_focus_strings = I18N (_zoom_focus_strings);
314 edit_point_strings = I18N (_edit_point_strings);
315 #ifdef USE_RUBBERBAND
316 rb_opt_strings = I18N (_rb_opt_strings);
320 snap_threshold = 5.0;
321 bbt_beat_subdivision = 4;
324 last_autoscroll_x = 0;
325 last_autoscroll_y = 0;
326 autoscroll_active = false;
327 autoscroll_timeout_tag = -1;
332 current_interthread_info = 0;
333 _show_measures = true;
334 show_gain_after_trim = false;
335 last_item_entered = 0;
337 have_pending_keyboard_selection = false;
338 _follow_playhead = true;
339 _stationary_playhead = false;
340 _xfade_visibility = true;
341 editor_ruler_menu = 0;
342 no_ruler_shown_update = false;
344 range_marker_menu = 0;
345 marker_menu_item = 0;
346 tempo_or_meter_marker_menu = 0;
347 transport_marker_menu = 0;
348 new_transport_marker_menu = 0;
349 editor_mixer_strip_width = Wide;
350 show_editor_mixer_when_tracks_arrive = false;
351 region_edit_menu_split_multichannel_item = 0;
352 region_edit_menu_split_item = 0;
355 current_stepping_trackview = 0;
357 entered_regionview = 0;
359 clear_entered_track = false;
362 button_release_can_deselect = true;
363 _dragging_playhead = false;
364 _dragging_edit_point = false;
365 select_new_marker = false;
367 layering_order_editor = 0;
368 no_save_visual = false;
371 scrubbing_direction = 0;
375 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
376 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
377 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
378 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
379 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
381 _edit_point = EditAtMouse;
382 _internal_editing = false;
383 current_canvas_cursor = 0;
385 frames_per_unit = 2048; /* too early to use reset_zoom () */
387 _scroll_callbacks = 0;
389 zoom_focus = ZoomFocusLeft;
390 set_zoom_focus (ZoomFocusLeft);
391 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
393 bbt_label.set_name ("EditorTimeButton");
394 bbt_label.set_size_request (-1, (int)timebar_height);
395 bbt_label.set_alignment (1.0, 0.5);
396 bbt_label.set_padding (5,0);
398 bbt_label.set_no_show_all();
399 minsec_label.set_name ("EditorTimeButton");
400 minsec_label.set_size_request (-1, (int)timebar_height);
401 minsec_label.set_alignment (1.0, 0.5);
402 minsec_label.set_padding (5,0);
403 minsec_label.hide ();
404 minsec_label.set_no_show_all();
405 timecode_label.set_name ("EditorTimeButton");
406 timecode_label.set_size_request (-1, (int)timebar_height);
407 timecode_label.set_alignment (1.0, 0.5);
408 timecode_label.set_padding (5,0);
409 timecode_label.hide ();
410 timecode_label.set_no_show_all();
411 samples_label.set_name ("EditorTimeButton");
412 samples_label.set_size_request (-1, (int)timebar_height);
413 samples_label.set_alignment (1.0, 0.5);
414 samples_label.set_padding (5,0);
415 samples_label.hide ();
416 samples_label.set_no_show_all();
418 tempo_label.set_name ("EditorTimeButton");
419 tempo_label.set_size_request (-1, (int)timebar_height);
420 tempo_label.set_alignment (1.0, 0.5);
421 tempo_label.set_padding (5,0);
423 tempo_label.set_no_show_all();
425 meter_label.set_name ("EditorTimeButton");
426 meter_label.set_size_request (-1, (int)timebar_height);
427 meter_label.set_alignment (1.0, 0.5);
428 meter_label.set_padding (5,0);
430 meter_label.set_no_show_all();
432 mark_label.set_name ("EditorTimeButton");
433 mark_label.set_size_request (-1, (int)timebar_height);
434 mark_label.set_alignment (1.0, 0.5);
435 mark_label.set_padding (5,0);
437 mark_label.set_no_show_all();
439 cd_mark_label.set_name ("EditorTimeButton");
440 cd_mark_label.set_size_request (-1, (int)timebar_height);
441 cd_mark_label.set_alignment (1.0, 0.5);
442 cd_mark_label.set_padding (5,0);
443 cd_mark_label.hide();
444 cd_mark_label.set_no_show_all();
446 range_mark_label.set_name ("EditorTimeButton");
447 range_mark_label.set_size_request (-1, (int)timebar_height);
448 range_mark_label.set_alignment (1.0, 0.5);
449 range_mark_label.set_padding (5,0);
450 range_mark_label.hide();
451 range_mark_label.set_no_show_all();
453 transport_mark_label.set_name ("EditorTimeButton");
454 transport_mark_label.set_size_request (-1, (int)timebar_height);
455 transport_mark_label.set_alignment (1.0, 0.5);
456 transport_mark_label.set_padding (5,0);
457 transport_mark_label.hide();
458 transport_mark_label.set_no_show_all();
460 initialize_rulers ();
461 initialize_canvas ();
463 _summary = new EditorSummary (this);
465 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
466 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
468 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
470 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
471 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
473 edit_controls_vbox.set_spacing (0);
474 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
475 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
477 HBox* h = manage (new HBox);
478 _group_tabs = new EditorGroupTabs (this);
479 h->pack_start (*_group_tabs, PACK_SHRINK);
480 h->pack_start (edit_controls_vbox);
481 controls_layout.add (*h);
483 controls_layout.set_name ("EditControlsBase");
484 controls_layout.add_events (Gdk::SCROLL_MASK);
485 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
487 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
488 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
490 _cursors = new MouseCursors;
492 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
493 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
494 0.0, 1.0, 100.0, 1.0));
496 pad_line_1->property_color_rgba() = 0xFF0000FF;
501 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
502 time_canvas_vbox.set_size_request (-1, -1);
504 ruler_label_event_box.add (ruler_label_vbox);
505 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
506 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
508 time_button_event_box.add (time_button_vbox);
509 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 /* these enable us to have a dedicated window (for cursor setting, etc.)
513 for the canvas areas.
516 track_canvas_event_box.add (*track_canvas);
518 time_canvas_event_box.add (time_canvas_vbox);
519 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
521 edit_packer.set_col_spacings (0);
522 edit_packer.set_row_spacings (0);
523 edit_packer.set_homogeneous (false);
524 edit_packer.set_border_width (0);
525 edit_packer.set_name ("EditorWindow");
527 /* labels for the rulers */
528 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
529 /* labels for the marker "tracks" */
530 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
532 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
534 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
536 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
538 bottom_hbox.set_border_width (2);
539 bottom_hbox.set_spacing (3);
541 _route_groups = new EditorRouteGroups (this);
542 _routes = new EditorRoutes (this);
543 _regions = new EditorRegions (this);
544 _snapshots = new EditorSnapshots (this);
545 _locations = new EditorLocations (this);
547 add_notebook_page (_("Regions"), _regions->widget ());
548 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
549 add_notebook_page (_("Snapshots"), _snapshots->widget ());
550 add_notebook_page (_("Route Groups"), _route_groups->widget ());
551 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
553 _the_notebook.set_show_tabs (true);
554 _the_notebook.set_scrollable (true);
555 _the_notebook.popup_disable ();
556 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
557 _the_notebook.show_all ();
559 post_maximal_editor_width = 0;
560 post_maximal_horizontal_pane_position = 0;
561 post_maximal_editor_height = 0;
562 post_maximal_vertical_pane_position = 0;
563 _notebook_shrunk = false;
565 editor_summary_pane.pack1(edit_packer);
567 Button* summary_arrows_left_left = manage (new Button);
568 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
569 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
570 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
572 Button* summary_arrows_left_right = manage (new Button);
573 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
574 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
575 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 VBox* summary_arrows_left = manage (new VBox);
578 summary_arrows_left->pack_start (*summary_arrows_left_left);
579 summary_arrows_left->pack_start (*summary_arrows_left_right);
581 Button* summary_arrows_right_up = manage (new Button);
582 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
583 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
584 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
586 Button* summary_arrows_right_down = manage (new Button);
587 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
588 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
589 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
591 VBox* summary_arrows_right = manage (new VBox);
592 summary_arrows_right->pack_start (*summary_arrows_right_up);
593 summary_arrows_right->pack_start (*summary_arrows_right_down);
595 Frame* summary_frame = manage (new Frame);
596 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
598 summary_frame->add (*_summary);
599 summary_frame->show ();
601 _summary_hbox.pack_start (*summary_arrows_left, false, false);
602 _summary_hbox.pack_start (*summary_frame, true, true);
603 _summary_hbox.pack_start (*summary_arrows_right, false, false);
605 editor_summary_pane.pack2 (_summary_hbox);
607 edit_pane.pack1 (editor_summary_pane, true, true);
608 edit_pane.pack2 (_the_notebook, false, true);
610 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
612 /* XXX: editor_summary_pane might need similar special OS X treatment to the edit_pane */
614 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
616 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
617 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
619 top_hbox.pack_start (toolbar_frame);
621 HBox *hbox = manage (new HBox);
622 hbox->pack_start (edit_pane, true, true);
624 global_vpacker.pack_start (top_hbox, false, false);
625 global_vpacker.pack_start (*hbox, true, true);
627 global_hpacker.pack_start (global_vpacker, true, true);
629 set_name ("EditorWindow");
630 add_accel_group (ActionManager::ui_manager->get_accel_group());
632 status_bar_hpacker.show ();
634 vpacker.pack_end (status_bar_hpacker, false, false);
635 vpacker.pack_end (global_hpacker, true, true);
637 /* register actions now so that set_state() can find them and set toggles/checks etc */
642 setup_midi_toolbar ();
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 set_edit_point_preference (EditAtMouse, true);
652 _playlist_selector = new PlaylistSelector();
653 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
655 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), ui_bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
659 nudge_forward_button.add (*(manage (new Image (::get_icon("nudge_right")))));
660 nudge_backward_button.add (*(manage (new Image (::get_icon("nudge_left")))));
662 nudge_forward_button.set_name ("TransportButton");
663 nudge_backward_button.set_name ("TransportButton");
665 fade_context_menu.set_name ("ArdourContextMenu");
667 /* icons, titles, WM stuff */
669 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
670 Glib::RefPtr<Gdk::Pixbuf> icon;
672 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
673 window_icons.push_back (icon);
675 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
676 window_icons.push_back (icon);
678 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
679 window_icons.push_back (icon);
681 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
682 window_icons.push_back (icon);
684 if (!window_icons.empty()) {
685 // set_icon_list (window_icons);
686 set_default_icon_list (window_icons);
689 WindowTitle title(Glib::get_application_name());
690 title += _("Editor");
691 set_title (title.get_string());
692 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
695 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
697 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
698 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
700 /* allow external control surfaces/protocols to do various things */
702 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
703 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
704 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
705 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), ui_bind (&Editor::control_scroll, this, _1), gui_context());
706 ControlProtocol::SelectByRID.connect (*this, invalidator (*this), ui_bind (&Editor::control_select, this, _1), gui_context());
707 BasicUI::AccessAction.connect (*this, invalidator (*this), ui_bind (&Editor::access_action, this, _1, _2), gui_context());
709 /* problematic: has to return a value and thus cannot be x-thread */
711 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
713 Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
715 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), ui_bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
717 _ignore_region_action = false;
718 _last_region_menu_was_main = false;
719 _popup_region_menu_item = 0;
721 _show_marker_lines = false;
722 _over_region_trim_target = false;
724 /* Button bindings */
726 button_bindings = new Bindings;
728 XMLNode* node = button_settings();
730 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
731 button_bindings->load (**i);
738 setup_fade_images ();
744 if(image_socket_listener) {
745 if(image_socket_listener->is_connected())
747 image_socket_listener->close_connection() ;
750 delete image_socket_listener ;
751 image_socket_listener = 0 ;
755 delete button_bindings;
757 delete _route_groups;
763 Editor::button_settings () const
765 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
766 XMLNode* node = find_named_node (*settings, X_("Buttons"));
769 cerr << "new empty Button node\n";
770 node = new XMLNode (X_("Buttons"));
777 Editor::add_toplevel_controls (Container& cont)
779 vpacker.pack_start (cont, false, false);
784 Editor::catch_vanishing_regionview (RegionView *rv)
786 /* note: the selection will take care of the vanishing
787 audioregionview by itself.
790 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
794 if (clicked_regionview == rv) {
795 clicked_regionview = 0;
798 if (entered_regionview == rv) {
799 set_entered_regionview (0);
802 if (!_all_region_actions_sensitized) {
803 sensitize_all_region_actions (true);
806 _over_region_trim_target = false;
810 Editor::set_entered_regionview (RegionView* rv)
812 if (rv == entered_regionview) {
816 if (entered_regionview) {
817 entered_regionview->exited ();
820 if ((entered_regionview = rv) != 0) {
821 entered_regionview->entered (internal_editing ());
824 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
825 /* This RegionView entry might have changed what region actions
826 are allowed, so sensitize them all in case a key is pressed.
828 sensitize_all_region_actions (true);
833 Editor::set_entered_track (TimeAxisView* tav)
836 entered_track->exited ();
839 if ((entered_track = tav) != 0) {
840 entered_track->entered ();
845 Editor::show_window ()
847 if (!is_visible ()) {
850 /* XXX: this is a bit unfortunate; it would probably
851 be nicer if we could just call show () above rather
852 than needing the show_all ()
855 /* re-hide stuff if necessary */
856 editor_list_button_toggled ();
857 parameter_changed ("show-summary");
858 parameter_changed ("show-group-tabs");
859 parameter_changed ("show-zoom-tools");
861 /* now reset all audio_time_axis heights, because widgets might need
867 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
868 tv = (static_cast<TimeAxisView*>(*i));
872 if (current_mixer_strip) {
873 current_mixer_strip->hide_things ();
881 Editor::instant_save ()
883 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
888 _session->add_instant_xml(get_state());
890 Config->add_instant_xml(get_state());
895 Editor::zoom_adjustment_changed ()
901 double fpu = zoom_range_clock->current_duration() / _canvas_width;
905 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
906 } else if (fpu > _session->current_end_frame() / _canvas_width) {
907 fpu = _session->current_end_frame() / _canvas_width;
908 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
915 Editor::control_select (uint32_t rid)
917 /* handles the (static) signal from the ControlProtocol class that
918 * requests setting the selected track to a given RID
925 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
931 TimeAxisView* tav = axis_view_from_route (r);
934 selection->set (tav);
936 selection->clear_tracks ();
941 Editor::control_scroll (float fraction)
943 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
949 double step = fraction * current_page_frames();
952 _control_scroll_target is an optional<T>
954 it acts like a pointer to an framepos_t, with
955 a operator conversion to boolean to check
956 that it has a value could possibly use
957 playhead_cursor->current_frame to store the
958 value and a boolean in the class to know
959 when it's out of date
962 if (!_control_scroll_target) {
963 _control_scroll_target = _session->transport_frame();
964 _dragging_playhead = true;
967 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
968 *_control_scroll_target = 0;
969 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
970 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
972 *_control_scroll_target += (framepos_t) floor (step);
975 /* move visuals, we'll catch up with it later */
977 playhead_cursor->set_position (*_control_scroll_target);
978 UpdateAllTransportClocks (*_control_scroll_target);
980 if (*_control_scroll_target > (current_page_frames() / 2)) {
981 /* try to center PH in window */
982 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
988 Now we do a timeout to actually bring the session to the right place
989 according to the playhead. This is to avoid reading disk buffers on every
990 call to control_scroll, which is driven by ScrollTimeline and therefore
991 probably by a control surface wheel which can generate lots of events.
993 /* cancel the existing timeout */
995 control_scroll_connection.disconnect ();
997 /* add the next timeout */
999 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1003 Editor::deferred_control_scroll (framepos_t /*target*/)
1005 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1006 // reset for next stream
1007 _control_scroll_target = boost::none;
1008 _dragging_playhead = false;
1013 Editor::access_action (std::string action_group, std::string action_item)
1019 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1022 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1030 Editor::on_realize ()
1032 Window::on_realize ();
1037 Editor::map_position_change (framepos_t frame)
1039 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1041 if (_session == 0) {
1045 if (_follow_playhead) {
1046 center_screen (frame);
1049 playhead_cursor->set_position (frame);
1053 Editor::center_screen (framepos_t frame)
1055 double page = _canvas_width * frames_per_unit;
1057 /* if we're off the page, then scroll.
1060 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1061 center_screen_internal (frame, page);
1066 Editor::center_screen_internal (framepos_t frame, float page)
1071 frame -= (framepos_t) page;
1076 reset_x_origin (frame);
1081 Editor::update_title ()
1083 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1086 bool dirty = _session->dirty();
1088 string session_name;
1090 if (_session->snap_name() != _session->name()) {
1091 session_name = _session->snap_name();
1093 session_name = _session->name();
1097 session_name = "*" + session_name;
1100 WindowTitle title(session_name);
1101 title += Glib::get_application_name();
1102 set_title (title.get_string());
1107 Editor::set_session (Session *t)
1109 SessionHandlePtr::set_session (t);
1115 zoom_range_clock->set_session (_session);
1116 _playlist_selector->set_session (_session);
1117 nudge_clock->set_session (_session);
1118 _summary->set_session (_session);
1119 _group_tabs->set_session (_session);
1120 _route_groups->set_session (_session);
1121 _regions->set_session (_session);
1122 _snapshots->set_session (_session);
1123 _routes->set_session (_session);
1124 _locations->set_session (_session);
1126 if (rhythm_ferret) {
1127 rhythm_ferret->set_session (_session);
1130 if (analysis_window) {
1131 analysis_window->set_session (_session);
1135 sfbrowser->set_session (_session);
1138 compute_fixed_ruler_scale ();
1140 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1141 set_state (*node, Stateful::loading_state_version);
1143 /* catch up with the playhead */
1145 _session->request_locate (playhead_cursor->current_frame);
1146 _pending_initial_locate = true;
1150 /* These signals can all be emitted by a non-GUI thread. Therefore the
1151 handlers for them must not attempt to directly interact with the GUI,
1152 but use Gtkmm2ext::UI::instance()->call_slot();
1155 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), ui_bind(&Editor::step_edit_status_change, this, _1), gui_context());
1156 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1157 _session->PositionChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::map_position_change, this, _1), gui_context());
1158 _session->RouteAdded.connect (_session_connections, invalidator (*this), ui_bind (&Editor::handle_new_route, this, _1), gui_context());
1159 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1160 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::tempo_map_changed, this, _1), gui_context());
1161 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1162 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::parameter_changed, this, _1), gui_context());
1163 _session->StateSaved.connect (_session_connections, invalidator (*this), ui_bind (&Editor::session_state_saved, this, _1), gui_context());
1164 _session->locations()->added.connect (_session_connections, invalidator (*this), ui_bind (&Editor::add_new_location, this, _1), gui_context());
1165 _session->locations()->removed.connect (_session_connections, invalidator (*this), ui_bind (&Editor::location_gone, this, _1), gui_context());
1166 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1167 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), ui_bind (&Editor::refresh_location_display, this), gui_context());
1168 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1170 if (Profile->get_sae()) {
1171 Timecode::BBT_Time bbt;
1175 framepos_t pos = _session->tempo_map().bbt_duration_at (0, bbt, 1);
1176 nudge_clock->set_mode(AudioClock::BBT);
1177 nudge_clock->set (pos, true, 0, AudioClock::BBT);
1180 nudge_clock->set (_session->frame_rate() * 5, true, 0, AudioClock::Timecode); // default of 5 seconds
1183 playhead_cursor->canvas_item.show ();
1185 Location* loc = _session->locations()->auto_loop_location();
1187 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1189 if (loc->start() == loc->end()) {
1190 loc->set_end (loc->start() + 1);
1193 _session->locations()->add (loc, false);
1194 _session->set_auto_loop_location (loc);
1197 loc->set_name (_("Loop"));
1200 loc = _session->locations()->auto_punch_location();
1203 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1205 if (loc->start() == loc->end()) {
1206 loc->set_end (loc->start() + 1);
1209 _session->locations()->add (loc, false);
1210 _session->set_auto_punch_location (loc);
1213 loc->set_name (_("Punch"));
1216 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1217 Config->map_parameters (pc);
1218 _session->config.map_parameters (pc);
1220 refresh_location_display ();
1222 restore_ruler_visibility ();
1223 //tempo_map_changed (PropertyChange (0));
1224 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1226 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1227 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1230 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1231 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1234 switch (_snap_type) {
1235 case SnapToRegionStart:
1236 case SnapToRegionEnd:
1237 case SnapToRegionSync:
1238 case SnapToRegionBoundary:
1239 build_region_boundary_cache ();
1246 /* register for undo history */
1247 _session->register_with_memento_command_factory(_id, this);
1249 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1251 start_updating_meters ();
1255 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1257 if (a->get_name() == "RegionMenu") {
1258 /* When the main menu's region menu is opened, we setup the actions so that they look right
1259 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1260 so we resensitize all region actions when the entered regionview or the region selection
1261 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1262 happens after the region context menu is opened. So we set a flag here, too.
1266 sensitize_the_right_region_actions ();
1267 _last_region_menu_was_main = true;
1271 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1273 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1275 using namespace Menu_Helpers;
1276 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1279 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1283 MenuList& items (fade_context_menu.items());
1287 switch (item_type) {
1289 case FadeInHandleItem:
1290 if (arv->audio_region()->fade_in_active()) {
1291 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1293 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1296 items.push_back (SeparatorElem());
1298 if (Profile->get_sae()) {
1300 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1301 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1308 *_fade_in_images[FadeLinear],
1309 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1313 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1318 *_fade_in_images[FadeFast],
1319 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1322 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1327 *_fade_in_images[FadeLogB],
1328 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogB)
1331 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1336 *_fade_in_images[FadeLogA],
1337 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLogA)
1340 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1345 *_fade_in_images[FadeSlow],
1346 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1349 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1355 case FadeOutHandleItem:
1356 if (arv->audio_region()->fade_out_active()) {
1357 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1359 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1362 items.push_back (SeparatorElem());
1364 if (Profile->get_sae()) {
1365 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1366 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1372 *_fade_out_images[FadeLinear],
1373 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1377 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1382 *_fade_out_images[FadeFast],
1383 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1386 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1391 *_fade_out_images[FadeLogB],
1392 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogA)
1395 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1400 *_fade_out_images[FadeLogA],
1401 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLogB)
1404 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1409 *_fade_out_images[FadeSlow],
1410 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1413 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1419 fatal << _("programming error: ")
1420 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1425 fade_context_menu.popup (button, time);
1429 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1431 using namespace Menu_Helpers;
1432 Menu* (Editor::*build_menu_function)();
1435 switch (item_type) {
1437 case RegionViewName:
1438 case RegionViewNameHighlight:
1439 case LeftFrameHandle:
1440 case RightFrameHandle:
1441 if (with_selection) {
1442 build_menu_function = &Editor::build_track_selection_context_menu;
1444 build_menu_function = &Editor::build_track_region_context_menu;
1449 if (with_selection) {
1450 build_menu_function = &Editor::build_track_selection_context_menu;
1452 build_menu_function = &Editor::build_track_context_menu;
1456 case CrossfadeViewItem:
1457 build_menu_function = &Editor::build_track_crossfade_context_menu;
1461 if (clicked_routeview->track()) {
1462 build_menu_function = &Editor::build_track_context_menu;
1464 build_menu_function = &Editor::build_track_bus_context_menu;
1469 /* probably shouldn't happen but if it does, we don't care */
1473 menu = (this->*build_menu_function)();
1474 menu->set_name ("ArdourContextMenu");
1476 /* now handle specific situations */
1478 switch (item_type) {
1480 case RegionViewName:
1481 case RegionViewNameHighlight:
1482 case LeftFrameHandle:
1483 case RightFrameHandle:
1484 if (!with_selection) {
1485 if (region_edit_menu_split_item) {
1486 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1487 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1489 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1492 if (region_edit_menu_split_multichannel_item) {
1493 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1494 region_edit_menu_split_multichannel_item->set_sensitive (true);
1496 region_edit_menu_split_multichannel_item->set_sensitive (false);
1505 case CrossfadeViewItem:
1512 /* probably shouldn't happen but if it does, we don't care */
1516 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1518 /* Bounce to disk */
1520 using namespace Menu_Helpers;
1521 MenuList& edit_items = menu->items();
1523 edit_items.push_back (SeparatorElem());
1525 switch (clicked_routeview->audio_track()->freeze_state()) {
1526 case AudioTrack::NoFreeze:
1527 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1530 case AudioTrack::Frozen:
1531 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1534 case AudioTrack::UnFrozen:
1535 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1541 if (item_type == StreamItem && clicked_routeview) {
1542 clicked_routeview->build_underlay_menu(menu);
1545 /* When the region menu is opened, we setup the actions so that they look right
1548 sensitize_the_right_region_actions ();
1549 _last_region_menu_was_main = false;
1551 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1552 menu->popup (button, time);
1556 Editor::build_track_context_menu ()
1558 using namespace Menu_Helpers;
1560 MenuList& edit_items = track_context_menu.items();
1563 add_dstream_context_items (edit_items);
1564 return &track_context_menu;
1568 Editor::build_track_bus_context_menu ()
1570 using namespace Menu_Helpers;
1572 MenuList& edit_items = track_context_menu.items();
1575 add_bus_context_items (edit_items);
1576 return &track_context_menu;
1580 Editor::build_track_region_context_menu ()
1582 using namespace Menu_Helpers;
1583 MenuList& edit_items = track_region_context_menu.items();
1586 /* we've just cleared the track region context menu, so the menu that these
1587 two items were on will have disappeared; stop them dangling.
1589 region_edit_menu_split_item = 0;
1590 region_edit_menu_split_multichannel_item = 0;
1592 /* we might try to use items that are currently attached to a crossfade menu,
1595 track_crossfade_context_menu.items().clear ();
1597 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1600 boost::shared_ptr<Track> tr;
1601 boost::shared_ptr<Playlist> pl;
1603 if ((tr = rtv->track())) {
1604 add_region_context_items (edit_items, tr);
1608 add_dstream_context_items (edit_items);
1610 return &track_region_context_menu;
1614 Editor::build_track_crossfade_context_menu ()
1616 using namespace Menu_Helpers;
1617 MenuList& edit_items = track_crossfade_context_menu.items();
1618 edit_items.clear ();
1620 /* we might try to use items that are currently attached to a crossfade menu,
1623 track_region_context_menu.items().clear ();
1625 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
1628 boost::shared_ptr<Track> tr;
1629 boost::shared_ptr<Playlist> pl;
1630 boost::shared_ptr<AudioPlaylist> apl;
1632 if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
1634 AudioPlaylist::Crossfades xfades;
1638 /* The xfade menu is a bit of a special case, as we always use the mouse position
1639 to decide whether or not to display it (rather than the edit point). No particularly
1640 strong reasons for this, other than it is a bit surprising to right-click on a xfade
1643 mouse_frame (where, ignored);
1644 apl->crossfades_at (where, xfades);
1646 bool const many = xfades.size() > 1;
1648 for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
1649 add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
1652 add_region_context_items (edit_items, tr);
1656 add_dstream_context_items (edit_items);
1658 return &track_crossfade_context_menu;
1662 Editor::analyze_region_selection ()
1664 if (analysis_window == 0) {
1665 analysis_window = new AnalysisWindow();
1668 analysis_window->set_session(_session);
1670 analysis_window->show_all();
1673 analysis_window->set_regionmode();
1674 analysis_window->analyze();
1676 analysis_window->present();
1680 Editor::analyze_range_selection()
1682 if (analysis_window == 0) {
1683 analysis_window = new AnalysisWindow();
1686 analysis_window->set_session(_session);
1688 analysis_window->show_all();
1691 analysis_window->set_rangemode();
1692 analysis_window->analyze();
1694 analysis_window->present();
1698 Editor::build_track_selection_context_menu ()
1700 using namespace Menu_Helpers;
1701 MenuList& edit_items = track_selection_context_menu.items();
1702 edit_items.clear ();
1704 add_selection_context_items (edit_items);
1705 // edit_items.push_back (SeparatorElem());
1706 // add_dstream_context_items (edit_items);
1708 return &track_selection_context_menu;
1711 /** Add context menu items relevant to crossfades.
1712 * @param edit_items List to add the items to.
1715 Editor::add_crossfade_context_items (AudioStreamView* /*view*/, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
1717 using namespace Menu_Helpers;
1718 Menu *xfade_menu = manage (new Menu);
1719 MenuList& items = xfade_menu->items();
1720 xfade_menu->set_name ("ArdourContextMenu");
1723 if (xfade->active()) {
1729 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_active), boost::weak_ptr<Crossfade> (xfade))));
1730 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun(*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade))));
1732 if (xfade->can_follow_overlap()) {
1734 if (xfade->following_overlap()) {
1735 str = _("Convert to Short");
1737 str = _("Convert to Full");
1740 items.push_back (MenuElem (str, sigc::bind (sigc::mem_fun(*this, &Editor::toggle_xfade_length), xfade)));
1744 str = xfade->out()->name();
1746 str += xfade->in()->name();
1748 str = _("Crossfade");
1751 edit_items.push_back (MenuElem (str, *xfade_menu));
1752 edit_items.push_back (SeparatorElem());
1756 Editor::xfade_edit_left_region ()
1758 if (clicked_crossfadeview) {
1759 clicked_crossfadeview->left_view.show_region_editor ();
1764 Editor::xfade_edit_right_region ()
1766 if (clicked_crossfadeview) {
1767 clicked_crossfadeview->right_view.show_region_editor ();
1772 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1774 using namespace Menu_Helpers;
1776 /* OK, stick the region submenu at the top of the list, and then add
1780 RegionSelection rs = get_regions_from_selection_and_entered ();
1782 string::size_type pos = 0;
1783 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1785 /* we have to hack up the region name because "_" has a special
1786 meaning for menu titles.
1789 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1790 menu_item_name.replace (pos, 1, "__");
1794 if (_popup_region_menu_item == 0) {
1795 _popup_region_menu_item = new MenuItem (menu_item_name);
1796 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1797 _popup_region_menu_item->show ();
1799 _popup_region_menu_item->set_label (menu_item_name);
1802 /* Use the mouse position rather than the edit point to decide whether to show the `choose top region'
1803 dialogue. If we use the edit point it gets a bit messy because the user still has to click over
1804 *some* region in order to get the region context menu stuff to be displayed at all.
1809 mouse_frame (mouse, ignored);
1811 edit_items.push_back (*_popup_region_menu_item);
1812 if (track->playlist()->count_regions_at (mouse) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1813 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region")->create_menu_item ()));
1815 edit_items.push_back (SeparatorElem());
1818 /** Add context menu items relevant to selection ranges.
1819 * @param edit_items List to add the items to.
1822 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1824 using namespace Menu_Helpers;
1826 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1827 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1829 edit_items.push_back (SeparatorElem());
1830 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1832 edit_items.push_back (SeparatorElem());
1834 edit_items.push_back (
1836 _("Move Range Start to Previous Region Boundary"),
1837 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1841 edit_items.push_back (
1843 _("Move Range Start to Next Region Boundary"),
1844 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1848 edit_items.push_back (
1850 _("Move Range End to Previous Region Boundary"),
1851 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1855 edit_items.push_back (
1857 _("Move Range End to Next Region Boundary"),
1858 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1862 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1864 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1866 edit_items.push_back (SeparatorElem());
1867 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1869 edit_items.push_back (SeparatorElem());
1870 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1871 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1873 edit_items.push_back (SeparatorElem());
1874 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1876 edit_items.push_back (SeparatorElem());
1877 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1878 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1879 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_dialog), false)));
1881 edit_items.push_back (SeparatorElem());
1882 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1883 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1884 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1885 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1886 edit_items.push_back (MenuElem (_("Export Range"), sigc::mem_fun(*this, &Editor::export_selection)));
1891 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1893 using namespace Menu_Helpers;
1897 Menu *play_menu = manage (new Menu);
1898 MenuList& play_items = play_menu->items();
1899 play_menu->set_name ("ArdourContextMenu");
1901 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1902 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1903 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1904 play_items.push_back (SeparatorElem());
1905 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1907 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1911 Menu *select_menu = manage (new Menu);
1912 MenuList& select_items = select_menu->items();
1913 select_menu->set_name ("ArdourContextMenu");
1915 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1916 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1917 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1918 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1919 select_items.push_back (SeparatorElem());
1920 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1921 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1922 select_items.push_back (SeparatorElem());
1923 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1924 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1925 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1926 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1927 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1928 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1929 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1931 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1935 Menu *cutnpaste_menu = manage (new Menu);
1936 MenuList& cutnpaste_items = cutnpaste_menu->items();
1937 cutnpaste_menu->set_name ("ArdourContextMenu");
1939 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1940 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1941 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
1943 cutnpaste_items.push_back (SeparatorElem());
1945 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1946 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1948 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1950 /* Adding new material */
1952 edit_items.push_back (SeparatorElem());
1953 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1954 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1958 Menu *nudge_menu = manage (new Menu());
1959 MenuList& nudge_items = nudge_menu->items();
1960 nudge_menu->set_name ("ArdourContextMenu");
1962 edit_items.push_back (SeparatorElem());
1963 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1964 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1965 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1966 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
1968 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
1972 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
1974 using namespace Menu_Helpers;
1978 Menu *play_menu = manage (new Menu);
1979 MenuList& play_items = play_menu->items();
1980 play_menu->set_name ("ArdourContextMenu");
1982 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1983 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1984 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1988 Menu *select_menu = manage (new Menu);
1989 MenuList& select_items = select_menu->items();
1990 select_menu->set_name ("ArdourContextMenu");
1992 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1993 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1994 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1995 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1996 select_items.push_back (SeparatorElem());
1997 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1998 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1999 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2000 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2002 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2006 Menu *cutnpaste_menu = manage (new Menu);
2007 MenuList& cutnpaste_items = cutnpaste_menu->items();
2008 cutnpaste_menu->set_name ("ArdourContextMenu");
2010 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2011 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2012 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f)));
2014 Menu *nudge_menu = manage (new Menu());
2015 MenuList& nudge_items = nudge_menu->items();
2016 nudge_menu->set_name ("ArdourContextMenu");
2018 edit_items.push_back (SeparatorElem());
2019 nudge_items.push_back (MenuElem (_("Nudge Entire Track Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2020 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Forward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2021 nudge_items.push_back (MenuElem (_("Nudge Entire Track Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2022 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Backward"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2024 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2028 Editor::snap_type() const
2034 Editor::snap_mode() const
2040 Editor::set_snap_to (SnapType st)
2042 unsigned int snap_ind = (unsigned int)st;
2046 if (snap_ind > snap_type_strings.size() - 1) {
2048 _snap_type = (SnapType)snap_ind;
2051 string str = snap_type_strings[snap_ind];
2053 if (str != snap_type_selector.get_active_text()) {
2054 snap_type_selector.set_active_text (str);
2059 switch (_snap_type) {
2060 case SnapToBeatDiv32:
2061 case SnapToBeatDiv28:
2062 case SnapToBeatDiv24:
2063 case SnapToBeatDiv20:
2064 case SnapToBeatDiv16:
2065 case SnapToBeatDiv14:
2066 case SnapToBeatDiv12:
2067 case SnapToBeatDiv10:
2068 case SnapToBeatDiv8:
2069 case SnapToBeatDiv7:
2070 case SnapToBeatDiv6:
2071 case SnapToBeatDiv5:
2072 case SnapToBeatDiv4:
2073 case SnapToBeatDiv3:
2074 case SnapToBeatDiv2:
2075 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames());
2076 update_tempo_based_rulers ();
2079 case SnapToRegionStart:
2080 case SnapToRegionEnd:
2081 case SnapToRegionSync:
2082 case SnapToRegionBoundary:
2083 build_region_boundary_cache ();
2091 SnapChanged (); /* EMIT SIGNAL */
2095 Editor::set_snap_mode (SnapMode mode)
2098 string str = snap_mode_strings[(int)mode];
2100 if (str != snap_mode_selector.get_active_text ()) {
2101 snap_mode_selector.set_active_text (str);
2107 Editor::set_edit_point_preference (EditPoint ep, bool force)
2109 bool changed = (_edit_point != ep);
2112 string str = edit_point_strings[(int)ep];
2114 if (str != edit_point_selector.get_active_text ()) {
2115 edit_point_selector.set_active_text (str);
2118 set_canvas_cursor ();
2120 if (!force && !changed) {
2124 const char* action=NULL;
2126 switch (_edit_point) {
2127 case EditAtPlayhead:
2128 action = "edit-at-playhead";
2130 case EditAtSelectedMarker:
2131 action = "edit-at-marker";
2134 action = "edit-at-mouse";
2138 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2140 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2144 bool in_track_canvas;
2146 if (!mouse_frame (foo, in_track_canvas)) {
2147 in_track_canvas = false;
2150 reset_canvas_action_sensitivity (in_track_canvas);
2156 Editor::set_state (const XMLNode& node, int /*version*/)
2158 const XMLProperty* prop;
2163 if ((prop = node.property ("id")) != 0) {
2164 _id = prop->value ();
2167 g.base_width = default_width;
2168 g.base_height = default_height;
2172 if ((geometry = find_named_node (node, "geometry")) != 0) {
2176 if ((prop = geometry->property("x_size")) == 0) {
2177 prop = geometry->property ("x-size");
2180 g.base_width = atoi(prop->value());
2182 if ((prop = geometry->property("y_size")) == 0) {
2183 prop = geometry->property ("y-size");
2186 g.base_height = atoi(prop->value());
2189 if ((prop = geometry->property ("x_pos")) == 0) {
2190 prop = geometry->property ("x-pos");
2193 x = atoi (prop->value());
2196 if ((prop = geometry->property ("y_pos")) == 0) {
2197 prop = geometry->property ("y-pos");
2200 y = atoi (prop->value());
2204 set_default_size (g.base_width, g.base_height);
2207 if (_session && (prop = node.property ("playhead"))) {
2209 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2210 playhead_cursor->set_position (pos);
2212 playhead_cursor->set_position (0);
2215 if ((prop = node.property ("mixer-width"))) {
2216 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2219 if ((prop = node.property ("zoom-focus"))) {
2220 set_zoom_focus ((ZoomFocus) atoi (prop->value()));
2223 if ((prop = node.property ("zoom"))) {
2224 reset_zoom (PBD::atof (prop->value()));
2226 reset_zoom (frames_per_unit);
2229 if ((prop = node.property ("snap-to"))) {
2230 set_snap_to ((SnapType) atoi (prop->value()));
2233 if ((prop = node.property ("snap-mode"))) {
2234 set_snap_mode ((SnapMode) atoi (prop->value()));
2237 if ((prop = node.property ("mouse-mode"))) {
2238 MouseMode m = str2mousemode(prop->value());
2239 set_mouse_mode (m, true);
2241 set_mouse_mode (MouseObject, true);
2244 if ((prop = node.property ("left-frame")) != 0) {
2246 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2247 reset_x_origin (pos);
2251 if ((prop = node.property ("y-origin")) != 0) {
2252 reset_y_origin (atof (prop->value ()));
2255 if ((prop = node.property ("internal-edit"))) {
2256 bool yn = string_is_affirmative (prop->value());
2257 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2259 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2260 tact->set_active (!yn);
2261 tact->set_active (yn);
2265 if ((prop = node.property ("join-object-range"))) {
2266 join_object_range_button.set_active (string_is_affirmative (prop->value ()));
2269 if ((prop = node.property ("edit-point"))) {
2270 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2273 if ((prop = node.property ("show-measures"))) {
2274 bool yn = string_is_affirmative (prop->value());
2275 _show_measures = yn;
2276 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2278 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2279 /* do it twice to force the change */
2280 tact->set_active (!yn);
2281 tact->set_active (yn);
2285 if ((prop = node.property ("follow-playhead"))) {
2286 bool yn = string_is_affirmative (prop->value());
2287 set_follow_playhead (yn);
2288 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2290 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2291 if (tact->get_active() != yn) {
2292 tact->set_active (yn);
2297 if ((prop = node.property ("stationary-playhead"))) {
2298 bool yn = string_is_affirmative (prop->value());
2299 set_stationary_playhead (yn);
2300 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2302 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2303 if (tact->get_active() != yn) {
2304 tact->set_active (yn);
2309 if ((prop = node.property ("region-list-sort-type"))) {
2310 RegionListSortType st;
2311 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2314 if ((prop = node.property ("xfades-visible"))) {
2315 bool yn = string_is_affirmative (prop->value());
2316 _xfade_visibility = !yn;
2317 // set_xfade_visibility (yn);
2320 if ((prop = node.property ("show-editor-mixer"))) {
2322 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2325 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2326 bool yn = string_is_affirmative (prop->value());
2328 /* do it twice to force the change */
2330 tact->set_active (!yn);
2331 tact->set_active (yn);
2334 if ((prop = node.property ("show-editor-list"))) {
2336 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2339 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2340 bool yn = string_is_affirmative (prop->value());
2342 /* do it twice to force the change */
2344 tact->set_active (!yn);
2345 tact->set_active (yn);
2348 if ((prop = node.property (X_("editor-list-page")))) {
2349 _the_notebook.set_current_page (atoi (prop->value ()));
2352 if ((prop = node.property (X_("show-marker-lines")))) {
2353 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2355 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2356 bool yn = string_is_affirmative (prop->value ());
2358 tact->set_active (!yn);
2359 tact->set_active (yn);
2362 XMLNodeList children = node.children ();
2363 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2364 selection->set_state (**i, Stateful::current_state_version);
2365 _regions->set_state (**i);
2372 Editor::get_state ()
2374 XMLNode* node = new XMLNode ("Editor");
2377 _id.print (buf, sizeof (buf));
2378 node->add_property ("id", buf);
2380 if (is_realized()) {
2381 Glib::RefPtr<Gdk::Window> win = get_window();
2383 int x, y, width, height;
2384 win->get_root_origin(x, y);
2385 win->get_size(width, height);
2387 XMLNode* geometry = new XMLNode ("geometry");
2389 snprintf(buf, sizeof(buf), "%d", width);
2390 geometry->add_property("x-size", string(buf));
2391 snprintf(buf, sizeof(buf), "%d", height);
2392 geometry->add_property("y-size", string(buf));
2393 snprintf(buf, sizeof(buf), "%d", x);
2394 geometry->add_property("x-pos", string(buf));
2395 snprintf(buf, sizeof(buf), "%d", y);
2396 geometry->add_property("y-pos", string(buf));
2397 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2398 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2399 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2400 snprintf(buf,sizeof(buf), "%d",pre_maximal_horizontal_pane_position);
2401 geometry->add_property("pre-maximal-horizontal-pane-position", string(buf));
2402 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2403 geometry->add_property("edit-vertical-pane-pos", string(buf));
2405 node->add_child_nocopy (*geometry);
2408 maybe_add_mixer_strip_width (*node);
2410 snprintf (buf, sizeof(buf), "%d", (int) zoom_focus);
2411 node->add_property ("zoom-focus", buf);
2412 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2413 node->add_property ("zoom", buf);
2414 snprintf (buf, sizeof(buf), "%d", (int) _snap_type);
2415 node->add_property ("snap-to", buf);
2416 snprintf (buf, sizeof(buf), "%d", (int) _snap_mode);
2417 node->add_property ("snap-mode", buf);
2419 node->add_property ("edit-point", enum_2_string (_edit_point));
2421 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2422 node->add_property ("playhead", buf);
2423 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2424 node->add_property ("left-frame", buf);
2425 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2426 node->add_property ("y-origin", buf);
2428 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2429 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2430 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2431 node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
2432 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2433 node->add_property ("mouse-mode", enum2str(mouse_mode));
2434 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2435 node->add_property ("join-object-range", join_object_range_button.get_active () ? "yes" : "no");
2437 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2439 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2440 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2443 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2445 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2446 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2449 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2450 node->add_property (X_("editor-list-page"), buf);
2452 if (button_bindings) {
2453 XMLNode* bb = new XMLNode (X_("Buttons"));
2454 button_bindings->save (*bb);
2455 node->add_child_nocopy (*bb);
2458 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2460 node->add_child_nocopy (selection->get_state ());
2461 node->add_child_nocopy (_regions->get_state ());
2468 /** @param y y offset from the top of all trackviews.
2469 * @return pair: TimeAxisView that y is over, layer index.
2470 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2471 * in stacked region display mode, otherwise 0.
2473 std::pair<TimeAxisView *, layer_t>
2474 Editor::trackview_by_y_position (double y)
2476 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2478 std::pair<TimeAxisView*, int> const r = (*iter)->covers_y_position (y);
2484 return std::make_pair ( (TimeAxisView *) 0, 0);
2487 /** Snap a position to the grid, if appropriate, taking into account current
2488 * grid settings and also the state of any snap modifier keys that may be pressed.
2489 * @param start Position to snap.
2490 * @param event Event to get current key modifier information from, or 0.
2493 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2495 if (!_session || !event) {
2499 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2500 if (_snap_mode == SnapOff) {
2501 snap_to_internal (start, direction, for_mark);
2504 if (_snap_mode != SnapOff) {
2505 snap_to_internal (start, direction, for_mark);
2511 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2513 if (!_session || _snap_mode == SnapOff) {
2517 snap_to_internal (start, direction, for_mark);
2521 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2523 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2524 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2526 switch (_snap_type) {
2527 case SnapToTimecodeFrame:
2528 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2529 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2531 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2535 case SnapToTimecodeSeconds:
2536 if (_session->config.get_timecode_offset_negative()) {
2537 start += _session->config.get_timecode_offset ();
2539 start -= _session->config.get_timecode_offset ();
2541 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2542 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2544 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2547 if (_session->config.get_timecode_offset_negative()) {
2548 start -= _session->config.get_timecode_offset ();
2550 start += _session->config.get_timecode_offset ();
2554 case SnapToTimecodeMinutes:
2555 if (_session->config.get_timecode_offset_negative()) {
2556 start += _session->config.get_timecode_offset ();
2558 start -= _session->config.get_timecode_offset ();
2560 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2561 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2563 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2565 if (_session->config.get_timecode_offset_negative()) {
2566 start -= _session->config.get_timecode_offset ();
2568 start += _session->config.get_timecode_offset ();
2572 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2578 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2580 const framepos_t one_second = _session->frame_rate();
2581 const framepos_t one_minute = _session->frame_rate() * 60;
2582 framepos_t presnap = start;
2586 switch (_snap_type) {
2587 case SnapToTimecodeFrame:
2588 case SnapToTimecodeSeconds:
2589 case SnapToTimecodeMinutes:
2590 return timecode_snap_to_internal (start, direction, for_mark);
2593 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2594 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2596 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2601 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2602 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2604 start = (framepos_t) floor ((double) start / one_second) * one_second;
2609 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2610 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2612 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2617 start = _session->tempo_map().round_to_bar (start, direction);
2621 start = _session->tempo_map().round_to_beat (start, direction);
2624 case SnapToBeatDiv32:
2625 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2627 case SnapToBeatDiv28:
2628 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2630 case SnapToBeatDiv24:
2631 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2633 case SnapToBeatDiv20:
2634 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2636 case SnapToBeatDiv16:
2637 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2639 case SnapToBeatDiv14:
2640 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2642 case SnapToBeatDiv12:
2643 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2645 case SnapToBeatDiv10:
2646 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2648 case SnapToBeatDiv8:
2649 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2651 case SnapToBeatDiv7:
2652 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2654 case SnapToBeatDiv6:
2655 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2657 case SnapToBeatDiv5:
2658 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2660 case SnapToBeatDiv4:
2661 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2663 case SnapToBeatDiv3:
2664 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2666 case SnapToBeatDiv2:
2667 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2675 _session->locations()->marks_either_side (start, before, after);
2677 if (before == max_framepos) {
2679 } else if (after == max_framepos) {
2681 } else if (before != max_framepos && after != max_framepos) {
2682 /* have before and after */
2683 if ((start - before) < (after - start)) {
2692 case SnapToRegionStart:
2693 case SnapToRegionEnd:
2694 case SnapToRegionSync:
2695 case SnapToRegionBoundary:
2696 if (!region_boundary_cache.empty()) {
2698 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2699 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2701 if (direction > 0) {
2702 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2704 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2707 if (next != region_boundary_cache.begin ()) {
2712 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2713 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2715 if (start > (p + n) / 2) {
2724 switch (_snap_mode) {
2730 if (presnap > start) {
2731 if (presnap > (start + unit_to_frame(snap_threshold))) {
2735 } else if (presnap < start) {
2736 if (presnap < (start - unit_to_frame(snap_threshold))) {
2742 /* handled at entry */
2750 Editor::setup_toolbar ()
2752 HBox* mode_box = manage(new HBox);
2753 mode_box->set_border_width (2);
2754 mode_box->set_spacing(4);
2756 /* table containing mode buttons */
2758 HBox* mouse_mode_button_box = manage (new HBox ());
2760 if (Profile->get_sae()) {
2761 mouse_mode_button_box->pack_start (mouse_move_button);
2763 mouse_mode_button_box->pack_start (mouse_move_button);
2764 mouse_mode_button_box->pack_start (join_object_range_button);
2765 mouse_mode_button_box->pack_start (mouse_select_button);
2768 mouse_mode_button_box->pack_start (mouse_zoom_button);
2770 if (!Profile->get_sae()) {
2771 mouse_mode_button_box->pack_start (mouse_gain_button);
2774 mouse_mode_button_box->pack_start (mouse_timefx_button);
2775 mouse_mode_button_box->pack_start (mouse_audition_button);
2776 mouse_mode_button_box->pack_start (internal_edit_button);
2778 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2779 if (!Profile->get_sae()) {
2780 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2782 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2784 edit_mode_selector.set_name ("EditModeSelector");
2785 set_popdown_strings (edit_mode_selector, edit_mode_strings, true);
2786 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2788 mode_box->pack_start (edit_mode_selector);
2789 mode_box->pack_start (*mouse_mode_button_box);
2791 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2792 _mouse_mode_tearoff->set_name ("MouseModeBase");
2793 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2795 if (Profile->get_sae()) {
2796 _mouse_mode_tearoff->set_can_be_torn_off (false);
2799 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2800 &_mouse_mode_tearoff->tearoff_window()));
2801 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2802 &_mouse_mode_tearoff->tearoff_window(), 1));
2803 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2804 &_mouse_mode_tearoff->tearoff_window()));
2805 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2806 &_mouse_mode_tearoff->tearoff_window(), 1));
2808 mouse_move_button.set_mode (false);
2809 mouse_select_button.set_mode (false);
2810 mouse_gain_button.set_mode (false);
2811 mouse_zoom_button.set_mode (false);
2812 mouse_timefx_button.set_mode (false);
2813 mouse_audition_button.set_mode (false);
2814 join_object_range_button.set_mode (false);
2816 mouse_move_button.set_name ("MouseModeButton");
2817 mouse_select_button.set_name ("MouseModeButton");
2818 mouse_gain_button.set_name ("MouseModeButton");
2819 mouse_zoom_button.set_name ("MouseModeButton");
2820 mouse_timefx_button.set_name ("MouseModeButton");
2821 mouse_audition_button.set_name ("MouseModeButton");
2822 internal_edit_button.set_name ("MouseModeButton");
2823 join_object_range_button.set_name ("MouseModeButton");
2825 mouse_move_button.unset_flags (CAN_FOCUS);
2826 mouse_select_button.unset_flags (CAN_FOCUS);
2827 mouse_gain_button.unset_flags (CAN_FOCUS);
2828 mouse_zoom_button.unset_flags (CAN_FOCUS);
2829 mouse_timefx_button.unset_flags (CAN_FOCUS);
2830 mouse_audition_button.unset_flags (CAN_FOCUS);
2831 internal_edit_button.unset_flags (CAN_FOCUS);
2832 join_object_range_button.unset_flags (CAN_FOCUS);
2836 _zoom_box.set_spacing (1);
2837 _zoom_box.set_border_width (0);
2839 zoom_in_button.set_name ("EditorTimeButton");
2840 zoom_in_button.set_image (*(manage (new Image (::get_icon ("zoom_in")))));
2841 zoom_in_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), false));
2843 zoom_out_button.set_name ("EditorTimeButton");
2844 zoom_out_button.set_image (*(manage (new Image (::get_icon ("zoom_out")))));
2845 zoom_out_button.signal_clicked().connect (sigc::bind (sigc::mem_fun(*this, &Editor::temporal_zoom_step), true));
2847 zoom_out_full_button.set_name ("EditorTimeButton");
2848 zoom_out_full_button.set_image (*(manage (new Image (::get_icon ("zoom_full")))));
2849 zoom_out_full_button.signal_clicked().connect (sigc::mem_fun(*this, &Editor::temporal_zoom_session));
2851 zoom_focus_selector.set_name ("ZoomFocusSelector");
2852 set_popdown_strings (zoom_focus_selector, zoom_focus_strings, true);
2853 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2855 _zoom_box.pack_start (zoom_out_button, false, false);
2856 _zoom_box.pack_start (zoom_in_button, false, false);
2857 _zoom_box.pack_start (zoom_out_full_button, false, false);
2859 _zoom_box.pack_start (zoom_focus_selector);
2861 /* Track zoom buttons */
2862 tav_expand_button.set_name ("TrackHeightButton");
2863 tav_expand_button.set_size_request (-1, 20);
2864 tav_expand_button.add (*(manage (new Image (::get_icon ("tav_exp")))));
2865 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2866 act->connect_proxy (tav_expand_button);
2868 tav_shrink_button.set_name ("TrackHeightButton");
2869 tav_shrink_button.set_size_request (-1, 20);
2870 tav_shrink_button.add (*(manage (new Image (::get_icon ("tav_shrink")))));
2871 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2872 act->connect_proxy (tav_shrink_button);
2874 _zoom_box.pack_start (tav_shrink_button);
2875 _zoom_box.pack_start (tav_expand_button);
2877 _zoom_tearoff = manage (new TearOff (_zoom_box));
2879 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2880 &_zoom_tearoff->tearoff_window()));
2881 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2882 &_zoom_tearoff->tearoff_window(), 0));
2883 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2884 &_zoom_tearoff->tearoff_window()));
2885 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2886 &_zoom_tearoff->tearoff_window(), 0));
2888 snap_box.set_spacing (1);
2889 snap_box.set_border_width (2);
2891 snap_type_selector.set_name ("SnapTypeSelector");
2892 set_popdown_strings (snap_type_selector, snap_type_strings, true);
2893 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2895 snap_mode_selector.set_name ("SnapModeSelector");
2896 set_popdown_strings (snap_mode_selector, snap_mode_strings, true);
2897 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
2899 edit_point_selector.set_name ("EditPointSelector");
2900 set_popdown_strings (edit_point_selector, edit_point_strings, true);
2901 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
2903 snap_box.pack_start (snap_mode_selector, false, false);
2904 snap_box.pack_start (snap_type_selector, false, false);
2905 snap_box.pack_start (edit_point_selector, false, false);
2909 HBox *nudge_box = manage (new HBox);
2910 nudge_box->set_spacing(1);
2911 nudge_box->set_border_width (2);
2913 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
2914 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
2916 nudge_box->pack_start (nudge_backward_button, false, false);
2917 nudge_box->pack_start (nudge_forward_button, false, false);
2918 nudge_box->pack_start (*nudge_clock, false, false);
2921 /* Pack everything in... */
2923 HBox* hbox = manage (new HBox);
2924 hbox->set_spacing(10);
2926 _tools_tearoff = manage (new TearOff (*hbox));
2927 _tools_tearoff->set_name ("MouseModeBase");
2928 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
2930 if (Profile->get_sae()) {
2931 _tools_tearoff->set_can_be_torn_off (false);
2934 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2935 &_tools_tearoff->tearoff_window()));
2936 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2937 &_tools_tearoff->tearoff_window(), 0));
2938 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2939 &_tools_tearoff->tearoff_window()));
2940 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2941 &_tools_tearoff->tearoff_window(), 0));
2943 toolbar_hbox.set_spacing (10);
2944 toolbar_hbox.set_border_width (1);
2946 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
2947 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
2948 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
2950 hbox->pack_start (snap_box, false, false);
2951 if (!Profile->get_small_screen()) {
2952 hbox->pack_start (*nudge_box, false, false);
2954 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
2956 hbox->pack_start (panic_box, false, false);
2960 toolbar_base.set_name ("ToolBarBase");
2961 toolbar_base.add (toolbar_hbox);
2963 _toolbar_viewport.add (toolbar_base);
2964 /* stick to the required height but allow width to vary if there's not enough room */
2965 _toolbar_viewport.set_size_request (1, -1);
2967 toolbar_frame.set_shadow_type (SHADOW_OUT);
2968 toolbar_frame.set_name ("BaseFrame");
2969 toolbar_frame.add (_toolbar_viewport);
2971 DPIReset.connect (sigc::mem_fun (*this, &Editor::resize_text_widgets));
2975 Editor::setup_tooltips ()
2977 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Select/Move Objects"));
2978 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
2979 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
2980 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
2981 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
2982 ARDOUR_UI::instance()->set_tip (join_object_range_button, _("Select/Move Objects or Ranges"));
2983 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Edit Region Contents (e.g. notes)"));
2984 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
2985 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Forwards"));
2986 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Backwards"));
2987 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
2988 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
2989 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
2990 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
2991 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
2992 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
2993 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
2994 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
2995 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
2996 ARDOUR_UI::instance()->set_tip (midi_sound_notes, _("Sound Notes"));
2997 ARDOUR_UI::instance()->set_tip (midi_panic_button, _("Send note off and reset controller messages on all MIDI channels"));
2998 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3002 Editor::midi_panic ()
3004 cerr << "MIDI panic\n";
3007 _session->midi_panic();
3012 Editor::setup_midi_toolbar ()
3016 /* Midi sound notes */
3017 midi_sound_notes.add (*(manage (new Image (::get_icon("midi_sound_notes")))));
3018 midi_sound_notes.unset_flags (CAN_FOCUS);
3022 act = ActionManager::get_action (X_("MIDI"), X_("panic"));
3023 midi_panic_button.set_name("MidiPanicButton");
3024 act->connect_proxy (midi_panic_button);
3026 panic_box.pack_start (midi_sound_notes , true, true);
3027 panic_box.pack_start (midi_panic_button, true, true);
3031 Editor::convert_drop_to_paths (
3032 vector<string>& paths,
3033 const RefPtr<Gdk::DragContext>& /*context*/,
3036 const SelectionData& data,
3040 if (_session == 0) {
3044 vector<string> uris = data.get_uris();
3048 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3049 are actually URI lists. So do it by hand.
3052 if (data.get_target() != "text/plain") {
3056 /* Parse the "uri-list" format that Nautilus provides,
3057 where each pathname is delimited by \r\n.
3059 THERE MAY BE NO NULL TERMINATING CHAR!!!
3062 string txt = data.get_text();
3066 p = (const char *) malloc (txt.length() + 1);
3067 txt.copy ((char *) p, txt.length(), 0);
3068 ((char*)p)[txt.length()] = '\0';
3074 while (g_ascii_isspace (*p))
3078 while (*q && (*q != '\n') && (*q != '\r')) {
3085 while (q > p && g_ascii_isspace (*q))
3090 uris.push_back (string (p, q - p + 1));
3094 p = strchr (p, '\n');
3106 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3108 if ((*i).substr (0,7) == "file://") {
3111 PBD::url_decode (p);
3113 // scan forward past three slashes
3115 string::size_type slashcnt = 0;
3116 string::size_type n = 0;
3117 string::iterator x = p.begin();
3119 while (slashcnt < 3 && x != p.end()) {
3122 } else if (slashcnt == 3) {
3129 if (slashcnt != 3 || x == p.end()) {
3130 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3134 paths.push_back (p.substr (n - 1));
3142 Editor::new_tempo_section ()
3148 Editor::map_transport_state ()
3150 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state)
3152 if (_session && _session->transport_stopped()) {
3153 have_pending_keyboard_selection = false;
3156 update_loop_range_view (true);
3161 Editor::State::State (PublicEditor const * e)
3163 selection = new Selection (e);
3166 Editor::State::~State ()
3172 Editor::begin_reversible_command (string name)
3175 _session->begin_reversible_command (name);
3180 Editor::begin_reversible_command (GQuark q)
3183 _session->begin_reversible_command (q);
3188 Editor::commit_reversible_command ()
3191 _session->commit_reversible_command ();
3196 Editor::history_changed ()
3200 if (undo_action && _session) {
3201 if (_session->undo_depth() == 0) {
3204 label = string_compose(_("Undo (%1)"), _session->next_undo());
3206 undo_action->property_label() = label;
3209 if (redo_action && _session) {
3210 if (_session->redo_depth() == 0) {
3213 label = string_compose(_("Redo (%1)"), _session->next_redo());
3215 redo_action->property_label() = label;
3220 Editor::duplicate_dialog (bool with_dialog)
3224 if (mouse_mode == MouseRange) {
3225 if (selection->time.length() == 0) {
3230 RegionSelection rs = get_regions_from_selection_and_entered ();
3232 if (mouse_mode != MouseRange && rs.empty()) {
3238 ArdourDialog win (_("Duplicate"));
3239 Label label (_("Number of duplications:"));
3240 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3241 SpinButton spinner (adjustment, 0.0, 1);
3244 win.get_vbox()->set_spacing (12);
3245 win.get_vbox()->pack_start (hbox);
3246 hbox.set_border_width (6);
3247 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3249 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3250 place, visually. so do this by hand.
3253 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3254 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3255 spinner.grab_focus();
3261 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3262 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3263 win.set_default_response (RESPONSE_ACCEPT);
3265 win.set_position (WIN_POS_MOUSE);
3267 spinner.grab_focus ();
3269 switch (win.run ()) {
3270 case RESPONSE_ACCEPT:
3276 times = adjustment.get_value();
3279 if (mouse_mode == MouseRange) {
3280 duplicate_selection (times);
3282 duplicate_some_regions (rs, times);
3287 Editor::set_edit_mode (EditMode m)
3289 Config->set_edit_mode (m);
3293 Editor::cycle_edit_mode ()
3295 switch (Config->get_edit_mode()) {
3297 if (Profile->get_sae()) {
3298 Config->set_edit_mode (Lock);
3300 Config->set_edit_mode (Splice);
3304 Config->set_edit_mode (Lock);
3307 Config->set_edit_mode (Slide);
3313 Editor::edit_mode_selection_done ()
3315 string s = edit_mode_selector.get_active_text ();
3318 Config->set_edit_mode (string_to_edit_mode (s));
3323 Editor::snap_type_selection_done ()
3325 string choice = snap_type_selector.get_active_text();
3326 SnapType snaptype = SnapToBeat;
3328 if (choice == _("Beats/2")) {
3329 snaptype = SnapToBeatDiv2;
3330 } else if (choice == _("Beats/3")) {
3331 snaptype = SnapToBeatDiv3;
3332 } else if (choice == _("Beats/4")) {
3333 snaptype = SnapToBeatDiv4;
3334 } else if (choice == _("Beats/5")) {
3335 snaptype = SnapToBeatDiv5;
3336 } else if (choice == _("Beats/6")) {
3337 snaptype = SnapToBeatDiv6;
3338 } else if (choice == _("Beats/7")) {
3339 snaptype = SnapToBeatDiv7;
3340 } else if (choice == _("Beats/8")) {
3341 snaptype = SnapToBeatDiv8;
3342 } else if (choice == _("Beats/10")) {
3343 snaptype = SnapToBeatDiv10;
3344 } else if (choice == _("Beats/12")) {
3345 snaptype = SnapToBeatDiv12;
3346 } else if (choice == _("Beats/14")) {
3347 snaptype = SnapToBeatDiv14;
3348 } else if (choice == _("Beats/16")) {
3349 snaptype = SnapToBeatDiv16;
3350 } else if (choice == _("Beats/20")) {
3351 snaptype = SnapToBeatDiv20;
3352 } else if (choice == _("Beats/24")) {
3353 snaptype = SnapToBeatDiv24;
3354 } else if (choice == _("Beats/28")) {
3355 snaptype = SnapToBeatDiv28;
3356 } else if (choice == _("Beats/32")) {
3357 snaptype = SnapToBeatDiv32;
3358 } else if (choice == _("Beats")) {
3359 snaptype = SnapToBeat;
3360 } else if (choice == _("Bars")) {
3361 snaptype = SnapToBar;
3362 } else if (choice == _("Marks")) {
3363 snaptype = SnapToMark;
3364 } else if (choice == _("Region starts")) {
3365 snaptype = SnapToRegionStart;
3366 } else if (choice == _("Region ends")) {
3367 snaptype = SnapToRegionEnd;
3368 } else if (choice == _("Region bounds")) {
3369 snaptype = SnapToRegionBoundary;
3370 } else if (choice == _("Region syncs")) {
3371 snaptype = SnapToRegionSync;
3372 } else if (choice == _("CD Frames")) {
3373 snaptype = SnapToCDFrame;
3374 } else if (choice == _("Timecode Frames")) {
3375 snaptype = SnapToTimecodeFrame;
3376 } else if (choice == _("Timecode Seconds")) {
3377 snaptype = SnapToTimecodeSeconds;
3378 } else if (choice == _("Timecode Minutes")) {
3379 snaptype = SnapToTimecodeMinutes;
3380 } else if (choice == _("Seconds")) {
3381 snaptype = SnapToSeconds;
3382 } else if (choice == _("Minutes")) {
3383 snaptype = SnapToMinutes;
3386 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3388 ract->set_active ();
3393 Editor::snap_mode_selection_done ()
3395 string choice = snap_mode_selector.get_active_text();
3396 SnapMode mode = SnapNormal;
3398 if (choice == _("No Grid")) {
3400 } else if (choice == _("Grid")) {
3402 } else if (choice == _("Magnetic")) {
3403 mode = SnapMagnetic;
3406 RefPtr<RadioAction> ract = snap_mode_action (mode);
3409 ract->set_active (true);
3414 Editor::cycle_edit_point (bool with_marker)
3416 switch (_edit_point) {
3418 set_edit_point_preference (EditAtPlayhead);
3420 case EditAtPlayhead:
3422 set_edit_point_preference (EditAtSelectedMarker);
3424 set_edit_point_preference (EditAtMouse);
3427 case EditAtSelectedMarker:
3428 set_edit_point_preference (EditAtMouse);
3434 Editor::edit_point_selection_done ()
3436 string choice = edit_point_selector.get_active_text();
3437 EditPoint ep = EditAtSelectedMarker;
3439 if (choice == _("Marker")) {
3440 set_edit_point_preference (EditAtSelectedMarker);
3441 } else if (choice == _("Playhead")) {
3442 set_edit_point_preference (EditAtPlayhead);
3444 set_edit_point_preference (EditAtMouse);
3447 RefPtr<RadioAction> ract = edit_point_action (ep);
3450 ract->set_active (true);
3455 Editor::zoom_focus_selection_done ()
3457 string choice = zoom_focus_selector.get_active_text();
3458 ZoomFocus focus_type = ZoomFocusLeft;
3460 if (choice == _("Left")) {
3461 focus_type = ZoomFocusLeft;
3462 } else if (choice == _("Right")) {
3463 focus_type = ZoomFocusRight;
3464 } else if (choice == _("Center")) {
3465 focus_type = ZoomFocusCenter;
3466 } else if (choice == _("Playhead")) {
3467 focus_type = ZoomFocusPlayhead;
3468 } else if (choice == _("Mouse")) {
3469 focus_type = ZoomFocusMouse;
3470 } else if (choice == _("Edit point")) {
3471 focus_type = ZoomFocusEdit;
3474 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3477 ract->set_active ();
3482 Editor::edit_controls_button_release (GdkEventButton* ev)
3484 if (Keyboard::is_context_menu_event (ev)) {
3485 ARDOUR_UI::instance()->add_route (this);
3486 } else if (ev->button == 1) {
3487 selection->clear_tracks ();
3494 Editor::mouse_select_button_release (GdkEventButton* ev)
3496 /* this handles just right-clicks */
3498 if (ev->button != 3) {
3506 Editor::set_zoom_focus (ZoomFocus f)
3508 string str = zoom_focus_strings[(int)f];
3510 if (str != zoom_focus_selector.get_active_text()) {
3511 zoom_focus_selector.set_active_text (str);
3514 if (zoom_focus != f) {
3521 Editor::ensure_float (Window& win)
3523 win.set_transient_for (*this);
3527 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3529 /* recover or initialize pane positions. do this here rather than earlier because
3530 we don't want the positions to change the child allocations, which they seem to do.
3536 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3545 XMLNode* geometry = find_named_node (*node, "geometry");
3547 if (which == static_cast<Paned*> (&edit_pane)) {
3549 if (done & Horizontal) {
3553 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3554 _notebook_shrunk = string_is_affirmative (prop->value ());
3557 if (geometry && (prop = geometry->property ("pre-maximal-horizontal-pane-position"))) {
3558 pre_maximal_horizontal_pane_position = atoi (prop->value ());
3561 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3562 /* initial allocation is 90% to canvas, 10% to notebook */
3563 pos = (int) floor (alloc.get_width() * 0.90f);
3564 snprintf (buf, sizeof(buf), "%d", pos);
3566 pos = atoi (prop->value());
3569 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3570 edit_pane.set_position (pos);
3571 if (pre_maximal_horizontal_pane_position == 0) {
3572 pre_maximal_horizontal_pane_position = pos;
3576 done = (Pane) (done | Horizontal);
3578 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3580 if (done & Vertical) {
3584 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3585 /* initial allocation is 90% to canvas, 10% to summary */
3586 pos = (int) floor (alloc.get_height() * 0.90f);
3587 snprintf (buf, sizeof(buf), "%d", pos);
3589 pos = atoi (prop->value());
3592 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3593 editor_summary_pane.set_position (pos);
3594 pre_maximal_vertical_pane_position = pos;
3597 done = (Pane) (done | Vertical);
3602 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3604 if (_tools_tearoff->torn_off() && _mouse_mode_tearoff->torn_off()) {
3605 top_hbox.remove (toolbar_frame);
3610 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3612 if (toolbar_frame.get_parent() == 0) {
3613 top_hbox.pack_end (toolbar_frame);
3618 Editor::set_show_measures (bool yn)
3620 if (_show_measures != yn) {
3623 if ((_show_measures = yn) == true) {
3625 tempo_lines->show();
3633 Editor::toggle_follow_playhead ()
3635 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3637 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3638 set_follow_playhead (tact->get_active());
3642 /** @param yn true to follow playhead, otherwise false.
3643 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3646 Editor::set_follow_playhead (bool yn, bool catch_up)
3648 if (_follow_playhead != yn) {
3649 if ((_follow_playhead = yn) == true && catch_up) {
3651 reset_x_origin_to_follow_playhead ();
3658 Editor::toggle_stationary_playhead ()
3660 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3662 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3663 set_stationary_playhead (tact->get_active());
3668 Editor::set_stationary_playhead (bool yn)
3670 if (_stationary_playhead != yn) {
3671 if ((_stationary_playhead = yn) == true) {
3673 // FIXME need a 3.0 equivalent of this 2.X call
3674 // update_current_screen ();
3681 Editor::toggle_xfade_active (boost::weak_ptr<Crossfade> wxfade)
3683 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3685 xfade->set_active (!xfade->active());
3690 Editor::toggle_xfade_length (boost::weak_ptr<Crossfade> wxfade)
3692 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3694 xfade->set_follow_overlap (!xfade->following_overlap());
3699 Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
3701 boost::shared_ptr<Crossfade> xfade (wxfade.lock());
3707 CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
3711 switch (cew.run ()) {
3712 case RESPONSE_ACCEPT:
3719 PropertyChange all_crossfade_properties;
3720 all_crossfade_properties.add (ARDOUR::Properties::active);
3721 all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
3722 xfade->PropertyChanged (all_crossfade_properties);
3726 Editor::playlist_selector () const
3728 return *_playlist_selector;
3732 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3736 switch (_snap_type) {
3741 case SnapToBeatDiv32:
3744 case SnapToBeatDiv28:
3747 case SnapToBeatDiv24:
3750 case SnapToBeatDiv20:
3753 case SnapToBeatDiv16:
3756 case SnapToBeatDiv14:
3759 case SnapToBeatDiv12:
3762 case SnapToBeatDiv10:
3765 case SnapToBeatDiv8:
3768 case SnapToBeatDiv7:
3771 case SnapToBeatDiv6:
3774 case SnapToBeatDiv5:
3777 case SnapToBeatDiv4:
3780 case SnapToBeatDiv3:
3783 case SnapToBeatDiv2:
3789 return _session->tempo_map().meter_at (position).beats_per_bar();
3794 case SnapToTimecodeFrame:
3795 case SnapToTimecodeSeconds:
3796 case SnapToTimecodeMinutes:
3799 case SnapToRegionStart:
3800 case SnapToRegionEnd:
3801 case SnapToRegionSync:
3802 case SnapToRegionBoundary:
3812 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3816 ret = nudge_clock->current_duration (pos);
3817 next = ret + 1; /* XXXX fix me */
3823 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3825 ArdourDialog dialog (_("Playlist Deletion"));
3826 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3827 "If it is kept, its audio files will not be cleaned.\n"
3828 "If it is deleted, audio files used by it alone will be cleaned."),
3831 dialog.set_position (WIN_POS_CENTER);
3832 dialog.get_vbox()->pack_start (label);
3836 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3837 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3838 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3840 switch (dialog.run ()) {
3841 case RESPONSE_ACCEPT:
3842 /* delete the playlist */
3846 case RESPONSE_REJECT:
3847 /* keep the playlist */
3859 Editor::audio_region_selection_covers (framepos_t where)
3861 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3862 if ((*a)->region()->covers (where)) {
3871 Editor::prepare_for_cleanup ()
3873 cut_buffer->clear_regions ();
3874 cut_buffer->clear_playlists ();
3876 selection->clear_regions ();
3877 selection->clear_playlists ();
3879 _regions->suspend_redisplay ();
3883 Editor::finish_cleanup ()
3885 _regions->resume_redisplay ();
3889 Editor::transport_loop_location()
3892 return _session->locations()->auto_loop_location();
3899 Editor::transport_punch_location()
3902 return _session->locations()->auto_punch_location();
3909 Editor::control_layout_scroll (GdkEventScroll* ev)
3911 if (Keyboard::some_magic_widget_has_focus()) {
3915 switch (ev->direction) {
3917 scroll_tracks_up_line ();
3921 case GDK_SCROLL_DOWN:
3922 scroll_tracks_down_line ();
3926 /* no left/right handling yet */
3934 Editor::session_state_saved (string)
3937 _snapshots->redisplay ();
3941 Editor::maximise_editing_space ()
3943 _mouse_mode_tearoff->set_visible (false);
3944 _tools_tearoff->set_visible (false);
3945 _zoom_tearoff->set_visible (false);
3947 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
3948 pre_maximal_vertical_pane_position = editor_summary_pane.get_position ();
3949 pre_maximal_editor_width = this->get_width ();
3950 pre_maximal_editor_height = this->get_height ();
3952 if (post_maximal_horizontal_pane_position == 0) {
3953 post_maximal_horizontal_pane_position = edit_pane.get_width();
3956 if (post_maximal_vertical_pane_position == 0) {
3957 post_maximal_vertical_pane_position = editor_summary_pane.get_height();
3962 if (post_maximal_editor_width) {
3963 edit_pane.set_position (post_maximal_horizontal_pane_position -
3964 abs(post_maximal_editor_width - pre_maximal_editor_width));
3966 edit_pane.set_position (post_maximal_horizontal_pane_position);
3969 /* Hack: we must do this in an idle handler for it to work; see comment in
3970 restore_editing_space()
3973 Glib::signal_idle().connect (
3975 sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position),
3976 post_maximal_vertical_pane_position
3980 if (Config->get_keep_tearoffs()) {
3981 _mouse_mode_tearoff->set_visible (true);
3982 _tools_tearoff->set_visible (true);
3983 if (Config->get_show_zoom_tools ()) {
3984 _zoom_tearoff->set_visible (true);
3991 Editor::idle_reset_vertical_pane_position (int p)
3993 editor_summary_pane.set_position (p);
3998 Editor::restore_editing_space ()
4000 // user changed width/height of panes during fullscreen
4002 if (post_maximal_horizontal_pane_position != edit_pane.get_position()) {
4003 post_maximal_horizontal_pane_position = edit_pane.get_position();
4006 if (post_maximal_vertical_pane_position != editor_summary_pane.get_position()) {
4007 post_maximal_vertical_pane_position = editor_summary_pane.get_position();
4012 _mouse_mode_tearoff->set_visible (true);
4013 _tools_tearoff->set_visible (true);
4014 if (Config->get_show_zoom_tools ()) {
4015 _zoom_tearoff->set_visible (true);
4017 post_maximal_editor_width = this->get_width();
4018 post_maximal_editor_height = this->get_height();
4020 edit_pane.set_position (pre_maximal_horizontal_pane_position + abs(this->get_width() - pre_maximal_editor_width));
4022 /* This is a bit of a hack, but it seems that if you set the vertical pane position
4023 here it gets reset to some wrong value after this method has finished. Doing
4024 the setup in an idle callback seems to work.
4026 Glib::signal_idle().connect (
4028 sigc::mem_fun (*this, &Editor::idle_reset_vertical_pane_position),
4029 pre_maximal_vertical_pane_position
4035 * Make new playlists for a given track and also any others that belong
4036 * to the same active route group with the `edit' property.
4041 Editor::new_playlists (TimeAxisView* v)
4043 begin_reversible_command (_("new playlists"));
4044 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4045 _session->playlists->get (playlists);
4046 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4047 commit_reversible_command ();
4051 * Use a copy of the current playlist for a given track and also any others that belong
4052 * to the same active route group with the `edit' property.
4057 Editor::copy_playlists (TimeAxisView* v)
4059 begin_reversible_command (_("copy playlists"));
4060 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4061 _session->playlists->get (playlists);
4062 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::edit.property_id);
4063 commit_reversible_command ();
4066 /** Clear the current playlist for a given track and also any others that belong
4067 * to the same active route group with the `edit' property.
4072 Editor::clear_playlists (TimeAxisView* v)
4074 begin_reversible_command (_("clear playlists"));
4075 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4076 _session->playlists->get (playlists);
4077 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::edit.property_id);
4078 commit_reversible_command ();
4082 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4084 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4088 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4090 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4094 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4096 atv.clear_playlist ();
4100 Editor::on_key_press_event (GdkEventKey* ev)
4102 return key_press_focus_accelerator_handler (*this, ev);
4106 Editor::on_key_release_event (GdkEventKey* ev)
4108 return Gtk::Window::on_key_release_event (ev);
4109 // return key_press_focus_accelerator_handler (*this, ev);
4112 /** Queue up a change to the viewport x origin.
4113 * @param frame New x origin.
4116 Editor::reset_x_origin (framepos_t frame)
4118 queue_visual_change (frame);
4122 Editor::reset_y_origin (double y)
4124 queue_visual_change_y (y);
4128 Editor::reset_zoom (double fpu)
4130 queue_visual_change (fpu);
4134 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4136 reset_x_origin (frame);
4139 if (!no_save_visual) {
4140 undo_visual_stack.push_back (current_visual_state(false));
4144 Editor::VisualState::VisualState ()
4145 : gui_state (new GUIObjectState)
4149 Editor::VisualState::~VisualState ()
4154 Editor::VisualState*
4155 Editor::current_visual_state (bool with_tracks)
4157 VisualState* vs = new VisualState;
4158 vs->y_position = vertical_adjustment.get_value();
4159 vs->frames_per_unit = frames_per_unit;
4160 vs->leftmost_frame = leftmost_frame;
4161 vs->zoom_focus = zoom_focus;
4164 *(vs->gui_state) = *ARDOUR_UI::instance()->gui_object_state;
4171 Editor::undo_visual_state ()
4173 if (undo_visual_stack.empty()) {
4177 redo_visual_stack.push_back (current_visual_state());
4179 VisualState* vs = undo_visual_stack.back();
4180 undo_visual_stack.pop_back();
4181 use_visual_state (*vs);
4185 Editor::redo_visual_state ()
4187 if (redo_visual_stack.empty()) {
4191 undo_visual_stack.push_back (current_visual_state());
4193 VisualState* vs = redo_visual_stack.back();
4194 redo_visual_stack.pop_back();
4195 use_visual_state (*vs);
4199 Editor::swap_visual_state ()
4201 if (undo_visual_stack.empty()) {
4202 redo_visual_state ();
4204 undo_visual_state ();
4209 Editor::use_visual_state (VisualState& vs)
4211 no_save_visual = true;
4213 _routes->suspend_redisplay ();
4215 vertical_adjustment.set_value (vs.y_position);
4217 set_zoom_focus (vs.zoom_focus);
4218 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4220 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4222 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4223 (*i)->reset_visual_state ();
4226 _routes->update_visibility ();
4227 _routes->resume_redisplay ();
4229 no_save_visual = false;
4233 Editor::set_frames_per_unit (double fpu)
4235 /* this is the core function that controls the zoom level of the canvas. it is called
4236 whenever one or more calls are made to reset_zoom(). it executes in an idle handler.
4239 if (fpu == frames_per_unit) {
4248 /* don't allow zooms that fit more than the maximum number
4249 of frames into an 800 pixel wide space.
4252 if (max_framepos / fpu < 800.0) {
4257 tempo_lines->tempo_map_changed();
4259 frames_per_unit = fpu;
4264 Editor::post_zoom ()
4266 // convert fpu to frame count
4268 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4270 if (frames_per_unit != zoom_range_clock->current_duration()) {
4271 zoom_range_clock->set (frames);
4274 if (mouse_mode == MouseRange && selection->time.start () != selection->time.end_frame ()) {
4275 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4276 (*i)->reshow_selection (selection->time);
4280 ZoomChanged (); /* EMIT_SIGNAL */
4282 //reset_scrolling_region ();
4284 if (playhead_cursor) {
4285 playhead_cursor->set_position (playhead_cursor->current_frame);
4288 refresh_location_display();
4289 _summary->set_overlays_dirty ();
4291 update_marker_labels ();
4297 Editor::queue_visual_change (framepos_t where)
4299 pending_visual_change.add (VisualChange::TimeOrigin);
4300 pending_visual_change.time_origin = where;
4301 ensure_visual_change_idle_handler ();
4305 Editor::queue_visual_change (double fpu)
4307 pending_visual_change.add (VisualChange::ZoomLevel);
4308 pending_visual_change.frames_per_unit = fpu;
4310 ensure_visual_change_idle_handler ();
4314 Editor::queue_visual_change_y (double y)
4316 pending_visual_change.add (VisualChange::YOrigin);
4317 pending_visual_change.y_origin = y;
4319 ensure_visual_change_idle_handler ();
4323 Editor::ensure_visual_change_idle_handler ()
4325 if (pending_visual_change.idle_handler_id < 0) {
4326 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4331 Editor::_idle_visual_changer (void* arg)
4333 return static_cast<Editor*>(arg)->idle_visual_changer ();
4337 Editor::idle_visual_changer ()
4339 VisualChange::Type p = pending_visual_change.pending;
4340 pending_visual_change.pending = (VisualChange::Type) 0;
4342 double const last_time_origin = horizontal_position ();
4344 if (p & VisualChange::TimeOrigin) {
4345 /* This is a bit of a hack, but set_frames_per_unit
4346 below will (if called) end up with the
4347 CrossfadeViews looking at Editor::leftmost_frame,
4348 and if we're changing origin and zoom in the same
4349 operation it will be the wrong value unless we
4353 leftmost_frame = pending_visual_change.time_origin;
4356 if (p & VisualChange::ZoomLevel) {
4357 set_frames_per_unit (pending_visual_change.frames_per_unit);
4359 compute_fixed_ruler_scale ();
4360 compute_current_bbt_points(pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4361 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames());
4362 update_tempo_based_rulers ();
4364 if (p & VisualChange::TimeOrigin) {
4365 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4367 if (p & VisualChange::YOrigin) {
4368 vertical_adjustment.set_value (pending_visual_change.y_origin);
4371 if (last_time_origin == horizontal_position ()) {
4372 /* changed signal not emitted */
4373 update_fixed_rulers ();
4374 redisplay_tempo (true);
4377 _summary->set_overlays_dirty ();
4379 pending_visual_change.idle_handler_id = -1;
4380 return 0; /* this is always a one-shot call */
4383 struct EditorOrderTimeAxisSorter {
4384 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4385 return a->order () < b->order ();
4390 Editor::sort_track_selection (TrackViewList* sel)
4392 EditorOrderTimeAxisSorter cmp;
4397 selection->tracks.sort (cmp);
4402 Editor::get_preferred_edit_position (bool ignore_playhead)
4405 framepos_t where = 0;
4406 EditPoint ep = _edit_point;
4408 if (entered_marker) {
4409 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4410 return entered_marker->position();
4413 if (ignore_playhead && ep == EditAtPlayhead) {
4414 ep = EditAtSelectedMarker;
4418 case EditAtPlayhead:
4419 where = _session->audible_frame();
4420 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4423 case EditAtSelectedMarker:
4424 if (!selection->markers.empty()) {
4426 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4429 where = loc->start();
4433 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4441 if (!mouse_frame (where, ignored)) {
4442 /* XXX not right but what can we do ? */
4446 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4454 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4456 if (!_session) return;
4458 begin_reversible_command (cmd);
4462 if ((tll = transport_loop_location()) == 0) {
4463 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4464 XMLNode &before = _session->locations()->get_state();
4465 _session->locations()->add (loc, true);
4466 _session->set_auto_loop_location (loc);
4467 XMLNode &after = _session->locations()->get_state();
4468 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4470 XMLNode &before = tll->get_state();
4471 tll->set_hidden (false, this);
4472 tll->set (start, end);
4473 XMLNode &after = tll->get_state();
4474 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4477 commit_reversible_command ();
4481 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4483 if (!_session) return;
4485 begin_reversible_command (cmd);
4489 if ((tpl = transport_punch_location()) == 0) {
4490 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoPunch);
4491 XMLNode &before = _session->locations()->get_state();
4492 _session->locations()->add (loc, true);
4493 _session->set_auto_loop_location (loc);
4494 XMLNode &after = _session->locations()->get_state();
4495 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4498 XMLNode &before = tpl->get_state();
4499 tpl->set_hidden (false, this);
4500 tpl->set (start, end);
4501 XMLNode &after = tpl->get_state();
4502 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4505 commit_reversible_command ();
4508 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4509 * @param rs List to which found regions are added.
4510 * @param where Time to look at.
4511 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4514 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4516 const TrackViewList* tracks;
4519 tracks = &track_views;
4524 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4526 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4529 boost::shared_ptr<Track> tr;
4530 boost::shared_ptr<Playlist> pl;
4532 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4534 Playlist::RegionList* regions = pl->regions_at (
4535 (framepos_t) floor ( (double) where * tr->speed()));
4537 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4538 RegionView* rv = rtv->view()->find_view (*i);
4551 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4553 const TrackViewList* tracks;
4556 tracks = &track_views;
4561 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4562 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4564 boost::shared_ptr<Track> tr;
4565 boost::shared_ptr<Playlist> pl;
4567 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4569 Playlist::RegionList* regions = pl->regions_touched (
4570 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4572 for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4574 RegionView* rv = rtv->view()->find_view (*i);
4587 /** Start with regions that are selected. Then add equivalent regions
4588 * on tracks in the same active edit-enabled route group as any of
4589 * the regions that we started with.
4593 Editor::get_regions_from_selection ()
4595 return get_equivalent_regions (selection->regions, ARDOUR::Properties::edit.property_id);
4598 /** Get regions using the following method:
4600 * Make an initial region list using the selected regions, unless
4601 * the edit point is `mouse' and the mouse is over an unselected
4602 * region. In this case, start with just that region.
4604 * Then, make an initial track list of the tracks that these
4605 * regions are on, and if the edit point is not `mouse', add the
4608 * Look at this track list and add any other tracks that are on the
4609 * same active edit-enabled route group as one of the initial tracks.
4611 * Finally take the initial region list and add any regions that are
4612 * under the edit point on one of the tracks on the track list to get
4613 * the returned region list.
4615 * The rationale here is that the mouse edit point is special in that
4616 * its position describes both a time and a track; the other edit
4617 * modes only describe a time. Hence if the edit point is `mouse' we
4618 * ignore selected tracks, as we assume the user means something by
4619 * pointing at a particular track. Also in this case we take note of
4620 * the region directly under the edit point, as there is always just one
4621 * (rather than possibly several with non-mouse edit points).
4625 Editor::get_regions_from_selection_and_edit_point ()
4627 RegionSelection regions;
4629 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4630 regions.add (entered_regionview);
4632 regions = selection->regions;
4635 TrackViewList tracks;
4637 if (_edit_point != EditAtMouse) {
4638 tracks = selection->tracks;
4641 /* Add any other tracks that have regions that are in the same
4642 edit-activated route group as one of our regions.
4644 for (RegionSelection::iterator i = regions.begin (); i != regions.end(); ++i) {
4646 RouteGroup* g = (*i)->get_time_axis_view().route_group ();
4648 if (g && g->is_active() && g->is_edit()) {
4649 tracks.add (axis_views_from_routes (g->route_list()));
4653 if (!tracks.empty()) {
4654 /* now find regions that are at the edit position on those tracks */
4655 framepos_t const where = get_preferred_edit_position ();
4656 get_regions_at (regions, where, tracks);
4662 /** Start with regions that are selected, or the entered regionview if none are selected.
4663 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4664 * of the regions that we started with.
4668 Editor::get_regions_from_selection_and_entered ()
4670 RegionSelection regions = selection->regions;
4672 if (regions.empty() && entered_regionview) {
4673 regions.add (entered_regionview);
4676 return get_equivalent_regions (regions, ARDOUR::Properties::edit.property_id);
4680 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions)
4682 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4684 RouteTimeAxisView* tatv;
4686 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4688 boost::shared_ptr<Playlist> pl;
4689 vector<boost::shared_ptr<Region> > results;
4691 boost::shared_ptr<Track> tr;
4693 if ((tr = tatv->track()) == 0) {
4698 if ((pl = (tr->playlist())) != 0) {
4699 pl->get_region_list_equivalent_regions (region, results);
4702 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4703 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4704 regions.push_back (marv);
4713 Editor::show_rhythm_ferret ()
4715 if (rhythm_ferret == 0) {
4716 rhythm_ferret = new RhythmFerret(*this);
4719 rhythm_ferret->set_session (_session);
4720 rhythm_ferret->show ();
4721 rhythm_ferret->present ();
4725 Editor::first_idle ()
4727 MessageDialog* dialog = 0;
4729 if (track_views.size() > 1) {
4730 dialog = new MessageDialog (*this,
4731 string_compose (_("Please wait while %1 loads visual data"), PROGRAM_NAME),
4736 ARDOUR_UI::instance()->flush_pending ();
4739 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4743 // first idle adds route children (automation tracks), so we need to redisplay here
4744 _routes->redisplay ();
4752 Editor::_idle_resize (gpointer arg)
4754 return ((Editor*)arg)->idle_resize ();
4758 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4760 if (resize_idle_id < 0) {
4761 resize_idle_id = g_idle_add (_idle_resize, this);
4762 _pending_resize_amount = 0;
4765 /* make a note of the smallest resulting height, so that we can clamp the
4766 lower limit at TimeAxisView::hSmall */
4768 int32_t min_resulting = INT32_MAX;
4770 _pending_resize_amount += h;
4771 _pending_resize_view = view;
4773 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4775 if (selection->tracks.contains (_pending_resize_view)) {
4776 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4777 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4781 if (min_resulting < 0) {
4786 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4787 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4791 /** Handle pending resizing of tracks */
4793 Editor::idle_resize ()
4795 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4797 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4798 selection->tracks.contains (_pending_resize_view)) {
4800 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4801 if (*i != _pending_resize_view) {
4802 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4807 _pending_resize_amount = 0;
4809 _group_tabs->set_dirty ();
4810 resize_idle_id = -1;
4818 ENSURE_GUI_THREAD (*this, &Editor::located);
4820 playhead_cursor->set_position (_session->audible_frame ());
4821 if (_follow_playhead && !_pending_initial_locate) {
4822 reset_x_origin_to_follow_playhead ();
4825 _pending_locate_request = false;
4826 _pending_initial_locate = false;
4830 Editor::region_view_added (RegionView *)
4832 _summary->set_dirty ();
4836 Editor::region_view_removed ()
4838 _summary->set_dirty ();
4842 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4844 TrackViewList::const_iterator j = track_views.begin ();
4845 while (j != track_views.end()) {
4846 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4847 if (rtv && rtv->route() == r) {
4858 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4862 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4863 TimeAxisView* tv = axis_view_from_route (*i);
4874 Editor::handle_new_route (RouteList& routes)
4876 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4878 RouteTimeAxisView *rtv;
4879 list<RouteTimeAxisView*> new_views;
4881 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4882 boost::shared_ptr<Route> route = (*x);
4884 if (route->is_hidden() || route->is_monitor()) {
4888 DataType dt = route->input()->default_type();
4890 if (dt == ARDOUR::DataType::AUDIO) {
4891 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4892 rtv->set_route (route);
4893 } else if (dt == ARDOUR::DataType::MIDI) {
4894 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4895 rtv->set_route (route);
4897 throw unknown_type();
4900 new_views.push_back (rtv);
4901 track_views.push_back (rtv);
4903 rtv->effective_gain_display ();
4905 if (internal_editing()) {
4906 rtv->enter_internal_edit_mode ();
4908 rtv->leave_internal_edit_mode ();
4911 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4912 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4915 _routes->routes_added (new_views);
4916 _summary->routes_added (new_views);
4918 if (show_editor_mixer_when_tracks_arrive) {
4919 show_editor_mixer (true);
4922 editor_list_button.set_sensitive (true);
4926 Editor::timeaxisview_deleted (TimeAxisView *tv)
4928 if (_session && _session->deletion_in_progress()) {
4929 /* the situation is under control */
4933 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4935 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4937 _routes->route_removed (tv);
4939 if (tv == entered_track) {
4943 TimeAxisView::Children c = tv->get_child_list ();
4944 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4945 if (entered_track == i->get()) {
4950 /* remove it from the list of track views */
4952 TrackViewList::iterator i;
4954 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4955 i = track_views.erase (i);
4958 /* update whatever the current mixer strip is displaying, if revelant */
4960 boost::shared_ptr<Route> route;
4963 route = rtav->route ();
4966 if (current_mixer_strip && current_mixer_strip->route() == route) {
4968 TimeAxisView* next_tv;
4970 if (track_views.empty()) {
4972 } else if (i == track_views.end()) {
4973 next_tv = track_views.front();
4980 set_selected_mixer_strip (*next_tv);
4982 /* make the editor mixer strip go away setting the
4983 * button to inactive (which also unticks the menu option)
4986 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4992 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4994 if (apply_to_selection) {
4995 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4997 TrackSelection::iterator j = i;
5000 hide_track_in_display (*i, false);
5005 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
5007 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
5008 // this will hide the mixer strip
5009 set_selected_mixer_strip (*tv);
5012 _routes->hide_track_in_display (*tv);
5017 Editor::sync_track_view_list_and_routes ()
5019 track_views = TrackViewList (_routes->views ());
5021 _summary->set_dirty ();
5022 _group_tabs->set_dirty ();
5024 return false; // do not call again (until needed)
5028 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5030 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5035 /** Find a RouteTimeAxisView by the ID of its route */
5037 Editor::get_route_view_by_route_id (PBD::ID& id) const
5039 RouteTimeAxisView* v;
5041 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5042 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5043 if(v->route()->id() == id) {
5053 Editor::fit_route_group (RouteGroup *g)
5055 TrackViewList ts = axis_views_from_routes (g->route_list ());
5060 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5062 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5065 _session->cancel_audition ();
5069 if (_session->is_auditioning()) {
5070 _session->cancel_audition ();
5071 if (r == last_audition_region) {
5076 _session->audition_region (r);
5077 last_audition_region = r;
5082 Editor::hide_a_region (boost::shared_ptr<Region> r)
5084 r->set_hidden (true);
5088 Editor::show_a_region (boost::shared_ptr<Region> r)
5090 r->set_hidden (false);
5094 Editor::audition_region_from_region_list ()
5096 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5100 Editor::hide_region_from_region_list ()
5102 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5106 Editor::show_region_in_region_list ()
5108 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5112 Editor::step_edit_status_change (bool yn)
5115 start_step_editing ();
5117 stop_step_editing ();
5122 Editor::start_step_editing ()
5124 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5128 Editor::stop_step_editing ()
5130 step_edit_connection.disconnect ();
5134 Editor::check_step_edit ()
5136 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5137 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5139 mtv->check_step_edit ();
5143 return true; // do it again, till we stop
5147 Editor::scroll_press (Direction dir)
5149 ++_scroll_callbacks;
5151 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5152 /* delay the first auto-repeat */
5158 scroll_backward (1);
5166 scroll_tracks_up_line ();
5170 scroll_tracks_down_line ();
5174 /* do hacky auto-repeat */
5175 if (!_scroll_connection.connected ()) {
5177 _scroll_connection = Glib::signal_timeout().connect (
5178 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5181 _scroll_callbacks = 0;
5188 Editor::scroll_release ()
5190 _scroll_connection.disconnect ();
5193 /** Queue a change for the Editor viewport x origin to follow the playhead */
5195 Editor::reset_x_origin_to_follow_playhead ()
5197 framepos_t const frame = playhead_cursor->current_frame;
5199 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5201 if (_session->transport_speed() < 0) {
5203 if (frame > (current_page_frames() / 2)) {
5204 center_screen (frame-(current_page_frames()/2));
5206 center_screen (current_page_frames()/2);
5211 if (frame < leftmost_frame) {
5214 if (_session->transport_rolling()) {
5215 /* rolling; end up with the playhead at the right of the page */
5216 l = frame - current_page_frames ();
5218 /* not rolling: end up with the playhead 3/4 of the way along the page */
5219 l = frame - (3 * current_page_frames() / 4);
5226 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5229 if (_session->transport_rolling()) {
5230 /* rolling: end up with the playhead on the left of the page */
5231 center_screen_internal (frame + (current_page_frames() / 2), current_page_frames ());
5233 /* not rolling: end up with the playhead 1/4 of the way along the page */
5234 center_screen_internal (frame + (current_page_frames() / 4), current_page_frames ());
5242 Editor::super_rapid_screen_update ()
5244 if (!_session || !_session->engine().running()) {
5248 /* METERING / MIXER STRIPS */
5250 /* update track meters, if required */
5251 if (is_mapped() && meters_running) {
5252 RouteTimeAxisView* rtv;
5253 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5254 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5255 rtv->fast_update ();
5260 /* and any current mixer strip */
5261 if (current_mixer_strip) {
5262 current_mixer_strip->fast_update ();
5265 /* PLAYHEAD AND VIEWPORT */
5267 framepos_t const frame = _session->audible_frame();
5269 /* There are a few reasons why we might not update the playhead / viewport stuff:
5271 * 1. we don't update things when there's a pending locate request, otherwise
5272 * when the editor requests a locate there is a chance that this method
5273 * will move the playhead before the locate request is processed, causing
5275 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5276 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5279 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5281 last_update_frame = frame;
5283 if (!_dragging_playhead) {
5284 playhead_cursor->set_position (frame);
5287 if (!_stationary_playhead) {
5289 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0) {
5290 reset_x_origin_to_follow_playhead ();
5295 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5299 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5300 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5301 if (target <= 0.0) {
5304 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5305 target = (target * 0.15) + (current * 0.85);
5311 set_horizontal_position (current);
5320 Editor::session_going_away ()
5322 _have_idled = false;
5324 _session_connections.drop_connections ();
5326 super_rapid_screen_update_connection.disconnect ();
5328 selection->clear ();
5329 cut_buffer->clear ();
5331 clicked_regionview = 0;
5332 clicked_axisview = 0;
5333 clicked_routeview = 0;
5334 clicked_crossfadeview = 0;
5335 entered_regionview = 0;
5337 last_update_frame = 0;
5340 playhead_cursor->canvas_item.hide ();
5342 /* rip everything out of the list displays */
5346 _route_groups->clear ();
5348 /* do this first so that deleting a track doesn't reset cms to null
5349 and thus cause a leak.
5352 if (current_mixer_strip) {
5353 if (current_mixer_strip->get_parent() != 0) {
5354 global_hpacker.remove (*current_mixer_strip);
5356 delete current_mixer_strip;
5357 current_mixer_strip = 0;
5360 /* delete all trackviews */
5362 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5365 track_views.clear ();
5367 zoom_range_clock->set_session (0);
5368 nudge_clock->set_session (0);
5370 editor_list_button.set_active(false);
5371 editor_list_button.set_sensitive(false);
5373 /* clear tempo/meter rulers */
5374 remove_metric_marks ();
5376 clear_marker_display ();
5378 delete current_bbt_points;
5379 current_bbt_points = 0;
5381 /* get rid of any existing editor mixer strip */
5383 WindowTitle title(Glib::get_application_name());
5384 title += _("Editor");
5386 set_title (title.get_string());
5388 SessionHandlePtr::session_going_away ();
5393 Editor::show_editor_list (bool yn)
5396 _the_notebook.show ();
5398 _the_notebook.hide ();
5403 Editor::change_region_layering_order ()
5405 framepos_t const position = get_preferred_edit_position ();
5407 if (!clicked_routeview) {
5408 if (layering_order_editor) {
5409 layering_order_editor->hide ();
5414 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5420 boost::shared_ptr<Playlist> pl = track->playlist();
5426 if (layering_order_editor == 0) {
5427 layering_order_editor = new RegionLayeringOrderEditor(*this);
5430 layering_order_editor->set_context (clicked_routeview->name(), _session, pl, position);
5431 layering_order_editor->maybe_present ();
5435 Editor::update_region_layering_order_editor ()
5437 if (layering_order_editor && layering_order_editor->is_visible ()) {
5438 change_region_layering_order ();
5443 Editor::setup_fade_images ()
5445 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-in-linear")));
5446 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-in-short-cut")));
5447 _fade_in_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-in-slow-cut")));
5448 _fade_in_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-in-fast-cut")));
5449 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-in-long-cut")));
5451 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("crossfade-out-linear")));
5452 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("crossfade-out-short-cut")));
5453 _fade_out_images[FadeLogB] = new Gtk::Image (get_icon_path (X_("crossfade-out-slow-cut")));
5454 _fade_out_images[FadeLogA] = new Gtk::Image (get_icon_path (X_("crossfade-out-fast-cut")));
5455 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
5459 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5461 Editor::action_menu_item (std::string const & name)
5463 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5466 return *manage (a->create_menu_item ());
5470 Editor::resize_text_widgets ()
5472 set_size_request_to_display_given_text (edit_mode_selector, edit_mode_strings, COMBO_FUDGE+10, 15);
5473 set_size_request_to_display_given_text (zoom_focus_selector, zoom_focus_strings, COMBO_FUDGE+10, 15);
5474 set_size_request_to_display_given_text (snap_type_selector, snap_type_strings, COMBO_FUDGE+10, 15);
5475 set_size_request_to_display_given_text (snap_mode_selector, snap_mode_strings, COMBO_FUDGE+10, 15);
5476 set_size_request_to_display_given_text (edit_point_selector, edit_point_strings, COMBO_FUDGE+10, 15);
5480 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5482 EventBox* b = manage (new EventBox);
5483 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5484 Label* l = manage (new Label (name));
5488 _the_notebook.append_page (widget, *b);
5492 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5494 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5495 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5498 if (ev->type == GDK_2BUTTON_PRESS) {
5500 /* double-click on a notebook tab shrinks or expands the notebook */
5502 if (_notebook_shrunk) {
5503 edit_pane.set_position (pre_maximal_horizontal_pane_position);
5504 _notebook_shrunk = false;
5506 pre_maximal_horizontal_pane_position = edit_pane.get_position ();
5507 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5508 _notebook_shrunk = true;
5516 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5518 using namespace Menu_Helpers;
5520 MenuList& items = _control_point_context_menu.items ();
5523 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5524 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5525 if (!can_remove_control_point (item)) {
5526 items.back().set_sensitive (false);
5529 _control_point_context_menu.popup (event->button.button, event->button.time);