2 Copyright (C) 2000-2009 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /* Note: public Editor methods are documented in public_editor.h */
30 #include "ardour_ui.h"
32 * ardour_ui.h include was moved to the top of the list
33 * due to a conflicting definition of 'Style' between
34 * Apple's MacTypes.h and BarController.
37 #include <boost/none.hpp>
39 #include <sigc++/bind.h>
41 #include "pbd/convert.h"
42 #include "pbd/error.h"
43 #include "pbd/enumwriter.h"
44 #include "pbd/memento_command.h"
45 #include "pbd/unknown_type.h"
46 #include "pbd/unwind.h"
47 #include "pbd/stacktrace.h"
49 #include <glibmm/miscutils.h>
50 #include <gtkmm/image.h>
51 #include <gdkmm/color.h>
52 #include <gdkmm/bitmap.h>
54 #include "gtkmm2ext/bindings.h"
55 #include "gtkmm2ext/grouped_buttons.h"
56 #include "gtkmm2ext/gtk_ui.h"
57 #include "gtkmm2ext/tearoff.h"
58 #include "gtkmm2ext/utils.h"
59 #include "gtkmm2ext/window_title.h"
60 #include "gtkmm2ext/choice.h"
61 #include "gtkmm2ext/cell_renderer_pixbuf_toggle.h"
63 #include "ardour/audio_track.h"
64 #include "ardour/audioengine.h"
65 #include "ardour/audioregion.h"
66 #include "ardour/location.h"
67 #include "ardour/profile.h"
68 #include "ardour/route_group.h"
69 #include "ardour/session_playlists.h"
70 #include "ardour/tempo.h"
71 #include "ardour/utils.h"
73 #include "control_protocol/control_protocol.h"
77 #include "analysis_window.h"
78 #include "audio_clock.h"
79 #include "audio_region_view.h"
80 #include "audio_streamview.h"
81 #include "audio_time_axis.h"
82 #include "automation_time_axis.h"
83 #include "bundle_manager.h"
84 #include "canvas-noevent-text.h"
85 #include "canvas_impl.h"
86 #include "crossfade_edit.h"
90 #include "editor_cursors.h"
91 #include "editor_drag.h"
92 #include "editor_group_tabs.h"
93 #include "editor_locations.h"
94 #include "editor_regions.h"
95 #include "editor_route_groups.h"
96 #include "editor_routes.h"
97 #include "editor_snapshots.h"
98 #include "editor_summary.h"
99 #include "global_port_matrix.h"
100 #include "gui_object.h"
101 #include "gui_thread.h"
102 #include "keyboard.h"
104 #include "midi_time_axis.h"
105 #include "mixer_strip.h"
106 #include "mixer_ui.h"
107 #include "mouse_cursors.h"
108 #include "playlist_selector.h"
109 #include "public_editor.h"
110 #include "region_layering_order_editor.h"
111 #include "rgb_macros.h"
112 #include "rhythm_ferret.h"
113 #include "selection.h"
115 #include "simpleline.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 #include "imageframe_socket_handler.h"
127 using namespace ARDOUR;
130 using namespace Glib;
131 using namespace Gtkmm2ext;
132 using namespace Editing;
134 using PBD::internationalize;
136 using Gtkmm2ext::Keyboard;
138 const double Editor::timebar_height = 15.0;
140 static const gchar *_snap_type_strings[] = {
142 N_("Timecode Frames"),
143 N_("Timecode Seconds"),
144 N_("Timecode Minutes"),
174 static const gchar *_snap_mode_strings[] = {
181 static const gchar *_edit_point_strings[] = {
188 static const gchar *_zoom_focus_strings[] = {
198 #ifdef USE_RUBBERBAND
199 static const gchar *_rb_opt_strings[] = {
202 N_("Balanced multitimbral mixture"),
203 N_("Unpitched percussion with stable notes"),
204 N_("Crisp monophonic instrumental"),
205 N_("Unpitched solo percussion"),
206 N_("Resample without preserving pitch"),
212 pane_size_watcher (Paned* pane)
214 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
218 Quartz: impossible to access
220 so stop that by preventing it from ever getting too narrow. 35
221 pixels is basically a rough guess at the tab width.
226 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
228 gint pos = pane->get_position ();
230 if (pos > max_width_of_lhs) {
231 pane->set_position (max_width_of_lhs);
236 : VisibilityTracker (*((Gtk::Window*) this))
237 , _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
239 /* time display buttons */
240 , minsec_label (_("Mins:Secs"))
241 , bbt_label (_("Bars:Beats"))
242 , timecode_label (_("Timecode"))
243 , samples_label (_("Samples"))
244 , tempo_label (_("Tempo"))
245 , meter_label (_("Meter"))
246 , mark_label (_("Location Markers"))
247 , range_mark_label (_("Range Markers"))
248 , transport_mark_label (_("Loop/Punch Ranges"))
249 , cd_mark_label (_("CD Markers"))
250 , videotl_label (_("Video Timeline"))
251 , edit_packer (4, 4, true)
253 /* the values here don't matter: layout widgets
254 reset them as needed.
257 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
259 /* tool bar related */
261 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
263 , toolbar_selection_clock_table (2,3)
265 , automation_mode_button (_("mode"))
267 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
270 , image_socket_listener(0)
275 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
276 , meters_running(false)
277 , _pending_locate_request (false)
278 , _pending_initial_locate (false)
279 , _last_cut_copy_source_track (0)
281 , _region_selection_change_updates_region_list (true)
282 , _following_mixer_selection (false)
283 , _control_point_toggled_on_press (false)
284 , _stepping_axis_view (0)
288 /* we are a singleton */
290 PublicEditor::_instance = this;
294 selection = new Selection (this);
295 cut_buffer = new Selection (this);
297 clicked_regionview = 0;
298 clicked_axisview = 0;
299 clicked_routeview = 0;
300 clicked_control_point = 0;
301 last_update_frame = 0;
302 pre_press_cursor = 0;
303 _drags = new DragManager (this);
304 current_mixer_strip = 0;
307 snap_type_strings = I18N (_snap_type_strings);
308 snap_mode_strings = I18N (_snap_mode_strings);
309 zoom_focus_strings = I18N (_zoom_focus_strings);
310 edit_point_strings = I18N (_edit_point_strings);
311 #ifdef USE_RUBBERBAND
312 rb_opt_strings = I18N (_rb_opt_strings);
316 snap_threshold = 5.0;
317 bbt_beat_subdivision = 4;
320 last_autoscroll_x = 0;
321 last_autoscroll_y = 0;
322 autoscroll_active = false;
323 autoscroll_timeout_tag = -1;
328 current_interthread_info = 0;
329 _show_measures = true;
331 show_gain_after_trim = false;
333 have_pending_keyboard_selection = false;
334 _follow_playhead = true;
335 _stationary_playhead = false;
336 editor_ruler_menu = 0;
337 no_ruler_shown_update = false;
339 range_marker_menu = 0;
340 marker_menu_item = 0;
341 tempo_or_meter_marker_menu = 0;
342 transport_marker_menu = 0;
343 new_transport_marker_menu = 0;
344 editor_mixer_strip_width = Wide;
345 show_editor_mixer_when_tracks_arrive = false;
346 region_edit_menu_split_multichannel_item = 0;
347 region_edit_menu_split_item = 0;
350 current_stepping_trackview = 0;
352 entered_regionview = 0;
354 clear_entered_track = false;
357 button_release_can_deselect = true;
358 _dragging_playhead = false;
359 _dragging_edit_point = false;
360 select_new_marker = false;
362 layering_order_editor = 0;
363 no_save_visual = false;
365 within_track_canvas = false;
367 scrubbing_direction = 0;
371 location_marker_color = ARDOUR_UI::config()->canvasvar_LocationMarker.get();
372 location_range_color = ARDOUR_UI::config()->canvasvar_LocationRange.get();
373 location_cd_marker_color = ARDOUR_UI::config()->canvasvar_LocationCDMarker.get();
374 location_loop_color = ARDOUR_UI::config()->canvasvar_LocationLoop.get();
375 location_punch_color = ARDOUR_UI::config()->canvasvar_LocationPunch.get();
377 _edit_point = EditAtMouse;
378 _internal_editing = false;
379 current_canvas_cursor = 0;
381 frames_per_unit = 2048; /* too early to use reset_zoom () */
383 _scroll_callbacks = 0;
385 zoom_focus = ZoomFocusLeft;
386 set_zoom_focus (ZoomFocusLeft);
387 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
389 bbt_label.set_name ("EditorRulerLabel");
390 bbt_label.set_size_request (-1, (int)timebar_height);
391 bbt_label.set_alignment (1.0, 0.5);
392 bbt_label.set_padding (5,0);
394 bbt_label.set_no_show_all();
395 minsec_label.set_name ("EditorRulerLabel");
396 minsec_label.set_size_request (-1, (int)timebar_height);
397 minsec_label.set_alignment (1.0, 0.5);
398 minsec_label.set_padding (5,0);
399 minsec_label.hide ();
400 minsec_label.set_no_show_all();
401 timecode_label.set_name ("EditorRulerLabel");
402 timecode_label.set_size_request (-1, (int)timebar_height);
403 timecode_label.set_alignment (1.0, 0.5);
404 timecode_label.set_padding (5,0);
405 timecode_label.hide ();
406 timecode_label.set_no_show_all();
407 samples_label.set_name ("EditorRulerLabel");
408 samples_label.set_size_request (-1, (int)timebar_height);
409 samples_label.set_alignment (1.0, 0.5);
410 samples_label.set_padding (5,0);
411 samples_label.hide ();
412 samples_label.set_no_show_all();
414 tempo_label.set_name ("EditorRulerLabel");
415 tempo_label.set_size_request (-1, (int)timebar_height);
416 tempo_label.set_alignment (1.0, 0.5);
417 tempo_label.set_padding (5,0);
419 tempo_label.set_no_show_all();
421 meter_label.set_name ("EditorRulerLabel");
422 meter_label.set_size_request (-1, (int)timebar_height);
423 meter_label.set_alignment (1.0, 0.5);
424 meter_label.set_padding (5,0);
426 meter_label.set_no_show_all();
428 mark_label.set_name ("EditorRulerLabel");
429 mark_label.set_size_request (-1, (int)timebar_height);
430 mark_label.set_alignment (1.0, 0.5);
431 mark_label.set_padding (5,0);
433 mark_label.set_no_show_all();
435 cd_mark_label.set_name ("EditorRulerLabel");
436 cd_mark_label.set_size_request (-1, (int)timebar_height);
437 cd_mark_label.set_alignment (1.0, 0.5);
438 cd_mark_label.set_padding (5,0);
439 cd_mark_label.hide();
440 cd_mark_label.set_no_show_all();
442 videotl_bar_height = 4;
443 videotl_label.set_name ("EditorRulerLabel");
444 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
445 videotl_label.set_alignment (1.0, 0.5);
446 videotl_label.set_padding (5,0);
447 videotl_label.hide();
448 videotl_label.set_no_show_all();
450 range_mark_label.set_name ("EditorRulerLabel");
451 range_mark_label.set_size_request (-1, (int)timebar_height);
452 range_mark_label.set_alignment (1.0, 0.5);
453 range_mark_label.set_padding (5,0);
454 range_mark_label.hide();
455 range_mark_label.set_no_show_all();
457 transport_mark_label.set_name ("EditorRulerLabel");
458 transport_mark_label.set_size_request (-1, (int)timebar_height);
459 transport_mark_label.set_alignment (1.0, 0.5);
460 transport_mark_label.set_padding (5,0);
461 transport_mark_label.hide();
462 transport_mark_label.set_no_show_all();
464 initialize_rulers ();
465 initialize_canvas ();
467 _summary = new EditorSummary (this);
469 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
470 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
472 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
474 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
475 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
477 edit_controls_vbox.set_spacing (0);
478 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
479 track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
481 HBox* h = manage (new HBox);
482 _group_tabs = new EditorGroupTabs (this);
483 h->pack_start (*_group_tabs, PACK_SHRINK);
484 h->pack_start (edit_controls_vbox);
485 controls_layout.add (*h);
487 controls_layout.set_name ("EditControlsBase");
488 controls_layout.add_events (Gdk::SCROLL_MASK);
489 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
491 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
492 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
494 _cursors = new MouseCursors;
496 ArdourCanvas::Canvas* time_pad = manage(new ArdourCanvas::Canvas());
497 ArdourCanvas::SimpleLine* pad_line_1 = manage(new ArdourCanvas::SimpleLine(*time_pad->root(),
498 0.0, 1.0, 100.0, 1.0));
500 pad_line_1->property_color_rgba() = 0xFF0000FF;
505 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
506 time_canvas_vbox.set_size_request (-1, -1);
508 ruler_label_event_box.add (ruler_label_vbox);
509 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
510 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
512 time_button_event_box.add (time_button_vbox);
513 time_button_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
514 time_button_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
516 /* these enable us to have a dedicated window (for cursor setting, etc.)
517 for the canvas areas.
520 track_canvas_event_box.add (*track_canvas);
522 time_canvas_event_box.add (time_canvas_vbox);
523 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
525 edit_packer.set_col_spacings (0);
526 edit_packer.set_row_spacings (0);
527 edit_packer.set_homogeneous (false);
528 edit_packer.set_border_width (0);
529 edit_packer.set_name ("EditorWindow");
531 /* labels for the rulers */
532 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
533 /* labels for the marker "tracks" */
534 edit_packer.attach (time_button_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
536 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
538 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
540 edit_packer.attach (track_canvas_event_box, 2, 3, 1, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
542 bottom_hbox.set_border_width (2);
543 bottom_hbox.set_spacing (3);
545 _route_groups = new EditorRouteGroups (this);
546 _routes = new EditorRoutes (this);
547 _regions = new EditorRegions (this);
548 _snapshots = new EditorSnapshots (this);
549 _locations = new EditorLocations (this);
551 add_notebook_page (_("Regions"), _regions->widget ());
552 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
553 add_notebook_page (_("Snapshots"), _snapshots->widget ());
554 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
555 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
557 _the_notebook.set_show_tabs (true);
558 _the_notebook.set_scrollable (true);
559 _the_notebook.popup_disable ();
560 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
561 _the_notebook.show_all ();
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 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 */
640 /* when we start using our own keybinding system for the editor, this
641 * will be uncommented
647 _snap_type = SnapToBeat;
648 set_snap_to (_snap_type);
649 _snap_mode = SnapOff;
650 set_snap_mode (_snap_mode);
651 set_mouse_mode (MouseObject, true);
652 pre_internal_mouse_mode = MouseObject;
653 pre_internal_snap_type = _snap_type;
654 pre_internal_snap_mode = _snap_mode;
655 internal_snap_type = _snap_type;
656 internal_snap_mode = _snap_mode;
657 set_edit_point_preference (EditAtMouse, true);
659 _playlist_selector = new PlaylistSelector();
660 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
662 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
666 nudge_forward_button.set_name ("zoom button");
667 nudge_forward_button.add_elements (ArdourButton::FlatFace);
668 nudge_forward_button.set_image(::get_icon("nudge_right"));
670 nudge_backward_button.set_name ("zoom button");
671 nudge_backward_button.add_elements (ArdourButton::FlatFace);
672 nudge_backward_button.set_image(::get_icon("nudge_left"));
674 fade_context_menu.set_name ("ArdourContextMenu");
676 /* icons, titles, WM stuff */
678 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
679 Glib::RefPtr<Gdk::Pixbuf> icon;
681 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
682 window_icons.push_back (icon);
684 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
685 window_icons.push_back (icon);
687 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
688 window_icons.push_back (icon);
690 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
691 window_icons.push_back (icon);
693 if (!window_icons.empty()) {
694 // set_icon_list (window_icons);
695 set_default_icon_list (window_icons);
698 WindowTitle title(Glib::get_application_name());
699 title += _("Editor");
700 set_title (title.get_string());
701 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
704 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
706 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
707 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
709 Gtkmm2ext::Keyboard::the_keyboard().ShiftReleased.connect (sigc::mem_fun (*this, &Editor::shift_key_released));
711 /* allow external control surfaces/protocols to do various things */
713 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
714 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
715 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
716 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
717 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
718 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
719 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
720 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
721 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
722 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
723 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
724 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
725 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
726 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
728 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
729 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
730 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
731 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
732 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
734 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
736 /* problematic: has to return a value and thus cannot be x-thread */
738 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
740 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
742 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
744 _ignore_region_action = false;
745 _last_region_menu_was_main = false;
746 _popup_region_menu_item = 0;
748 _show_marker_lines = false;
749 _over_region_trim_target = false;
751 /* Button bindings */
753 button_bindings = new Bindings;
755 XMLNode* node = button_settings();
757 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
758 button_bindings->load (**i);
765 setup_fade_images ();
771 if(image_socket_listener) {
772 if(image_socket_listener->is_connected())
774 image_socket_listener->close_connection() ;
777 delete image_socket_listener ;
778 image_socket_listener = 0 ;
782 delete button_bindings;
784 delete _route_groups;
790 Editor::button_settings () const
792 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
793 XMLNode* node = find_named_node (*settings, X_("Buttons"));
796 node = new XMLNode (X_("Buttons"));
803 Editor::add_toplevel_controls (Container& cont)
805 vpacker.pack_start (cont, false, false);
810 Editor::get_smart_mode () const
812 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
816 Editor::catch_vanishing_regionview (RegionView *rv)
818 /* note: the selection will take care of the vanishing
819 audioregionview by itself.
822 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
826 if (clicked_regionview == rv) {
827 clicked_regionview = 0;
830 if (entered_regionview == rv) {
831 set_entered_regionview (0);
834 if (!_all_region_actions_sensitized) {
835 sensitize_all_region_actions (true);
838 _over_region_trim_target = false;
842 Editor::set_entered_regionview (RegionView* rv)
844 if (rv == entered_regionview) {
848 if (entered_regionview) {
849 entered_regionview->exited ();
852 if ((entered_regionview = rv) != 0) {
853 entered_regionview->entered (internal_editing ());
856 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
857 /* This RegionView entry might have changed what region actions
858 are allowed, so sensitize them all in case a key is pressed.
860 sensitize_all_region_actions (true);
865 Editor::set_entered_track (TimeAxisView* tav)
868 entered_track->exited ();
871 if ((entered_track = tav) != 0) {
872 entered_track->entered ();
877 Editor::show_window ()
879 if (!is_visible ()) {
882 /* XXX: this is a bit unfortunate; it would probably
883 be nicer if we could just call show () above rather
884 than needing the show_all ()
887 /* re-hide stuff if necessary */
888 editor_list_button_toggled ();
889 parameter_changed ("show-summary");
890 parameter_changed ("show-group-tabs");
891 parameter_changed ("show-zoom-tools");
893 /* now reset all audio_time_axis heights, because widgets might need
899 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
900 tv = (static_cast<TimeAxisView*>(*i));
904 if (current_mixer_strip) {
905 current_mixer_strip->hide_things ();
906 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
914 Editor::instant_save ()
916 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
921 _session->add_instant_xml(get_state());
923 Config->add_instant_xml(get_state());
928 Editor::zoom_adjustment_changed ()
934 double fpu = zoom_range_clock->current_duration() / _canvas_width;
935 bool clamped = clamp_frames_per_unit (fpu);
938 zoom_range_clock->set ((framepos_t) floor (fpu * _canvas_width));
945 Editor::control_vertical_zoom_in_all ()
947 tav_zoom_smooth (false, true);
951 Editor::control_vertical_zoom_out_all ()
953 tav_zoom_smooth (true, true);
957 Editor::control_vertical_zoom_in_selected ()
959 tav_zoom_smooth (false, false);
963 Editor::control_vertical_zoom_out_selected ()
965 tav_zoom_smooth (true, false);
969 Editor::control_view (uint32_t view)
971 goto_visual_state (view);
975 Editor::control_unselect ()
977 selection->clear_tracks ();
981 Editor::control_select (uint32_t rid, Selection::Operation op)
983 /* handles the (static) signal from the ControlProtocol class that
984 * requests setting the selected track to a given RID
991 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
997 TimeAxisView* tav = axis_view_from_route (r);
1001 case Selection::Add:
1002 selection->add (tav);
1004 case Selection::Toggle:
1005 selection->toggle (tav);
1007 case Selection::Extend:
1009 case Selection::Set:
1010 selection->set (tav);
1014 selection->clear_tracks ();
1019 Editor::control_step_tracks_up ()
1021 scroll_tracks_up_line ();
1025 Editor::control_step_tracks_down ()
1027 scroll_tracks_down_line ();
1031 Editor::control_scroll (float fraction)
1033 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1039 double step = fraction * current_page_frames();
1042 _control_scroll_target is an optional<T>
1044 it acts like a pointer to an framepos_t, with
1045 a operator conversion to boolean to check
1046 that it has a value could possibly use
1047 playhead_cursor->current_frame to store the
1048 value and a boolean in the class to know
1049 when it's out of date
1052 if (!_control_scroll_target) {
1053 _control_scroll_target = _session->transport_frame();
1054 _dragging_playhead = true;
1057 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1058 *_control_scroll_target = 0;
1059 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1060 *_control_scroll_target = max_framepos - (current_page_frames()*2); // allow room for slop in where the PH is on the screen
1062 *_control_scroll_target += (framepos_t) floor (step);
1065 /* move visuals, we'll catch up with it later */
1067 playhead_cursor->set_position (*_control_scroll_target);
1068 UpdateAllTransportClocks (*_control_scroll_target);
1070 if (*_control_scroll_target > (current_page_frames() / 2)) {
1071 /* try to center PH in window */
1072 reset_x_origin (*_control_scroll_target - (current_page_frames()/2));
1078 Now we do a timeout to actually bring the session to the right place
1079 according to the playhead. This is to avoid reading disk buffers on every
1080 call to control_scroll, which is driven by ScrollTimeline and therefore
1081 probably by a control surface wheel which can generate lots of events.
1083 /* cancel the existing timeout */
1085 control_scroll_connection.disconnect ();
1087 /* add the next timeout */
1089 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1093 Editor::deferred_control_scroll (framepos_t /*target*/)
1095 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1096 // reset for next stream
1097 _control_scroll_target = boost::none;
1098 _dragging_playhead = false;
1103 Editor::access_action (std::string action_group, std::string action_item)
1109 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1112 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1120 Editor::on_realize ()
1122 Window::on_realize ();
1127 Editor::map_position_change (framepos_t frame)
1129 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1131 if (_session == 0) {
1135 if (_follow_playhead) {
1136 center_screen (frame);
1139 playhead_cursor->set_position (frame);
1143 Editor::center_screen (framepos_t frame)
1145 double page = _canvas_width * frames_per_unit;
1147 /* if we're off the page, then scroll.
1150 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1151 center_screen_internal (frame, page);
1156 Editor::center_screen_internal (framepos_t frame, float page)
1161 frame -= (framepos_t) page;
1166 reset_x_origin (frame);
1171 Editor::update_title ()
1173 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1176 bool dirty = _session->dirty();
1178 string session_name;
1180 if (_session->snap_name() != _session->name()) {
1181 session_name = _session->snap_name();
1183 session_name = _session->name();
1187 session_name = "*" + session_name;
1190 WindowTitle title(session_name);
1191 title += Glib::get_application_name();
1192 set_title (title.get_string());
1194 /* ::session_going_away() will have taken care of it */
1199 Editor::set_session (Session *t)
1201 SessionHandlePtr::set_session (t);
1207 zoom_range_clock->set_session (_session);
1208 _playlist_selector->set_session (_session);
1209 nudge_clock->set_session (_session);
1210 _summary->set_session (_session);
1211 _group_tabs->set_session (_session);
1212 _route_groups->set_session (_session);
1213 _regions->set_session (_session);
1214 _snapshots->set_session (_session);
1215 _routes->set_session (_session);
1216 _locations->set_session (_session);
1218 if (rhythm_ferret) {
1219 rhythm_ferret->set_session (_session);
1222 if (analysis_window) {
1223 analysis_window->set_session (_session);
1227 sfbrowser->set_session (_session);
1230 compute_fixed_ruler_scale ();
1232 /* Make sure we have auto loop and auto punch ranges */
1234 Location* loc = _session->locations()->auto_loop_location();
1236 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1238 if (loc->start() == loc->end()) {
1239 loc->set_end (loc->start() + 1);
1242 _session->locations()->add (loc, false);
1243 _session->set_auto_loop_location (loc);
1246 loc->set_name (_("Loop"));
1249 loc = _session->locations()->auto_punch_location();
1252 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1254 if (loc->start() == loc->end()) {
1255 loc->set_end (loc->start() + 1);
1258 _session->locations()->add (loc, false);
1259 _session->set_auto_punch_location (loc);
1262 loc->set_name (_("Punch"));
1265 refresh_location_display ();
1267 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1268 the selected Marker; this needs the LocationMarker list to be available.
1270 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1271 set_state (*node, Stateful::loading_state_version);
1273 /* catch up with the playhead */
1275 _session->request_locate (playhead_cursor->current_frame);
1276 _pending_initial_locate = true;
1280 /* These signals can all be emitted by a non-GUI thread. Therefore the
1281 handlers for them must not attempt to directly interact with the GUI,
1282 but use Gtkmm2ext::UI::instance()->call_slot();
1285 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1286 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1287 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1288 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1289 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1290 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1291 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1292 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1293 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1294 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1295 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1296 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1297 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1298 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1300 playhead_cursor->canvas_item.show ();
1302 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1303 Config->map_parameters (pc);
1304 _session->config.map_parameters (pc);
1306 restore_ruler_visibility ();
1307 //tempo_map_changed (PropertyChange (0));
1308 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1310 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1311 (static_cast<TimeAxisView*>(*i))->set_samples_per_unit (frames_per_unit);
1314 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1315 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1318 switch (_snap_type) {
1319 case SnapToRegionStart:
1320 case SnapToRegionEnd:
1321 case SnapToRegionSync:
1322 case SnapToRegionBoundary:
1323 build_region_boundary_cache ();
1330 /* register for undo history */
1331 _session->register_with_memento_command_factory(id(), this);
1333 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1335 start_updating_meters ();
1339 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1341 if (a->get_name() == "RegionMenu") {
1342 /* When the main menu's region menu is opened, we setup the actions so that they look right
1343 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1344 so we resensitize all region actions when the entered regionview or the region selection
1345 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1346 happens after the region context menu is opened. So we set a flag here, too.
1350 sensitize_the_right_region_actions ();
1351 _last_region_menu_was_main = true;
1356 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1358 using namespace Menu_Helpers;
1360 void (Editor::*emf)(FadeShape);
1361 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1364 images = &_xfade_in_images;
1365 emf = &Editor::set_fade_in_shape;
1367 images = &_xfade_out_images;
1368 emf = &Editor::set_fade_out_shape;
1373 _("Linear (for highly correlated material)"),
1374 *(*images)[FadeLinear],
1375 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1379 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1383 _("Constant power"),
1384 *(*images)[FadeConstantPower],
1385 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1388 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1393 *(*images)[FadeSymmetric],
1394 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1398 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1403 *(*images)[FadeSlow],
1404 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1407 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1412 *(*images)[FadeFast],
1413 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1416 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1419 /** Pop up a context menu for when the user clicks on a start crossfade */
1421 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1423 using namespace Menu_Helpers;
1425 MenuList& items (xfade_in_context_menu.items());
1427 if (items.empty()) {
1428 fill_xfade_menu (items, true);
1431 xfade_in_context_menu.popup (button, time);
1434 /** Pop up a context menu for when the user clicks on an end crossfade */
1436 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1438 using namespace Menu_Helpers;
1440 MenuList& items (xfade_out_context_menu.items());
1442 if (items.empty()) {
1443 fill_xfade_menu (items, false);
1446 xfade_out_context_menu.popup (button, time);
1450 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1452 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1454 using namespace Menu_Helpers;
1455 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1458 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1462 MenuList& items (fade_context_menu.items());
1465 switch (item_type) {
1467 case FadeInHandleItem:
1468 if (arv->audio_region()->fade_in_active()) {
1469 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1471 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1474 items.push_back (SeparatorElem());
1476 if (Profile->get_sae()) {
1478 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1479 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1486 *_fade_in_images[FadeLinear],
1487 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1496 *_fade_in_images[FadeSlow],
1497 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1500 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1505 *_fade_in_images[FadeFast],
1506 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1509 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1514 *_fade_in_images[FadeSymmetric],
1515 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1520 _("Constant power"),
1521 *_fade_in_images[FadeConstantPower],
1522 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1525 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1531 case FadeOutHandleItem:
1532 if (arv->audio_region()->fade_out_active()) {
1533 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1535 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1538 items.push_back (SeparatorElem());
1540 if (Profile->get_sae()) {
1541 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1542 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1548 *_fade_out_images[FadeLinear],
1549 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1553 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1558 *_fade_out_images[FadeSlow],
1559 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1562 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1567 *_fade_out_images[FadeFast],
1568 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1571 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1576 *_fade_out_images[FadeSymmetric],
1577 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1582 _("Constant power"),
1583 *_fade_out_images[FadeConstantPower],
1584 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1587 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1593 fatal << _("programming error: ")
1594 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1599 fade_context_menu.popup (button, time);
1603 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1605 using namespace Menu_Helpers;
1606 Menu* (Editor::*build_menu_function)();
1609 switch (item_type) {
1611 case RegionViewName:
1612 case RegionViewNameHighlight:
1613 case LeftFrameHandle:
1614 case RightFrameHandle:
1615 if (with_selection) {
1616 build_menu_function = &Editor::build_track_selection_context_menu;
1618 build_menu_function = &Editor::build_track_region_context_menu;
1623 if (with_selection) {
1624 build_menu_function = &Editor::build_track_selection_context_menu;
1626 build_menu_function = &Editor::build_track_context_menu;
1631 if (clicked_routeview->track()) {
1632 build_menu_function = &Editor::build_track_context_menu;
1634 build_menu_function = &Editor::build_track_bus_context_menu;
1639 /* probably shouldn't happen but if it does, we don't care */
1643 menu = (this->*build_menu_function)();
1644 menu->set_name ("ArdourContextMenu");
1646 /* now handle specific situations */
1648 switch (item_type) {
1650 case RegionViewName:
1651 case RegionViewNameHighlight:
1652 case LeftFrameHandle:
1653 case RightFrameHandle:
1654 if (!with_selection) {
1655 if (region_edit_menu_split_item) {
1656 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1657 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1659 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1662 if (region_edit_menu_split_multichannel_item) {
1663 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1664 region_edit_menu_split_multichannel_item->set_sensitive (true);
1666 region_edit_menu_split_multichannel_item->set_sensitive (false);
1679 /* probably shouldn't happen but if it does, we don't care */
1683 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1685 /* Bounce to disk */
1687 using namespace Menu_Helpers;
1688 MenuList& edit_items = menu->items();
1690 edit_items.push_back (SeparatorElem());
1692 switch (clicked_routeview->audio_track()->freeze_state()) {
1693 case AudioTrack::NoFreeze:
1694 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1697 case AudioTrack::Frozen:
1698 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1701 case AudioTrack::UnFrozen:
1702 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1708 if (item_type == StreamItem && clicked_routeview) {
1709 clicked_routeview->build_underlay_menu(menu);
1712 /* When the region menu is opened, we setup the actions so that they look right
1715 sensitize_the_right_region_actions ();
1716 _last_region_menu_was_main = false;
1718 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1719 menu->popup (button, time);
1723 Editor::build_track_context_menu ()
1725 using namespace Menu_Helpers;
1727 MenuList& edit_items = track_context_menu.items();
1730 add_dstream_context_items (edit_items);
1731 return &track_context_menu;
1735 Editor::build_track_bus_context_menu ()
1737 using namespace Menu_Helpers;
1739 MenuList& edit_items = track_context_menu.items();
1742 add_bus_context_items (edit_items);
1743 return &track_context_menu;
1747 Editor::build_track_region_context_menu ()
1749 using namespace Menu_Helpers;
1750 MenuList& edit_items = track_region_context_menu.items();
1753 /* we've just cleared the track region context menu, so the menu that these
1754 two items were on will have disappeared; stop them dangling.
1756 region_edit_menu_split_item = 0;
1757 region_edit_menu_split_multichannel_item = 0;
1759 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1762 boost::shared_ptr<Track> tr;
1763 boost::shared_ptr<Playlist> pl;
1765 if ((tr = rtv->track())) {
1766 add_region_context_items (edit_items, tr);
1770 add_dstream_context_items (edit_items);
1772 return &track_region_context_menu;
1776 Editor::analyze_region_selection ()
1778 if (analysis_window == 0) {
1779 analysis_window = new AnalysisWindow();
1782 analysis_window->set_session(_session);
1784 analysis_window->show_all();
1787 analysis_window->set_regionmode();
1788 analysis_window->analyze();
1790 analysis_window->present();
1794 Editor::analyze_range_selection()
1796 if (analysis_window == 0) {
1797 analysis_window = new AnalysisWindow();
1800 analysis_window->set_session(_session);
1802 analysis_window->show_all();
1805 analysis_window->set_rangemode();
1806 analysis_window->analyze();
1808 analysis_window->present();
1812 Editor::build_track_selection_context_menu ()
1814 using namespace Menu_Helpers;
1815 MenuList& edit_items = track_selection_context_menu.items();
1816 edit_items.clear ();
1818 add_selection_context_items (edit_items);
1819 // edit_items.push_back (SeparatorElem());
1820 // add_dstream_context_items (edit_items);
1822 return &track_selection_context_menu;
1826 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1828 using namespace Menu_Helpers;
1830 /* OK, stick the region submenu at the top of the list, and then add
1834 RegionSelection rs = get_regions_from_selection_and_entered ();
1836 string::size_type pos = 0;
1837 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1839 /* we have to hack up the region name because "_" has a special
1840 meaning for menu titles.
1843 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1844 menu_item_name.replace (pos, 1, "__");
1848 if (_popup_region_menu_item == 0) {
1849 _popup_region_menu_item = new MenuItem (menu_item_name);
1850 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1851 _popup_region_menu_item->show ();
1853 _popup_region_menu_item->set_label (menu_item_name);
1856 const framepos_t position = get_preferred_edit_position (false, true);
1858 edit_items.push_back (*_popup_region_menu_item);
1859 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1860 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1862 edit_items.push_back (SeparatorElem());
1865 /** Add context menu items relevant to selection ranges.
1866 * @param edit_items List to add the items to.
1869 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1871 using namespace Menu_Helpers;
1873 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1874 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1876 edit_items.push_back (SeparatorElem());
1877 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1879 edit_items.push_back (SeparatorElem());
1881 edit_items.push_back (
1883 _("Move Range Start to Previous Region Boundary"),
1884 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1888 edit_items.push_back (
1890 _("Move Range Start to Next Region Boundary"),
1891 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1895 edit_items.push_back (
1897 _("Move Range End to Previous Region Boundary"),
1898 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1902 edit_items.push_back (
1904 _("Move Range End to Next Region Boundary"),
1905 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1909 edit_items.push_back (SeparatorElem());
1910 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1911 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1913 edit_items.push_back (SeparatorElem());
1914 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1916 edit_items.push_back (SeparatorElem());
1917 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1918 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1920 edit_items.push_back (SeparatorElem());
1921 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1923 edit_items.push_back (SeparatorElem());
1924 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1925 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1926 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1928 edit_items.push_back (SeparatorElem());
1929 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1930 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1931 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1932 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1933 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1938 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1940 using namespace Menu_Helpers;
1944 Menu *play_menu = manage (new Menu);
1945 MenuList& play_items = play_menu->items();
1946 play_menu->set_name ("ArdourContextMenu");
1948 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1949 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1950 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1951 play_items.push_back (SeparatorElem());
1952 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1954 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1958 Menu *select_menu = manage (new Menu);
1959 MenuList& select_items = select_menu->items();
1960 select_menu->set_name ("ArdourContextMenu");
1962 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1963 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1964 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1965 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1966 select_items.push_back (SeparatorElem());
1967 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1968 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1969 select_items.push_back (SeparatorElem());
1970 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1971 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1972 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1973 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1974 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1975 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1976 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1978 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1982 Menu *cutnpaste_menu = manage (new Menu);
1983 MenuList& cutnpaste_items = cutnpaste_menu->items();
1984 cutnpaste_menu->set_name ("ArdourContextMenu");
1986 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1987 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1988 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1990 cutnpaste_items.push_back (SeparatorElem());
1992 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1993 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1995 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1997 /* Adding new material */
1999 edit_items.push_back (SeparatorElem());
2000 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
2001 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
2005 Menu *nudge_menu = manage (new Menu());
2006 MenuList& nudge_items = nudge_menu->items();
2007 nudge_menu->set_name ("ArdourContextMenu");
2009 edit_items.push_back (SeparatorElem());
2010 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2011 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2012 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2013 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2015 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2019 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2021 using namespace Menu_Helpers;
2025 Menu *play_menu = manage (new Menu);
2026 MenuList& play_items = play_menu->items();
2027 play_menu->set_name ("ArdourContextMenu");
2029 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2030 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2031 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2035 Menu *select_menu = manage (new Menu);
2036 MenuList& select_items = select_menu->items();
2037 select_menu->set_name ("ArdourContextMenu");
2039 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2040 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2041 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2042 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2043 select_items.push_back (SeparatorElem());
2044 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2045 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2046 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2047 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2049 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2053 Menu *cutnpaste_menu = manage (new Menu);
2054 MenuList& cutnpaste_items = cutnpaste_menu->items();
2055 cutnpaste_menu->set_name ("ArdourContextMenu");
2057 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2058 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2059 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2061 Menu *nudge_menu = manage (new Menu());
2062 MenuList& nudge_items = nudge_menu->items();
2063 nudge_menu->set_name ("ArdourContextMenu");
2065 edit_items.push_back (SeparatorElem());
2066 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2067 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2068 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2069 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2071 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2075 Editor::snap_type() const
2081 Editor::snap_mode() const
2087 Editor::set_snap_to (SnapType st)
2089 unsigned int snap_ind = (unsigned int)st;
2093 if (snap_ind > snap_type_strings.size() - 1) {
2095 _snap_type = (SnapType)snap_ind;
2098 string str = snap_type_strings[snap_ind];
2100 if (str != snap_type_selector.get_active_text()) {
2101 snap_type_selector.set_active_text (str);
2106 switch (_snap_type) {
2107 case SnapToBeatDiv128:
2108 case SnapToBeatDiv64:
2109 case SnapToBeatDiv32:
2110 case SnapToBeatDiv28:
2111 case SnapToBeatDiv24:
2112 case SnapToBeatDiv20:
2113 case SnapToBeatDiv16:
2114 case SnapToBeatDiv14:
2115 case SnapToBeatDiv12:
2116 case SnapToBeatDiv10:
2117 case SnapToBeatDiv8:
2118 case SnapToBeatDiv7:
2119 case SnapToBeatDiv6:
2120 case SnapToBeatDiv5:
2121 case SnapToBeatDiv4:
2122 case SnapToBeatDiv3:
2123 case SnapToBeatDiv2: {
2124 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2125 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2127 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_frames(),
2128 current_bbt_points_begin, current_bbt_points_end);
2129 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_frames(),
2130 current_bbt_points_begin, current_bbt_points_end);
2131 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2135 case SnapToRegionStart:
2136 case SnapToRegionEnd:
2137 case SnapToRegionSync:
2138 case SnapToRegionBoundary:
2139 build_region_boundary_cache ();
2147 SnapChanged (); /* EMIT SIGNAL */
2151 Editor::set_snap_mode (SnapMode mode)
2153 string str = snap_mode_strings[(int)mode];
2155 if (_internal_editing) {
2156 internal_snap_mode = mode;
2158 pre_internal_snap_mode = mode;
2163 if (str != snap_mode_selector.get_active_text ()) {
2164 snap_mode_selector.set_active_text (str);
2170 Editor::set_edit_point_preference (EditPoint ep, bool force)
2172 bool changed = (_edit_point != ep);
2175 string str = edit_point_strings[(int)ep];
2177 if (str != edit_point_selector.get_active_text ()) {
2178 edit_point_selector.set_active_text (str);
2181 set_canvas_cursor ();
2183 if (!force && !changed) {
2187 const char* action=NULL;
2189 switch (_edit_point) {
2190 case EditAtPlayhead:
2191 action = "edit-at-playhead";
2193 case EditAtSelectedMarker:
2194 action = "edit-at-marker";
2197 action = "edit-at-mouse";
2201 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2203 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2207 bool in_track_canvas;
2209 if (!mouse_frame (foo, in_track_canvas)) {
2210 in_track_canvas = false;
2213 reset_canvas_action_sensitivity (in_track_canvas);
2219 Editor::set_state (const XMLNode& node, int /*version*/)
2221 const XMLProperty* prop;
2228 g.base_width = default_width;
2229 g.base_height = default_height;
2233 if ((geometry = find_named_node (node, "geometry")) != 0) {
2237 if ((prop = geometry->property("x_size")) == 0) {
2238 prop = geometry->property ("x-size");
2241 g.base_width = atoi(prop->value());
2243 if ((prop = geometry->property("y_size")) == 0) {
2244 prop = geometry->property ("y-size");
2247 g.base_height = atoi(prop->value());
2250 if ((prop = geometry->property ("x_pos")) == 0) {
2251 prop = geometry->property ("x-pos");
2254 x = atoi (prop->value());
2257 if ((prop = geometry->property ("y_pos")) == 0) {
2258 prop = geometry->property ("y-pos");
2261 y = atoi (prop->value());
2265 set_default_size (g.base_width, g.base_height);
2268 if (_session && (prop = node.property ("playhead"))) {
2270 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2271 playhead_cursor->set_position (pos);
2273 playhead_cursor->set_position (0);
2276 if ((prop = node.property ("mixer-width"))) {
2277 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2280 if ((prop = node.property ("zoom-focus"))) {
2281 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2284 if ((prop = node.property ("zoom"))) {
2285 reset_zoom (PBD::atof (prop->value()));
2287 reset_zoom (frames_per_unit);
2290 if ((prop = node.property ("snap-to"))) {
2291 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2294 if ((prop = node.property ("snap-mode"))) {
2295 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2298 if ((prop = node.property ("internal-snap-to"))) {
2299 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2302 if ((prop = node.property ("internal-snap-mode"))) {
2303 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2306 if ((prop = node.property ("pre-internal-snap-to"))) {
2307 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2311 if ((prop = node.property ("pre-internal-snap-mode"))) {
2312 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2315 if ((prop = node.property ("mouse-mode"))) {
2316 MouseMode m = str2mousemode(prop->value());
2317 set_mouse_mode (m, true);
2319 set_mouse_mode (MouseObject, true);
2322 if ((prop = node.property ("left-frame")) != 0) {
2324 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2328 reset_x_origin (pos);
2332 if ((prop = node.property ("y-origin")) != 0) {
2333 reset_y_origin (atof (prop->value ()));
2336 if ((prop = node.property ("internal-edit"))) {
2337 bool yn = string_is_affirmative (prop->value());
2338 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2340 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2341 tact->set_active (!yn);
2342 tact->set_active (yn);
2346 if ((prop = node.property ("join-object-range"))) {
2347 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2348 bool yn = string_is_affirmative (prop->value());
2350 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2351 tact->set_active (!yn);
2352 tact->set_active (yn);
2354 set_mouse_mode(mouse_mode, true);
2357 if ((prop = node.property ("edit-point"))) {
2358 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2361 if ((prop = node.property ("show-measures"))) {
2362 bool yn = string_is_affirmative (prop->value());
2363 _show_measures = yn;
2364 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2366 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2367 /* do it twice to force the change */
2368 tact->set_active (!yn);
2369 tact->set_active (yn);
2373 if ((prop = node.property ("follow-playhead"))) {
2374 bool yn = string_is_affirmative (prop->value());
2375 set_follow_playhead (yn);
2376 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2378 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2379 if (tact->get_active() != yn) {
2380 tact->set_active (yn);
2385 if ((prop = node.property ("stationary-playhead"))) {
2386 bool yn = string_is_affirmative (prop->value());
2387 set_stationary_playhead (yn);
2388 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2390 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2391 if (tact->get_active() != yn) {
2392 tact->set_active (yn);
2397 if ((prop = node.property ("region-list-sort-type"))) {
2398 RegionListSortType st;
2399 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2402 if ((prop = node.property ("show-editor-mixer"))) {
2404 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2407 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2408 bool yn = string_is_affirmative (prop->value());
2410 /* do it twice to force the change */
2412 tact->set_active (!yn);
2413 tact->set_active (yn);
2416 if ((prop = node.property ("show-editor-list"))) {
2418 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2421 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2422 bool yn = string_is_affirmative (prop->value());
2424 /* do it twice to force the change */
2426 tact->set_active (!yn);
2427 tact->set_active (yn);
2430 if ((prop = node.property (X_("editor-list-page")))) {
2431 _the_notebook.set_current_page (atoi (prop->value ()));
2434 if ((prop = node.property (X_("show-marker-lines")))) {
2435 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2437 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2438 bool yn = string_is_affirmative (prop->value ());
2440 tact->set_active (!yn);
2441 tact->set_active (yn);
2444 XMLNodeList children = node.children ();
2445 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2446 selection->set_state (**i, Stateful::current_state_version);
2447 _regions->set_state (**i);
2450 if ((prop = node.property ("maximised"))) {
2451 bool yn = string_is_affirmative (prop->value());
2453 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2457 if ((prop = node.property ("nudge-clock-value"))) {
2459 sscanf (prop->value().c_str(), "%" PRId64, &f);
2460 nudge_clock->set (f);
2462 nudge_clock->set_mode (AudioClock::Timecode);
2463 nudge_clock->set (_session->frame_rate() * 5, true);
2470 Editor::get_state ()
2472 XMLNode* node = new XMLNode ("Editor");
2475 id().print (buf, sizeof (buf));
2476 node->add_property ("id", buf);
2478 if (is_realized()) {
2479 Glib::RefPtr<Gdk::Window> win = get_window();
2481 int x, y, width, height;
2482 win->get_root_origin(x, y);
2483 win->get_size(width, height);
2485 XMLNode* geometry = new XMLNode ("geometry");
2487 snprintf(buf, sizeof(buf), "%d", width);
2488 geometry->add_property("x-size", string(buf));
2489 snprintf(buf, sizeof(buf), "%d", height);
2490 geometry->add_property("y-size", string(buf));
2491 snprintf(buf, sizeof(buf), "%d", x);
2492 geometry->add_property("x-pos", string(buf));
2493 snprintf(buf, sizeof(buf), "%d", y);
2494 geometry->add_property("y-pos", string(buf));
2495 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2496 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2497 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2498 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2499 geometry->add_property("edit-vertical-pane-pos", string(buf));
2501 node->add_child_nocopy (*geometry);
2504 maybe_add_mixer_strip_width (*node);
2506 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2507 snprintf (buf, sizeof(buf), "%f", frames_per_unit);
2508 node->add_property ("zoom", buf);
2509 node->add_property ("snap-to", enum_2_string (_snap_type));
2510 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2511 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2512 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2513 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2514 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2515 node->add_property ("edit-point", enum_2_string (_edit_point));
2517 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame);
2518 node->add_property ("playhead", buf);
2519 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2520 node->add_property ("left-frame", buf);
2521 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2522 node->add_property ("y-origin", buf);
2524 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2525 node->add_property ("maximised", _maximised ? "yes" : "no");
2526 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2527 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2528 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2529 node->add_property ("mouse-mode", enum2str(mouse_mode));
2530 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2531 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2533 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2535 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2536 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2539 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2541 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2542 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2545 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2546 node->add_property (X_("editor-list-page"), buf);
2548 if (button_bindings) {
2549 XMLNode* bb = new XMLNode (X_("Buttons"));
2550 button_bindings->save (*bb);
2551 node->add_child_nocopy (*bb);
2554 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2556 node->add_child_nocopy (selection->get_state ());
2557 node->add_child_nocopy (_regions->get_state ());
2559 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2560 node->add_property ("nudge-clock-value", buf);
2567 /** @param y y offset from the top of all trackviews.
2568 * @return pair: TimeAxisView that y is over, layer index.
2569 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2570 * in stacked or expanded region display mode, otherwise 0.
2572 std::pair<TimeAxisView *, double>
2573 Editor::trackview_by_y_position (double y)
2575 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2577 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2583 return std::make_pair ( (TimeAxisView *) 0, 0);
2586 /** Snap a position to the grid, if appropriate, taking into account current
2587 * grid settings and also the state of any snap modifier keys that may be pressed.
2588 * @param start Position to snap.
2589 * @param event Event to get current key modifier information from, or 0.
2592 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2594 if (!_session || !event) {
2598 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2599 if (_snap_mode == SnapOff) {
2600 snap_to_internal (start, direction, for_mark);
2603 if (_snap_mode != SnapOff) {
2604 snap_to_internal (start, direction, for_mark);
2610 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2612 if (!_session || _snap_mode == SnapOff) {
2616 snap_to_internal (start, direction, for_mark);
2620 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2622 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2623 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2625 switch (_snap_type) {
2626 case SnapToTimecodeFrame:
2627 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2628 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2630 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2634 case SnapToTimecodeSeconds:
2635 if (_session->config.get_timecode_offset_negative()) {
2636 start += _session->config.get_timecode_offset ();
2638 start -= _session->config.get_timecode_offset ();
2640 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2641 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2643 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2646 if (_session->config.get_timecode_offset_negative()) {
2647 start -= _session->config.get_timecode_offset ();
2649 start += _session->config.get_timecode_offset ();
2653 case SnapToTimecodeMinutes:
2654 if (_session->config.get_timecode_offset_negative()) {
2655 start += _session->config.get_timecode_offset ();
2657 start -= _session->config.get_timecode_offset ();
2659 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2660 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2662 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2664 if (_session->config.get_timecode_offset_negative()) {
2665 start -= _session->config.get_timecode_offset ();
2667 start += _session->config.get_timecode_offset ();
2671 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2677 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2679 const framepos_t one_second = _session->frame_rate();
2680 const framepos_t one_minute = _session->frame_rate() * 60;
2681 framepos_t presnap = start;
2685 switch (_snap_type) {
2686 case SnapToTimecodeFrame:
2687 case SnapToTimecodeSeconds:
2688 case SnapToTimecodeMinutes:
2689 return timecode_snap_to_internal (start, direction, for_mark);
2692 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2693 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2695 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2700 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2701 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2703 start = (framepos_t) floor ((double) start / one_second) * one_second;
2708 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2709 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2711 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2716 start = _session->tempo_map().round_to_bar (start, direction);
2720 start = _session->tempo_map().round_to_beat (start, direction);
2723 case SnapToBeatDiv128:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2726 case SnapToBeatDiv64:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2729 case SnapToBeatDiv32:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2732 case SnapToBeatDiv28:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2735 case SnapToBeatDiv24:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2738 case SnapToBeatDiv20:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2741 case SnapToBeatDiv16:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2744 case SnapToBeatDiv14:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2747 case SnapToBeatDiv12:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2750 case SnapToBeatDiv10:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2753 case SnapToBeatDiv8:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2756 case SnapToBeatDiv7:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2759 case SnapToBeatDiv6:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2762 case SnapToBeatDiv5:
2763 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2765 case SnapToBeatDiv4:
2766 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2768 case SnapToBeatDiv3:
2769 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2771 case SnapToBeatDiv2:
2772 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2780 _session->locations()->marks_either_side (start, before, after);
2782 if (before == max_framepos && after == max_framepos) {
2783 /* No marks to snap to, so just don't snap */
2785 } else if (before == max_framepos) {
2787 } else if (after == max_framepos) {
2789 } else if (before != max_framepos && after != max_framepos) {
2790 /* have before and after */
2791 if ((start - before) < (after - start)) {
2800 case SnapToRegionStart:
2801 case SnapToRegionEnd:
2802 case SnapToRegionSync:
2803 case SnapToRegionBoundary:
2804 if (!region_boundary_cache.empty()) {
2806 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2807 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2809 if (direction > 0) {
2810 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2812 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2815 if (next != region_boundary_cache.begin ()) {
2820 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2821 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2823 if (start > (p + n) / 2) {
2832 switch (_snap_mode) {
2838 if (presnap > start) {
2839 if (presnap > (start + unit_to_frame(snap_threshold))) {
2843 } else if (presnap < start) {
2844 if (presnap < (start - unit_to_frame(snap_threshold))) {
2850 /* handled at entry */
2858 Editor::setup_toolbar ()
2860 HBox* mode_box = manage(new HBox);
2861 mode_box->set_border_width (2);
2862 mode_box->set_spacing(4);
2864 HBox* mouse_mode_box = manage (new HBox);
2865 HBox* mouse_mode_hbox = manage (new HBox);
2866 VBox* mouse_mode_vbox = manage (new VBox);
2867 Alignment* mouse_mode_align = manage (new Alignment);
2869 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2870 // mouse_mode_size_group->add_widget (smart_mode_button);
2871 mouse_mode_size_group->add_widget (mouse_move_button);
2872 mouse_mode_size_group->add_widget (mouse_select_button);
2873 mouse_mode_size_group->add_widget (mouse_zoom_button);
2874 mouse_mode_size_group->add_widget (mouse_gain_button);
2875 mouse_mode_size_group->add_widget (mouse_timefx_button);
2876 mouse_mode_size_group->add_widget (mouse_audition_button);
2877 mouse_mode_size_group->add_widget (mouse_draw_button);
2878 mouse_mode_size_group->add_widget (internal_edit_button);
2880 /* make them just a bit bigger */
2881 mouse_move_button.set_size_request (-1, 30);
2883 mouse_mode_hbox->set_spacing (2);
2885 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2886 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2887 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2888 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2889 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2890 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2891 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2892 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2893 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2895 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2897 mouse_mode_align->add (*mouse_mode_vbox);
2898 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2900 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2902 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2903 if (!Profile->get_sae()) {
2904 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2906 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2908 edit_mode_selector.set_name ("EditModeSelector");
2909 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2910 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2912 mode_box->pack_start (edit_mode_selector, false, false);
2913 mode_box->pack_start (*mouse_mode_box, false, false);
2915 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2916 _mouse_mode_tearoff->set_name ("MouseModeBase");
2917 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2919 if (Profile->get_sae()) {
2920 _mouse_mode_tearoff->set_can_be_torn_off (false);
2923 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2924 &_mouse_mode_tearoff->tearoff_window()));
2925 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2926 &_mouse_mode_tearoff->tearoff_window(), 1));
2927 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2928 &_mouse_mode_tearoff->tearoff_window()));
2929 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2930 &_mouse_mode_tearoff->tearoff_window(), 1));
2934 _zoom_box.set_spacing (2);
2935 _zoom_box.set_border_width (2);
2939 zoom_in_button.set_name ("zoom button");
2940 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2941 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2942 zoom_in_button.set_image(::get_icon ("zoom_in"));
2943 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2944 zoom_in_button.set_related_action (act);
2946 zoom_out_button.set_name ("zoom button");
2947 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2948 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2949 zoom_out_button.set_image(::get_icon ("zoom_out"));
2950 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2951 zoom_out_button.set_related_action (act);
2953 zoom_out_full_button.set_name ("zoom button");
2954 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2955 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2956 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2957 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2958 zoom_out_full_button.set_related_action (act);
2960 zoom_focus_selector.set_name ("ZoomFocusSelector");
2961 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2962 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2964 _zoom_box.pack_start (zoom_out_button, false, false);
2965 _zoom_box.pack_start (zoom_in_button, false, false);
2966 _zoom_box.pack_start (zoom_out_full_button, false, false);
2968 _zoom_box.pack_start (zoom_focus_selector, false, false);
2970 /* Track zoom buttons */
2971 tav_expand_button.set_name ("zoom button");
2972 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2973 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2974 tav_expand_button.set_size_request (-1, 20);
2975 tav_expand_button.set_image(::get_icon ("tav_exp"));
2976 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2977 tav_expand_button.set_related_action (act);
2979 tav_shrink_button.set_name ("zoom button");
2980 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2981 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2982 tav_shrink_button.set_size_request (-1, 20);
2983 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2984 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2985 tav_shrink_button.set_related_action (act);
2987 _zoom_box.pack_start (tav_shrink_button);
2988 _zoom_box.pack_start (tav_expand_button);
2990 _zoom_tearoff = manage (new TearOff (_zoom_box));
2992 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2993 &_zoom_tearoff->tearoff_window()));
2994 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2995 &_zoom_tearoff->tearoff_window(), 0));
2996 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2997 &_zoom_tearoff->tearoff_window()));
2998 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2999 &_zoom_tearoff->tearoff_window(), 0));
3001 snap_box.set_spacing (2);
3002 snap_box.set_border_width (2);
3004 snap_type_selector.set_name ("SnapTypeSelector");
3005 set_popdown_strings (snap_type_selector, snap_type_strings);
3006 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
3008 snap_mode_selector.set_name ("SnapModeSelector");
3009 set_popdown_strings (snap_mode_selector, snap_mode_strings);
3010 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3012 edit_point_selector.set_name ("EditPointSelector");
3013 set_popdown_strings (edit_point_selector, edit_point_strings);
3014 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3016 snap_box.pack_start (snap_mode_selector, false, false);
3017 snap_box.pack_start (snap_type_selector, false, false);
3018 snap_box.pack_start (edit_point_selector, false, false);
3022 HBox *nudge_box = manage (new HBox);
3023 nudge_box->set_spacing (2);
3024 nudge_box->set_border_width (2);
3026 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3027 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3029 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3030 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3032 nudge_box->pack_start (nudge_backward_button, false, false);
3033 nudge_box->pack_start (nudge_forward_button, false, false);
3034 nudge_box->pack_start (*nudge_clock, false, false);
3037 /* Pack everything in... */
3039 HBox* hbox = manage (new HBox);
3040 hbox->set_spacing(10);
3042 _tools_tearoff = manage (new TearOff (*hbox));
3043 _tools_tearoff->set_name ("MouseModeBase");
3044 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3046 if (Profile->get_sae()) {
3047 _tools_tearoff->set_can_be_torn_off (false);
3050 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3051 &_tools_tearoff->tearoff_window()));
3052 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3053 &_tools_tearoff->tearoff_window(), 0));
3054 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3055 &_tools_tearoff->tearoff_window()));
3056 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3057 &_tools_tearoff->tearoff_window(), 0));
3059 toolbar_hbox.set_spacing (10);
3060 toolbar_hbox.set_border_width (1);
3062 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3063 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3064 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3066 hbox->pack_start (snap_box, false, false);
3067 if (!Profile->get_small_screen()) {
3068 hbox->pack_start (*nudge_box, false, false);
3070 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3072 hbox->pack_start (panic_box, false, false);
3076 toolbar_base.set_name ("ToolBarBase");
3077 toolbar_base.add (toolbar_hbox);
3079 _toolbar_viewport.add (toolbar_base);
3080 /* stick to the required height but allow width to vary if there's not enough room */
3081 _toolbar_viewport.set_size_request (1, -1);
3083 toolbar_frame.set_shadow_type (SHADOW_OUT);
3084 toolbar_frame.set_name ("BaseFrame");
3085 toolbar_frame.add (_toolbar_viewport);
3089 Editor::setup_tooltips ()
3091 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3092 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3093 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3094 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3095 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3096 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3097 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3098 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3099 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3100 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3101 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3102 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3103 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3104 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3105 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3106 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3107 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3108 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3109 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3110 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3111 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3112 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3113 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3117 Editor::convert_drop_to_paths (
3118 vector<string>& paths,
3119 const RefPtr<Gdk::DragContext>& /*context*/,
3122 const SelectionData& data,
3126 if (_session == 0) {
3130 vector<string> uris = data.get_uris();
3134 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3135 are actually URI lists. So do it by hand.
3138 if (data.get_target() != "text/plain") {
3142 /* Parse the "uri-list" format that Nautilus provides,
3143 where each pathname is delimited by \r\n.
3145 THERE MAY BE NO NULL TERMINATING CHAR!!!
3148 string txt = data.get_text();
3152 p = (const char *) malloc (txt.length() + 1);
3153 txt.copy (const_cast<char *> (p), txt.length(), 0);
3154 const_cast<char*>(p)[txt.length()] = '\0';
3160 while (g_ascii_isspace (*p))
3164 while (*q && (*q != '\n') && (*q != '\r')) {
3171 while (q > p && g_ascii_isspace (*q))
3176 uris.push_back (string (p, q - p + 1));
3180 p = strchr (p, '\n');
3192 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3194 if ((*i).substr (0,7) == "file://") {
3196 string const p = PBD::url_decode (*i);
3198 // scan forward past three slashes
3200 string::size_type slashcnt = 0;
3201 string::size_type n = 0;
3202 string::const_iterator x = p.begin();
3204 while (slashcnt < 3 && x != p.end()) {
3207 } else if (slashcnt == 3) {
3214 if (slashcnt != 3 || x == p.end()) {
3215 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3219 paths.push_back (p.substr (n - 1));
3227 Editor::new_tempo_section ()
3233 Editor::map_transport_state ()
3235 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3237 if (_session && _session->transport_stopped()) {
3238 have_pending_keyboard_selection = false;
3241 update_loop_range_view (true);
3247 Editor::begin_reversible_command (string name)
3250 _session->begin_reversible_command (name);
3255 Editor::begin_reversible_command (GQuark q)
3258 _session->begin_reversible_command (q);
3263 Editor::commit_reversible_command ()
3266 _session->commit_reversible_command ();
3271 Editor::history_changed ()
3275 if (undo_action && _session) {
3276 if (_session->undo_depth() == 0) {
3277 label = S_("Command|Undo");
3279 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3281 undo_action->property_label() = label;
3284 if (redo_action && _session) {
3285 if (_session->redo_depth() == 0) {
3288 label = string_compose(_("Redo (%1)"), _session->next_redo());
3290 redo_action->property_label() = label;
3295 Editor::duplicate_range (bool with_dialog)
3299 RegionSelection rs = get_regions_from_selection_and_entered ();
3301 if ( selection->time.length() == 0 && rs.empty()) {
3307 ArdourDialog win (_("Duplicate"));
3308 Label label (_("Number of duplications:"));
3309 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3310 SpinButton spinner (adjustment, 0.0, 1);
3313 win.get_vbox()->set_spacing (12);
3314 win.get_vbox()->pack_start (hbox);
3315 hbox.set_border_width (6);
3316 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3318 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3319 place, visually. so do this by hand.
3322 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3323 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3324 spinner.grab_focus();
3330 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3331 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3332 win.set_default_response (RESPONSE_ACCEPT);
3334 win.set_position (WIN_POS_MOUSE);
3336 spinner.grab_focus ();
3338 switch (win.run ()) {
3339 case RESPONSE_ACCEPT:
3345 times = adjustment.get_value();
3348 if ((current_mouse_mode() == Editing::MouseRange)) {
3349 if (selection->time.length()) {
3350 duplicate_selection (times);
3352 } else if (get_smart_mode()) {
3353 if (selection->time.length()) {
3354 duplicate_selection (times);
3356 duplicate_some_regions (rs, times);
3358 duplicate_some_regions (rs, times);
3363 Editor::set_edit_mode (EditMode m)
3365 Config->set_edit_mode (m);
3369 Editor::cycle_edit_mode ()
3371 switch (Config->get_edit_mode()) {
3373 if (Profile->get_sae()) {
3374 Config->set_edit_mode (Lock);
3376 Config->set_edit_mode (Splice);
3380 Config->set_edit_mode (Lock);
3383 Config->set_edit_mode (Slide);
3389 Editor::edit_mode_selection_done ()
3391 string s = edit_mode_selector.get_active_text ();
3394 Config->set_edit_mode (string_to_edit_mode (s));
3399 Editor::snap_type_selection_done ()
3401 string choice = snap_type_selector.get_active_text();
3402 SnapType snaptype = SnapToBeat;
3404 if (choice == _("Beats/2")) {
3405 snaptype = SnapToBeatDiv2;
3406 } else if (choice == _("Beats/3")) {
3407 snaptype = SnapToBeatDiv3;
3408 } else if (choice == _("Beats/4")) {
3409 snaptype = SnapToBeatDiv4;
3410 } else if (choice == _("Beats/5")) {
3411 snaptype = SnapToBeatDiv5;
3412 } else if (choice == _("Beats/6")) {
3413 snaptype = SnapToBeatDiv6;
3414 } else if (choice == _("Beats/7")) {
3415 snaptype = SnapToBeatDiv7;
3416 } else if (choice == _("Beats/8")) {
3417 snaptype = SnapToBeatDiv8;
3418 } else if (choice == _("Beats/10")) {
3419 snaptype = SnapToBeatDiv10;
3420 } else if (choice == _("Beats/12")) {
3421 snaptype = SnapToBeatDiv12;
3422 } else if (choice == _("Beats/14")) {
3423 snaptype = SnapToBeatDiv14;
3424 } else if (choice == _("Beats/16")) {
3425 snaptype = SnapToBeatDiv16;
3426 } else if (choice == _("Beats/20")) {
3427 snaptype = SnapToBeatDiv20;
3428 } else if (choice == _("Beats/24")) {
3429 snaptype = SnapToBeatDiv24;
3430 } else if (choice == _("Beats/28")) {
3431 snaptype = SnapToBeatDiv28;
3432 } else if (choice == _("Beats/32")) {
3433 snaptype = SnapToBeatDiv32;
3434 } else if (choice == _("Beats/64")) {
3435 snaptype = SnapToBeatDiv64;
3436 } else if (choice == _("Beats/128")) {
3437 snaptype = SnapToBeatDiv128;
3438 } else if (choice == _("Beats")) {
3439 snaptype = SnapToBeat;
3440 } else if (choice == _("Bars")) {
3441 snaptype = SnapToBar;
3442 } else if (choice == _("Marks")) {
3443 snaptype = SnapToMark;
3444 } else if (choice == _("Region starts")) {
3445 snaptype = SnapToRegionStart;
3446 } else if (choice == _("Region ends")) {
3447 snaptype = SnapToRegionEnd;
3448 } else if (choice == _("Region bounds")) {
3449 snaptype = SnapToRegionBoundary;
3450 } else if (choice == _("Region syncs")) {
3451 snaptype = SnapToRegionSync;
3452 } else if (choice == _("CD Frames")) {
3453 snaptype = SnapToCDFrame;
3454 } else if (choice == _("Timecode Frames")) {
3455 snaptype = SnapToTimecodeFrame;
3456 } else if (choice == _("Timecode Seconds")) {
3457 snaptype = SnapToTimecodeSeconds;
3458 } else if (choice == _("Timecode Minutes")) {
3459 snaptype = SnapToTimecodeMinutes;
3460 } else if (choice == _("Seconds")) {
3461 snaptype = SnapToSeconds;
3462 } else if (choice == _("Minutes")) {
3463 snaptype = SnapToMinutes;
3466 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3468 ract->set_active ();
3473 Editor::snap_mode_selection_done ()
3475 string choice = snap_mode_selector.get_active_text();
3476 SnapMode mode = SnapNormal;
3478 if (choice == _("No Grid")) {
3480 } else if (choice == _("Grid")) {
3482 } else if (choice == _("Magnetic")) {
3483 mode = SnapMagnetic;
3486 RefPtr<RadioAction> ract = snap_mode_action (mode);
3489 ract->set_active (true);
3494 Editor::cycle_edit_point (bool with_marker)
3496 switch (_edit_point) {
3498 set_edit_point_preference (EditAtPlayhead);
3500 case EditAtPlayhead:
3502 set_edit_point_preference (EditAtSelectedMarker);
3504 set_edit_point_preference (EditAtMouse);
3507 case EditAtSelectedMarker:
3508 set_edit_point_preference (EditAtMouse);
3514 Editor::edit_point_selection_done ()
3516 string choice = edit_point_selector.get_active_text();
3517 EditPoint ep = EditAtSelectedMarker;
3519 if (choice == _("Marker")) {
3520 set_edit_point_preference (EditAtSelectedMarker);
3521 } else if (choice == _("Playhead")) {
3522 set_edit_point_preference (EditAtPlayhead);
3524 set_edit_point_preference (EditAtMouse);
3527 RefPtr<RadioAction> ract = edit_point_action (ep);
3530 ract->set_active (true);
3535 Editor::zoom_focus_selection_done ()
3537 string choice = zoom_focus_selector.get_active_text();
3538 ZoomFocus focus_type = ZoomFocusLeft;
3540 if (choice == _("Left")) {
3541 focus_type = ZoomFocusLeft;
3542 } else if (choice == _("Right")) {
3543 focus_type = ZoomFocusRight;
3544 } else if (choice == _("Center")) {
3545 focus_type = ZoomFocusCenter;
3546 } else if (choice == _("Playhead")) {
3547 focus_type = ZoomFocusPlayhead;
3548 } else if (choice == _("Mouse")) {
3549 focus_type = ZoomFocusMouse;
3550 } else if (choice == _("Edit point")) {
3551 focus_type = ZoomFocusEdit;
3554 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3557 ract->set_active ();
3562 Editor::edit_controls_button_release (GdkEventButton* ev)
3564 if (Keyboard::is_context_menu_event (ev)) {
3565 ARDOUR_UI::instance()->add_route (this);
3566 } else if (ev->button == 1) {
3567 selection->clear_tracks ();
3574 Editor::mouse_select_button_release (GdkEventButton* ev)
3576 /* this handles just right-clicks */
3578 if (ev->button != 3) {
3586 Editor::set_zoom_focus (ZoomFocus f)
3588 string str = zoom_focus_strings[(int)f];
3590 if (str != zoom_focus_selector.get_active_text()) {
3591 zoom_focus_selector.set_active_text (str);
3594 if (zoom_focus != f) {
3601 Editor::cycle_zoom_focus ()
3603 switch (zoom_focus) {
3605 set_zoom_focus (ZoomFocusRight);
3607 case ZoomFocusRight:
3608 set_zoom_focus (ZoomFocusCenter);
3610 case ZoomFocusCenter:
3611 set_zoom_focus (ZoomFocusPlayhead);
3613 case ZoomFocusPlayhead:
3614 set_zoom_focus (ZoomFocusMouse);
3616 case ZoomFocusMouse:
3617 set_zoom_focus (ZoomFocusEdit);
3620 set_zoom_focus (ZoomFocusLeft);
3626 Editor::ensure_float (Window& win)
3628 win.set_transient_for (*this);
3632 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3634 /* recover or initialize pane positions. do this here rather than earlier because
3635 we don't want the positions to change the child allocations, which they seem to do.
3641 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3650 XMLNode* geometry = find_named_node (*node, "geometry");
3652 if (which == static_cast<Paned*> (&edit_pane)) {
3654 if (done & Horizontal) {
3658 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3659 _notebook_shrunk = string_is_affirmative (prop->value ());
3662 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3663 /* initial allocation is 90% to canvas, 10% to notebook */
3664 pos = (int) floor (alloc.get_width() * 0.90f);
3665 snprintf (buf, sizeof(buf), "%d", pos);
3667 pos = atoi (prop->value());
3670 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3671 edit_pane.set_position (pos);
3674 done = (Pane) (done | Horizontal);
3676 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3678 if (done & Vertical) {
3682 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3683 /* initial allocation is 90% to canvas, 10% to summary */
3684 pos = (int) floor (alloc.get_height() * 0.90f);
3685 snprintf (buf, sizeof(buf), "%d", pos);
3688 pos = atoi (prop->value());
3691 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3692 editor_summary_pane.set_position (pos);
3695 done = (Pane) (done | Vertical);
3700 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3702 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3703 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3704 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3705 top_hbox.remove (toolbar_frame);
3710 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3712 if (toolbar_frame.get_parent() == 0) {
3713 top_hbox.pack_end (toolbar_frame);
3718 Editor::set_show_measures (bool yn)
3720 if (_show_measures != yn) {
3723 if ((_show_measures = yn) == true) {
3725 tempo_lines->show();
3727 (void) redraw_measures ();
3734 Editor::toggle_follow_playhead ()
3736 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3738 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3739 set_follow_playhead (tact->get_active());
3743 /** @param yn true to follow playhead, otherwise false.
3744 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3747 Editor::set_follow_playhead (bool yn, bool catch_up)
3749 if (_follow_playhead != yn) {
3750 if ((_follow_playhead = yn) == true && catch_up) {
3752 reset_x_origin_to_follow_playhead ();
3759 Editor::toggle_stationary_playhead ()
3761 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3763 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3764 set_stationary_playhead (tact->get_active());
3769 Editor::set_stationary_playhead (bool yn)
3771 if (_stationary_playhead != yn) {
3772 if ((_stationary_playhead = yn) == true) {
3774 // FIXME need a 3.0 equivalent of this 2.X call
3775 // update_current_screen ();
3782 Editor::playlist_selector () const
3784 return *_playlist_selector;
3788 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3792 switch (_snap_type) {
3797 case SnapToBeatDiv128:
3800 case SnapToBeatDiv64:
3803 case SnapToBeatDiv32:
3806 case SnapToBeatDiv28:
3809 case SnapToBeatDiv24:
3812 case SnapToBeatDiv20:
3815 case SnapToBeatDiv16:
3818 case SnapToBeatDiv14:
3821 case SnapToBeatDiv12:
3824 case SnapToBeatDiv10:
3827 case SnapToBeatDiv8:
3830 case SnapToBeatDiv7:
3833 case SnapToBeatDiv6:
3836 case SnapToBeatDiv5:
3839 case SnapToBeatDiv4:
3842 case SnapToBeatDiv3:
3845 case SnapToBeatDiv2:
3851 return _session->tempo_map().meter_at (position).divisions_per_bar();
3856 case SnapToTimecodeFrame:
3857 case SnapToTimecodeSeconds:
3858 case SnapToTimecodeMinutes:
3861 case SnapToRegionStart:
3862 case SnapToRegionEnd:
3863 case SnapToRegionSync:
3864 case SnapToRegionBoundary:
3874 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3878 ret = nudge_clock->current_duration (pos);
3879 next = ret + 1; /* XXXX fix me */
3885 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3887 ArdourDialog dialog (_("Playlist Deletion"));
3888 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3889 "If it is kept, its audio files will not be cleaned.\n"
3890 "If it is deleted, audio files used by it alone will be cleaned."),
3893 dialog.set_position (WIN_POS_CENTER);
3894 dialog.get_vbox()->pack_start (label);
3898 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3899 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3900 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3902 switch (dialog.run ()) {
3903 case RESPONSE_ACCEPT:
3904 /* delete the playlist */
3908 case RESPONSE_REJECT:
3909 /* keep the playlist */
3921 Editor::audio_region_selection_covers (framepos_t where)
3923 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3924 if ((*a)->region()->covers (where)) {
3933 Editor::prepare_for_cleanup ()
3935 cut_buffer->clear_regions ();
3936 cut_buffer->clear_playlists ();
3938 selection->clear_regions ();
3939 selection->clear_playlists ();
3941 _regions->suspend_redisplay ();
3945 Editor::finish_cleanup ()
3947 _regions->resume_redisplay ();
3951 Editor::transport_loop_location()
3954 return _session->locations()->auto_loop_location();
3961 Editor::transport_punch_location()
3964 return _session->locations()->auto_punch_location();
3971 Editor::control_layout_scroll (GdkEventScroll* ev)
3973 if (Keyboard::some_magic_widget_has_focus()) {
3977 switch (ev->direction) {
3979 scroll_tracks_up_line ();
3983 case GDK_SCROLL_DOWN:
3984 scroll_tracks_down_line ();
3988 /* no left/right handling yet */
3996 Editor::session_state_saved (string)
3999 _snapshots->redisplay ();
4003 Editor::update_tearoff_visibility()
4005 bool visible = Config->get_keep_tearoffs();
4006 _mouse_mode_tearoff->set_visible (visible);
4007 _tools_tearoff->set_visible (visible);
4008 _zoom_tearoff->set_visible (visible);
4012 Editor::maximise_editing_space ()
4024 Editor::restore_editing_space ()
4036 * Make new playlists for a given track and also any others that belong
4037 * to the same active route group with the `select' property.
4042 Editor::new_playlists (TimeAxisView* v)
4044 begin_reversible_command (_("new playlists"));
4045 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4046 _session->playlists->get (playlists);
4047 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4048 commit_reversible_command ();
4052 * Use a copy of the current playlist for a given track and also any others that belong
4053 * to the same active route group with the `select' property.
4058 Editor::copy_playlists (TimeAxisView* v)
4060 begin_reversible_command (_("copy playlists"));
4061 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4062 _session->playlists->get (playlists);
4063 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4064 commit_reversible_command ();
4067 /** Clear the current playlist for a given track and also any others that belong
4068 * to the same active route group with the `select' property.
4073 Editor::clear_playlists (TimeAxisView* v)
4075 begin_reversible_command (_("clear playlists"));
4076 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4077 _session->playlists->get (playlists);
4078 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4079 commit_reversible_command ();
4083 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4085 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4089 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4091 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4095 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4097 atv.clear_playlist ();
4101 Editor::on_key_press_event (GdkEventKey* ev)
4103 return key_press_focus_accelerator_handler (*this, ev);
4107 Editor::on_key_release_event (GdkEventKey* ev)
4109 return Gtk::Window::on_key_release_event (ev);
4110 // return key_press_focus_accelerator_handler (*this, ev);
4113 /** Queue up a change to the viewport x origin.
4114 * @param frame New x origin.
4117 Editor::reset_x_origin (framepos_t frame)
4119 pending_visual_change.add (VisualChange::TimeOrigin);
4120 pending_visual_change.time_origin = frame;
4121 ensure_visual_change_idle_handler ();
4125 Editor::reset_y_origin (double y)
4127 pending_visual_change.add (VisualChange::YOrigin);
4128 pending_visual_change.y_origin = y;
4129 ensure_visual_change_idle_handler ();
4133 Editor::reset_zoom (double fpu)
4135 clamp_frames_per_unit (fpu);
4137 if (fpu == frames_per_unit) {
4141 pending_visual_change.add (VisualChange::ZoomLevel);
4142 pending_visual_change.frames_per_unit = fpu;
4143 ensure_visual_change_idle_handler ();
4147 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4149 reset_x_origin (frame);
4152 if (!no_save_visual) {
4153 undo_visual_stack.push_back (current_visual_state(false));
4157 Editor::VisualState::VisualState (bool with_tracks)
4158 : gui_state (with_tracks ? new GUIObjectState : 0)
4162 Editor::VisualState::~VisualState ()
4167 Editor::VisualState*
4168 Editor::current_visual_state (bool with_tracks)
4170 VisualState* vs = new VisualState (with_tracks);
4171 vs->y_position = vertical_adjustment.get_value();
4172 vs->frames_per_unit = frames_per_unit;
4173 vs->leftmost_frame = leftmost_frame;
4174 vs->zoom_focus = zoom_focus;
4177 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4184 Editor::undo_visual_state ()
4186 if (undo_visual_stack.empty()) {
4190 VisualState* vs = undo_visual_stack.back();
4191 undo_visual_stack.pop_back();
4194 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4196 use_visual_state (*vs);
4200 Editor::redo_visual_state ()
4202 if (redo_visual_stack.empty()) {
4206 VisualState* vs = redo_visual_stack.back();
4207 redo_visual_stack.pop_back();
4209 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4211 use_visual_state (*vs);
4215 Editor::swap_visual_state ()
4217 if (undo_visual_stack.empty()) {
4218 redo_visual_state ();
4220 undo_visual_state ();
4225 Editor::use_visual_state (VisualState& vs)
4227 PBD::Unwinder<bool> nsv (no_save_visual, true);
4229 _routes->suspend_redisplay ();
4231 vertical_adjustment.set_value (vs.y_position);
4233 set_zoom_focus (vs.zoom_focus);
4234 reposition_and_zoom (vs.leftmost_frame, vs.frames_per_unit);
4237 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4239 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4240 (*i)->reset_visual_state ();
4244 _routes->update_visibility ();
4245 _routes->resume_redisplay ();
4248 /** This is the core function that controls the zoom level of the canvas. It is called
4249 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4250 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4253 Editor::set_frames_per_unit (double fpu)
4256 tempo_lines->tempo_map_changed();
4259 frames_per_unit = fpu;
4261 /* convert fpu to frame count */
4263 framepos_t frames = (framepos_t) floor (frames_per_unit * _canvas_width);
4265 if (frames_per_unit != zoom_range_clock->current_duration()) {
4266 zoom_range_clock->set (frames);
4269 bool const showing_time_selection = selection->time.length() > 0;
4271 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4272 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4273 (*i)->reshow_selection (selection->time);
4277 ZoomChanged (); /* EMIT_SIGNAL */
4279 //reset_scrolling_region ();
4281 if (playhead_cursor) {
4282 playhead_cursor->set_position (playhead_cursor->current_frame);
4285 refresh_location_display();
4286 _summary->set_overlays_dirty ();
4288 update_marker_labels ();
4294 Editor::queue_visual_videotimeline_update ()
4297 * pending_visual_change.add (VisualChange::VideoTimeline);
4298 * or maybe even more specific: which videotimeline-image
4299 * currently it calls update_video_timeline() to update
4300 * _all outdated_ images on the video-timeline.
4301 * see 'exposeimg()' in video_image_frame.cc
4303 ensure_visual_change_idle_handler ();
4307 Editor::ensure_visual_change_idle_handler ()
4309 if (pending_visual_change.idle_handler_id < 0) {
4310 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4315 Editor::_idle_visual_changer (void* arg)
4317 return static_cast<Editor*>(arg)->idle_visual_changer ();
4321 Editor::idle_visual_changer ()
4323 /* set_horizontal_position() below (and maybe other calls) call
4324 gtk_main_iteration(), so it's possible that a signal will be handled
4325 half-way through this method. If this signal wants an
4326 idle_visual_changer we must schedule another one after this one, so
4327 mark the idle_handler_id as -1 here to allow that. Also make a note
4328 that we are doing the visual change, so that changes in response to
4329 super-rapid-screen-update can be dropped if we are still processing
4333 pending_visual_change.idle_handler_id = -1;
4334 pending_visual_change.being_handled = true;
4336 VisualChange::Type p = pending_visual_change.pending;
4337 pending_visual_change.pending = (VisualChange::Type) 0;
4339 double const last_time_origin = horizontal_position ();
4341 if (p & VisualChange::ZoomLevel) {
4342 set_frames_per_unit (pending_visual_change.frames_per_unit);
4344 compute_fixed_ruler_scale ();
4346 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4347 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4349 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4350 current_bbt_points_begin, current_bbt_points_end);
4351 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_frames(),
4352 current_bbt_points_begin, current_bbt_points_end);
4353 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4356 if (p & VisualChange::ZoomLevel) {
4357 update_video_timeline();
4360 if (p & VisualChange::TimeOrigin) {
4361 set_horizontal_position (pending_visual_change.time_origin / frames_per_unit);
4364 if (p & VisualChange::YOrigin) {
4365 vertical_adjustment.set_value (pending_visual_change.y_origin);
4368 if (last_time_origin == horizontal_position ()) {
4369 /* changed signal not emitted */
4370 update_fixed_rulers ();
4371 redisplay_tempo (true);
4374 if (!(p & VisualChange::ZoomLevel)) {
4375 update_video_timeline();
4378 _summary->set_overlays_dirty ();
4380 pending_visual_change.being_handled = false;
4381 return 0; /* this is always a one-shot call */
4384 struct EditorOrderTimeAxisSorter {
4385 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4386 return a->order () < b->order ();
4391 Editor::sort_track_selection (TrackViewList& sel)
4393 EditorOrderTimeAxisSorter cmp;
4398 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4401 framepos_t where = 0;
4402 EditPoint ep = _edit_point;
4404 if (from_context_menu && (ep == EditAtMouse)) {
4405 return event_frame (&context_click_event, 0, 0);
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, _("Punch"), 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 boost::shared_ptr<RegionList> regions = pl->regions_at (
4535 (framepos_t) floor ( (double) where * tr->speed()));
4537 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4538 RegionView* rv = rtv->view()->find_view (*i);
4549 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4551 const TrackViewList* tracks;
4554 tracks = &track_views;
4559 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4560 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4562 boost::shared_ptr<Track> tr;
4563 boost::shared_ptr<Playlist> pl;
4565 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4567 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4568 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4570 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4572 RegionView* rv = rtv->view()->find_view (*i);
4583 /** Get regions using the following method:
4585 * Make a region list using the selected regions, unless
4586 * the edit point is `mouse' and the mouse is over an unselected
4587 * region. In this case, use just that region.
4589 * If the edit point is not 'mouse', and there are no regions selected,
4590 * search the list of selected tracks and return regions that are under
4591 * the edit point on these tracks. If there are no selected tracks and
4592 * 'No Selection = All Tracks' is active, search all tracks,
4594 * The rationale here is that the mouse edit point is special in that
4595 * its position describes both a time and a track; the other edit
4596 * modes only describe a time. Hence if the edit point is `mouse' we
4597 * ignore selected tracks, as we assume the user means something by
4598 * pointing at a particular track. Also in this case we take note of
4599 * the region directly under the edit point, as there is always just one
4600 * (rather than possibly several with non-mouse edit points).
4604 Editor::get_regions_from_selection_and_edit_point ()
4606 RegionSelection regions;
4608 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4609 regions.add (entered_regionview);
4611 regions = selection->regions;
4615 if (regions.empty() && _edit_point != EditAtMouse) {
4616 TrackViewList tracks = selection->tracks;
4618 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4619 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4620 * is enabled, so consider all tracks
4622 tracks = track_views;
4625 if (!tracks.empty()) {
4626 /* no region selected or entered, but some selected tracks:
4627 * act on all regions on the selected tracks at the edit point
4629 framepos_t const where = get_preferred_edit_position ();
4630 get_regions_at(regions, where, tracks);
4636 /** Start with regions that are selected, or the entered regionview if none are selected.
4637 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4638 * of the regions that we started with.
4642 Editor::get_regions_from_selection_and_entered ()
4644 RegionSelection regions = selection->regions;
4646 if (regions.empty() && entered_regionview) {
4647 regions.add (entered_regionview);
4654 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4656 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4658 RouteTimeAxisView* tatv;
4660 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4662 boost::shared_ptr<Playlist> pl;
4663 vector<boost::shared_ptr<Region> > results;
4665 boost::shared_ptr<Track> tr;
4667 if ((tr = tatv->track()) == 0) {
4672 if ((pl = (tr->playlist())) != 0) {
4673 if (src_comparison) {
4674 pl->get_source_equivalent_regions (region, results);
4676 pl->get_region_list_equivalent_regions (region, results);
4680 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4681 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4682 regions.push_back (marv);
4691 Editor::show_rhythm_ferret ()
4693 if (rhythm_ferret == 0) {
4694 rhythm_ferret = new RhythmFerret(*this);
4697 rhythm_ferret->set_session (_session);
4698 rhythm_ferret->show ();
4699 rhythm_ferret->present ();
4703 Editor::first_idle ()
4705 MessageDialog* dialog = 0;
4707 if (track_views.size() > 1) {
4708 dialog = new MessageDialog (
4710 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4714 ARDOUR_UI::instance()->flush_pending ();
4717 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4721 // first idle adds route children (automation tracks), so we need to redisplay here
4722 _routes->redisplay ();
4729 Editor::_idle_resize (gpointer arg)
4731 return ((Editor*)arg)->idle_resize ();
4735 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4737 if (resize_idle_id < 0) {
4738 resize_idle_id = g_idle_add (_idle_resize, this);
4739 _pending_resize_amount = 0;
4742 /* make a note of the smallest resulting height, so that we can clamp the
4743 lower limit at TimeAxisView::hSmall */
4745 int32_t min_resulting = INT32_MAX;
4747 _pending_resize_amount += h;
4748 _pending_resize_view = view;
4750 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4752 if (selection->tracks.contains (_pending_resize_view)) {
4753 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4754 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4758 if (min_resulting < 0) {
4763 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4764 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4768 /** Handle pending resizing of tracks */
4770 Editor::idle_resize ()
4772 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4774 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4775 selection->tracks.contains (_pending_resize_view)) {
4777 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4778 if (*i != _pending_resize_view) {
4779 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4784 _pending_resize_amount = 0;
4786 _group_tabs->set_dirty ();
4787 resize_idle_id = -1;
4795 ENSURE_GUI_THREAD (*this, &Editor::located);
4798 playhead_cursor->set_position (_session->audible_frame ());
4799 if (_follow_playhead && !_pending_initial_locate) {
4800 reset_x_origin_to_follow_playhead ();
4804 _pending_locate_request = false;
4805 _pending_initial_locate = false;
4809 Editor::region_view_added (RegionView *)
4811 _summary->set_dirty ();
4815 Editor::region_view_removed ()
4817 _summary->set_dirty ();
4821 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4823 TrackViewList::const_iterator j = track_views.begin ();
4824 while (j != track_views.end()) {
4825 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4826 if (rtv && rtv->route() == r) {
4837 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4841 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4842 TimeAxisView* tv = axis_view_from_route (*i);
4852 Editor::add_routes (RouteList& routes)
4854 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4856 RouteTimeAxisView *rtv;
4857 list<RouteTimeAxisView*> new_views;
4859 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4860 boost::shared_ptr<Route> route = (*x);
4862 if (route->is_auditioner() || route->is_monitor()) {
4866 DataType dt = route->input()->default_type();
4868 if (dt == ARDOUR::DataType::AUDIO) {
4869 rtv = new AudioTimeAxisView (*this, _session, *track_canvas);
4870 rtv->set_route (route);
4871 } else if (dt == ARDOUR::DataType::MIDI) {
4872 rtv = new MidiTimeAxisView (*this, _session, *track_canvas);
4873 rtv->set_route (route);
4875 throw unknown_type();
4878 new_views.push_back (rtv);
4879 track_views.push_back (rtv);
4881 rtv->effective_gain_display ();
4883 if (internal_editing()) {
4884 rtv->enter_internal_edit_mode ();
4886 rtv->leave_internal_edit_mode ();
4889 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4890 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4893 _routes->routes_added (new_views);
4894 _summary->routes_added (new_views);
4896 if (show_editor_mixer_when_tracks_arrive) {
4897 show_editor_mixer (true);
4900 editor_list_button.set_sensitive (true);
4904 Editor::timeaxisview_deleted (TimeAxisView *tv)
4906 if (_session && _session->deletion_in_progress()) {
4907 /* the situation is under control */
4911 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4913 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4915 _routes->route_removed (tv);
4917 if (tv == entered_track) {
4921 TimeAxisView::Children c = tv->get_child_list ();
4922 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4923 if (entered_track == i->get()) {
4928 /* remove it from the list of track views */
4930 TrackViewList::iterator i;
4932 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4933 i = track_views.erase (i);
4936 /* update whatever the current mixer strip is displaying, if revelant */
4938 boost::shared_ptr<Route> route;
4941 route = rtav->route ();
4944 if (current_mixer_strip && current_mixer_strip->route() == route) {
4946 TimeAxisView* next_tv;
4948 if (track_views.empty()) {
4950 } else if (i == track_views.end()) {
4951 next_tv = track_views.front();
4958 set_selected_mixer_strip (*next_tv);
4960 /* make the editor mixer strip go away setting the
4961 * button to inactive (which also unticks the menu option)
4964 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4970 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4972 if (apply_to_selection) {
4973 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4975 TrackSelection::iterator j = i;
4978 hide_track_in_display (*i, false);
4983 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4985 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4986 // this will hide the mixer strip
4987 set_selected_mixer_strip (*tv);
4990 _routes->hide_track_in_display (*tv);
4995 Editor::sync_track_view_list_and_routes ()
4997 track_views = TrackViewList (_routes->views ());
4999 _summary->set_dirty ();
5000 _group_tabs->set_dirty ();
5002 return false; // do not call again (until needed)
5006 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5008 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5013 /** Find a RouteTimeAxisView by the ID of its route */
5015 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5017 RouteTimeAxisView* v;
5019 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5020 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5021 if(v->route()->id() == id) {
5031 Editor::fit_route_group (RouteGroup *g)
5033 TrackViewList ts = axis_views_from_routes (g->route_list ());
5038 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5040 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5043 _session->cancel_audition ();
5047 if (_session->is_auditioning()) {
5048 _session->cancel_audition ();
5049 if (r == last_audition_region) {
5054 _session->audition_region (r);
5055 last_audition_region = r;
5060 Editor::hide_a_region (boost::shared_ptr<Region> r)
5062 r->set_hidden (true);
5066 Editor::show_a_region (boost::shared_ptr<Region> r)
5068 r->set_hidden (false);
5072 Editor::audition_region_from_region_list ()
5074 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5078 Editor::hide_region_from_region_list ()
5080 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5084 Editor::show_region_in_region_list ()
5086 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5090 Editor::step_edit_status_change (bool yn)
5093 start_step_editing ();
5095 stop_step_editing ();
5100 Editor::start_step_editing ()
5102 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5106 Editor::stop_step_editing ()
5108 step_edit_connection.disconnect ();
5112 Editor::check_step_edit ()
5114 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5115 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5117 mtv->check_step_edit ();
5121 return true; // do it again, till we stop
5125 Editor::scroll_press (Direction dir)
5127 ++_scroll_callbacks;
5129 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5130 /* delay the first auto-repeat */
5136 scroll_backward (1);
5144 scroll_tracks_up_line ();
5148 scroll_tracks_down_line ();
5152 /* do hacky auto-repeat */
5153 if (!_scroll_connection.connected ()) {
5155 _scroll_connection = Glib::signal_timeout().connect (
5156 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5159 _scroll_callbacks = 0;
5166 Editor::scroll_release ()
5168 _scroll_connection.disconnect ();
5171 /** Queue a change for the Editor viewport x origin to follow the playhead */
5173 Editor::reset_x_origin_to_follow_playhead ()
5175 framepos_t const frame = playhead_cursor->current_frame;
5177 if (frame < leftmost_frame || frame > leftmost_frame + current_page_frames()) {
5179 if (_session->transport_speed() < 0) {
5181 if (frame > (current_page_frames() / 2)) {
5182 center_screen (frame-(current_page_frames()/2));
5184 center_screen (current_page_frames()/2);
5191 if (frame < leftmost_frame) {
5193 if (_session->transport_rolling()) {
5194 /* rolling; end up with the playhead at the right of the page */
5195 l = frame - current_page_frames ();
5197 /* not rolling: end up with the playhead 1/4 of the way along the page */
5198 l = frame - current_page_frames() / 4;
5202 if (_session->transport_rolling()) {
5203 /* rolling: end up with the playhead on the left of the page */
5206 /* not rolling: end up with the playhead 3/4 of the way along the page */
5207 l = frame - 3 * current_page_frames() / 4;
5215 center_screen_internal (l + (current_page_frames() / 2), current_page_frames ());
5221 Editor::super_rapid_screen_update ()
5223 if (!_session || !_session->engine().running()) {
5227 /* METERING / MIXER STRIPS */
5229 /* update track meters, if required */
5230 if (is_mapped() && meters_running) {
5231 RouteTimeAxisView* rtv;
5232 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5233 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5234 rtv->fast_update ();
5239 /* and any current mixer strip */
5240 if (current_mixer_strip) {
5241 current_mixer_strip->fast_update ();
5244 /* PLAYHEAD AND VIEWPORT */
5246 framepos_t const frame = _session->audible_frame();
5248 /* There are a few reasons why we might not update the playhead / viewport stuff:
5250 * 1. we don't update things when there's a pending locate request, otherwise
5251 * when the editor requests a locate there is a chance that this method
5252 * will move the playhead before the locate request is processed, causing
5254 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5255 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5258 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5260 last_update_frame = frame;
5262 if (!_dragging_playhead) {
5263 playhead_cursor->set_position (frame);
5266 if (!_stationary_playhead) {
5268 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5269 /* We only do this if we aren't already
5270 handling a visual change (ie if
5271 pending_visual_change.being_handled is
5272 false) so that these requests don't stack
5273 up there are too many of them to handle in
5276 reset_x_origin_to_follow_playhead ();
5281 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5285 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5286 double target = ((double)frame - (double)current_page_frames()/2.0) / frames_per_unit;
5287 if (target <= 0.0) {
5290 if (fabs(target - current) < current_page_frames() / frames_per_unit) {
5291 target = (target * 0.15) + (current * 0.85);
5297 set_horizontal_position (current);
5306 Editor::session_going_away ()
5308 _have_idled = false;
5310 _session_connections.drop_connections ();
5312 super_rapid_screen_update_connection.disconnect ();
5314 selection->clear ();
5315 cut_buffer->clear ();
5317 clicked_regionview = 0;
5318 clicked_axisview = 0;
5319 clicked_routeview = 0;
5320 entered_regionview = 0;
5322 last_update_frame = 0;
5325 playhead_cursor->canvas_item.hide ();
5327 /* rip everything out of the list displays */
5331 _route_groups->clear ();
5333 /* do this first so that deleting a track doesn't reset cms to null
5334 and thus cause a leak.
5337 if (current_mixer_strip) {
5338 if (current_mixer_strip->get_parent() != 0) {
5339 global_hpacker.remove (*current_mixer_strip);
5341 delete current_mixer_strip;
5342 current_mixer_strip = 0;
5345 /* delete all trackviews */
5347 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5350 track_views.clear ();
5352 zoom_range_clock->set_session (0);
5353 nudge_clock->set_session (0);
5355 editor_list_button.set_active(false);
5356 editor_list_button.set_sensitive(false);
5358 /* clear tempo/meter rulers */
5359 remove_metric_marks ();
5361 clear_marker_display ();
5363 stop_step_editing ();
5365 /* get rid of any existing editor mixer strip */
5367 WindowTitle title(Glib::get_application_name());
5368 title += _("Editor");
5370 set_title (title.get_string());
5372 SessionHandlePtr::session_going_away ();
5377 Editor::show_editor_list (bool yn)
5380 _the_notebook.show ();
5382 _the_notebook.hide ();
5387 Editor::change_region_layering_order (bool from_context_menu)
5389 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5391 if (!clicked_routeview) {
5392 if (layering_order_editor) {
5393 layering_order_editor->hide ();
5398 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5404 boost::shared_ptr<Playlist> pl = track->playlist();
5410 if (layering_order_editor == 0) {
5411 layering_order_editor = new RegionLayeringOrderEditor (*this);
5412 layering_order_editor->set_position (WIN_POS_MOUSE);
5415 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5416 layering_order_editor->maybe_present ();
5420 Editor::update_region_layering_order_editor ()
5422 if (layering_order_editor && layering_order_editor->is_visible ()) {
5423 change_region_layering_order (true);
5428 Editor::setup_fade_images ()
5430 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5431 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5432 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5433 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5434 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5436 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5437 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5438 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5439 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5440 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5442 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5443 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5444 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5445 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5446 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5448 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5449 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5450 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5451 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5452 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5456 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5458 Editor::action_menu_item (std::string const & name)
5460 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5463 return *manage (a->create_menu_item ());
5467 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5469 EventBox* b = manage (new EventBox);
5470 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5471 Label* l = manage (new Label (name));
5475 _the_notebook.append_page (widget, *b);
5479 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5481 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5482 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5485 if (ev->type == GDK_2BUTTON_PRESS) {
5487 /* double-click on a notebook tab shrinks or expands the notebook */
5489 if (_notebook_shrunk) {
5490 if (pre_notebook_shrink_pane_width) {
5491 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5493 _notebook_shrunk = false;
5495 pre_notebook_shrink_pane_width = edit_pane.get_position();
5497 /* this expands the LHS of the edit pane to cover the notebook
5498 PAGE but leaves the tabs visible.
5500 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5501 _notebook_shrunk = true;
5509 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5511 using namespace Menu_Helpers;
5513 MenuList& items = _control_point_context_menu.items ();
5516 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5517 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5518 if (!can_remove_control_point (item)) {
5519 items.back().set_sensitive (false);
5522 _control_point_context_menu.popup (event->button.button, event->button.time);
5526 Editor::shift_key_released ()
5528 _stepping_axis_view = 0;