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 "canvas/debug.h"
74 #include "canvas/text.h"
76 #include "control_protocol/control_protocol.h"
80 #include "analysis_window.h"
81 #include "audio_clock.h"
82 #include "audio_region_view.h"
83 #include "audio_streamview.h"
84 #include "audio_time_axis.h"
85 #include "automation_time_axis.h"
86 #include "bundle_manager.h"
87 #include "crossfade_edit.h"
91 #include "editor_cursors.h"
92 #include "editor_drag.h"
93 #include "editor_group_tabs.h"
94 #include "editor_locations.h"
95 #include "editor_regions.h"
96 #include "editor_route_groups.h"
97 #include "editor_routes.h"
98 #include "editor_snapshots.h"
99 #include "editor_summary.h"
100 #include "global_port_matrix.h"
101 #include "gui_object.h"
102 #include "gui_thread.h"
103 #include "keyboard.h"
105 #include "midi_time_axis.h"
106 #include "mixer_strip.h"
107 #include "mixer_ui.h"
108 #include "mouse_cursors.h"
109 #include "playlist_selector.h"
110 #include "public_editor.h"
111 #include "region_layering_order_editor.h"
112 #include "rgb_macros.h"
113 #include "rhythm_ferret.h"
114 #include "selection.h"
116 #include "tempo_lines.h"
117 #include "time_axis_view.h"
123 using namespace ARDOUR;
126 using namespace Glib;
127 using namespace Gtkmm2ext;
128 using namespace Editing;
130 using PBD::internationalize;
132 using Gtkmm2ext::Keyboard;
134 const double Editor::timebar_height = 15.0;
136 static const gchar *_snap_type_strings[] = {
138 N_("Timecode Frames"),
139 N_("Timecode Seconds"),
140 N_("Timecode Minutes"),
170 static const gchar *_snap_mode_strings[] = {
177 static const gchar *_edit_point_strings[] = {
184 static const gchar *_zoom_focus_strings[] = {
194 #ifdef USE_RUBBERBAND
195 static const gchar *_rb_opt_strings[] = {
198 N_("Balanced multitimbral mixture"),
199 N_("Unpitched percussion with stable notes"),
200 N_("Crisp monophonic instrumental"),
201 N_("Unpitched solo percussion"),
202 N_("Resample without preserving pitch"),
208 pane_size_watcher (Paned* pane)
210 /* if the handle of a pane vanishes into (at least) the tabs of a notebook,
214 Quartz: impossible to access
216 so stop that by preventing it from ever getting too narrow. 35
217 pixels is basically a rough guess at the tab width.
222 int max_width_of_lhs = GTK_WIDGET(pane->gobj())->allocation.width - 35;
224 gint pos = pane->get_position ();
226 if (pos > max_width_of_lhs) {
227 pane->set_position (max_width_of_lhs);
232 : _join_object_range_state (JOIN_OBJECT_RANGE_NONE)
234 /* time display buttons */
235 , minsec_label (_("Mins:Secs"))
236 , bbt_label (_("Bars:Beats"))
237 , timecode_label (_("Timecode"))
238 , samples_label (_("Samples"))
239 , tempo_label (_("Tempo"))
240 , meter_label (_("Meter"))
241 , mark_label (_("Location Markers"))
242 , range_mark_label (_("Range Markers"))
243 , transport_mark_label (_("Loop/Punch Ranges"))
244 , cd_mark_label (_("CD Markers"))
245 , videotl_label (_("Video Timeline"))
246 , edit_packer (4, 4, true)
248 /* the values here don't matter: layout widgets
249 reset them as needed.
252 , vertical_adjustment (0.0, 0.0, 10.0, 400.0)
253 , horizontal_adjustment (0.0, 0.0, 1e16)
254 , unused_adjustment (0.0, 0.0, 10.0, 400.0)
256 , controls_layout (unused_adjustment, vertical_adjustment)
258 /* tool bar related */
260 , zoom_range_clock (new AudioClock (X_("zoomrange"), false, X_("zoom range"), true, false, true))
262 , toolbar_selection_clock_table (2,3)
264 , automation_mode_button (_("mode"))
266 , _toolbar_viewport (*manage (new Gtk::Adjustment (0, 0, 1e10)), *manage (new Gtk::Adjustment (0, 0, 1e10)))
270 , nudge_clock (new AudioClock (X_("nudge"), false, X_("nudge"), true, false, true))
271 , meters_running(false)
272 , _pending_locate_request (false)
273 , _pending_initial_locate (false)
274 , _last_cut_copy_source_track (0)
276 , _region_selection_change_updates_region_list (true)
277 , _following_mixer_selection (false)
278 , _control_point_toggled_on_press (false)
279 , _stepping_axis_view (0)
283 /* we are a singleton */
285 PublicEditor::_instance = this;
289 selection = new Selection (this);
290 cut_buffer = new Selection (this);
292 clicked_regionview = 0;
293 clicked_axisview = 0;
294 clicked_routeview = 0;
295 clicked_control_point = 0;
296 last_update_frame = 0;
297 pre_press_cursor = 0;
298 _drags = new DragManager (this);
299 current_mixer_strip = 0;
302 snap_type_strings = I18N (_snap_type_strings);
303 snap_mode_strings = I18N (_snap_mode_strings);
304 zoom_focus_strings = I18N (_zoom_focus_strings);
305 edit_point_strings = I18N (_edit_point_strings);
306 #ifdef USE_RUBBERBAND
307 rb_opt_strings = I18N (_rb_opt_strings);
311 snap_threshold = 5.0;
312 bbt_beat_subdivision = 4;
313 _visible_canvas_width = 0;
314 _visible_canvas_height = 0;
315 last_autoscroll_x = 0;
316 last_autoscroll_y = 0;
317 autoscroll_active = false;
318 autoscroll_timeout_tag = -1;
323 current_interthread_info = 0;
324 _show_measures = true;
326 show_gain_after_trim = false;
328 have_pending_keyboard_selection = false;
329 _follow_playhead = true;
330 _stationary_playhead = false;
331 editor_ruler_menu = 0;
332 no_ruler_shown_update = false;
334 range_marker_menu = 0;
335 marker_menu_item = 0;
336 tempo_or_meter_marker_menu = 0;
337 transport_marker_menu = 0;
338 new_transport_marker_menu = 0;
339 editor_mixer_strip_width = Wide;
340 show_editor_mixer_when_tracks_arrive = false;
341 region_edit_menu_split_multichannel_item = 0;
342 region_edit_menu_split_item = 0;
345 current_stepping_trackview = 0;
347 entered_regionview = 0;
349 clear_entered_track = false;
352 button_release_can_deselect = true;
353 _dragging_playhead = false;
354 _dragging_edit_point = false;
355 select_new_marker = false;
357 layering_order_editor = 0;
358 no_save_visual = false;
360 within_track_canvas = false;
362 scrubbing_direction = 0;
366 location_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationMarker();
367 location_range_color = ARDOUR_UI::config()->get_canvasvar_LocationRange();
368 location_cd_marker_color = ARDOUR_UI::config()->get_canvasvar_LocationCDMarker();
369 location_loop_color = ARDOUR_UI::config()->get_canvasvar_LocationLoop();
370 location_punch_color = ARDOUR_UI::config()->get_canvasvar_LocationPunch();
372 zoom_focus = ZoomFocusLeft;
373 _edit_point = EditAtMouse;
374 _internal_editing = false;
375 current_canvas_cursor = 0;
377 samples_per_pixel = 2048; /* too early to use reset_zoom () */
379 _scroll_callbacks = 0;
381 zoom_range_clock->ValueChanged.connect (sigc::mem_fun(*this, &Editor::zoom_adjustment_changed));
383 bbt_label.set_name ("EditorRulerLabel");
384 bbt_label.set_size_request (-1, (int)timebar_height);
385 bbt_label.set_alignment (1.0, 0.5);
386 bbt_label.set_padding (5,0);
388 bbt_label.set_no_show_all();
389 minsec_label.set_name ("EditorRulerLabel");
390 minsec_label.set_size_request (-1, (int)timebar_height);
391 minsec_label.set_alignment (1.0, 0.5);
392 minsec_label.set_padding (5,0);
393 minsec_label.hide ();
394 minsec_label.set_no_show_all();
395 timecode_label.set_name ("EditorRulerLabel");
396 timecode_label.set_size_request (-1, (int)timebar_height);
397 timecode_label.set_alignment (1.0, 0.5);
398 timecode_label.set_padding (5,0);
399 timecode_label.hide ();
400 timecode_label.set_no_show_all();
401 samples_label.set_name ("EditorRulerLabel");
402 samples_label.set_size_request (-1, (int)timebar_height);
403 samples_label.set_alignment (1.0, 0.5);
404 samples_label.set_padding (5,0);
405 samples_label.hide ();
406 samples_label.set_no_show_all();
408 tempo_label.set_name ("EditorRulerLabel");
409 tempo_label.set_size_request (-1, (int)timebar_height);
410 tempo_label.set_alignment (1.0, 0.5);
411 tempo_label.set_padding (5,0);
413 tempo_label.set_no_show_all();
415 meter_label.set_name ("EditorRulerLabel");
416 meter_label.set_size_request (-1, (int)timebar_height);
417 meter_label.set_alignment (1.0, 0.5);
418 meter_label.set_padding (5,0);
420 meter_label.set_no_show_all();
422 mark_label.set_name ("EditorRulerLabel");
423 mark_label.set_size_request (-1, (int)timebar_height);
424 mark_label.set_alignment (1.0, 0.5);
425 mark_label.set_padding (5,0);
427 mark_label.set_no_show_all();
429 cd_mark_label.set_name ("EditorRulerLabel");
430 cd_mark_label.set_size_request (-1, (int)timebar_height);
431 cd_mark_label.set_alignment (1.0, 0.5);
432 cd_mark_label.set_padding (5,0);
433 cd_mark_label.hide();
434 cd_mark_label.set_no_show_all();
436 videotl_bar_height = 4;
437 videotl_label.set_name ("EditorRulerLabel");
438 videotl_label.set_size_request (-1, (int)timebar_height * videotl_bar_height);
439 videotl_label.set_alignment (1.0, 0.5);
440 videotl_label.set_padding (5,0);
441 videotl_label.hide();
442 videotl_label.set_no_show_all();
444 range_mark_label.set_name ("EditorRulerLabel");
445 range_mark_label.set_size_request (-1, (int)timebar_height);
446 range_mark_label.set_alignment (1.0, 0.5);
447 range_mark_label.set_padding (5,0);
448 range_mark_label.hide();
449 range_mark_label.set_no_show_all();
451 transport_mark_label.set_name ("EditorRulerLabel");
452 transport_mark_label.set_size_request (-1, (int)timebar_height);
453 transport_mark_label.set_alignment (1.0, 0.5);
454 transport_mark_label.set_padding (5,0);
455 transport_mark_label.hide();
456 transport_mark_label.set_no_show_all();
458 initialize_rulers ();
459 initialize_canvas ();
461 _summary = new EditorSummary (this);
463 selection->TimeChanged.connect (sigc::mem_fun(*this, &Editor::time_selection_changed));
464 selection->TracksChanged.connect (sigc::mem_fun(*this, &Editor::track_selection_changed));
466 editor_regions_selection_changed_connection = selection->RegionsChanged.connect (sigc::mem_fun(*this, &Editor::region_selection_changed));
468 selection->PointsChanged.connect (sigc::mem_fun(*this, &Editor::point_selection_changed));
469 selection->MarkersChanged.connect (sigc::mem_fun(*this, &Editor::marker_selection_changed));
471 edit_controls_vbox.set_spacing (0);
472 vertical_adjustment.signal_value_changed().connect (sigc::mem_fun(*this, &Editor::tie_vertical_scrolling), true);
473 _track_canvas->signal_map_event().connect (sigc::mem_fun (*this, &Editor::track_canvas_map_handler));
475 HBox* h = manage (new HBox);
476 _group_tabs = new EditorGroupTabs (this);
477 h->pack_start (*_group_tabs, PACK_SHRINK);
478 h->pack_start (edit_controls_vbox);
479 controls_layout.add (*h);
481 controls_layout.set_name ("EditControlsBase");
482 controls_layout.add_events (Gdk::SCROLL_MASK);
483 controls_layout.signal_scroll_event().connect (sigc::mem_fun(*this, &Editor::control_layout_scroll), false);
485 controls_layout.add_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
486 controls_layout.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::edit_controls_button_release));
488 _cursors = new MouseCursors;
490 ArdourCanvas::GtkCanvas* time_pad = manage (new ArdourCanvas::GtkCanvas ());
492 ArdourCanvas::Line* pad_line_1 = new ArdourCanvas::Line (time_pad->root());
493 pad_line_1->set (ArdourCanvas::Duple (0.0, 1.0), ArdourCanvas::Duple (100.0, 1.0));
494 pad_line_1->set_outline_color (0xFF0000FF);
500 time_canvas_vbox.set_size_request (-1, (int)(timebar_height * visible_timebars) + 2);
501 time_canvas_vbox.set_size_request (-1, -1);
503 ruler_label_event_box.add (ruler_label_vbox);
504 ruler_label_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
505 ruler_label_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
507 time_bars_event_box.add (time_bars_vbox);
508 time_bars_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
509 time_bars_event_box.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::ruler_label_button_release));
511 time_canvas_event_box.add (time_canvas_vbox);
512 time_canvas_event_box.set_events (Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK|Gdk::POINTER_MOTION_MASK);
514 edit_packer.set_col_spacings (0);
515 edit_packer.set_row_spacings (0);
516 edit_packer.set_homogeneous (false);
517 edit_packer.set_border_width (0);
518 edit_packer.set_name ("EditorWindow");
520 /* labels for the rulers */
521 edit_packer.attach (ruler_label_event_box, 1, 2, 0, 1, FILL, SHRINK, 0, 0);
522 /* labels for the marker "tracks" (time bars) */
523 edit_packer.attach (time_bars_event_box, 1, 2, 1, 2, FILL, SHRINK, 0, 0);
525 edit_packer.attach (time_canvas_event_box, 2, 3, 0, 1, FILL|EXPAND, FILL, 0, 0);
527 edit_packer.attach (controls_layout, 0, 2, 2, 3, FILL, FILL|EXPAND, 0, 0);
528 /* time bars canvas */
529 edit_packer.attach (*_time_bars_canvas_viewport, 2, 3, 1, 2, FILL, FILL, 0, 0);
531 edit_packer.attach (*_track_canvas_viewport, 2, 3, 2, 3, FILL|EXPAND, FILL|EXPAND, 0, 0);
533 bottom_hbox.set_border_width (2);
534 bottom_hbox.set_spacing (3);
536 _route_groups = new EditorRouteGroups (this);
537 _routes = new EditorRoutes (this);
538 _regions = new EditorRegions (this);
539 _snapshots = new EditorSnapshots (this);
540 _locations = new EditorLocations (this);
542 add_notebook_page (_("Regions"), _regions->widget ());
543 add_notebook_page (_("Tracks & Busses"), _routes->widget ());
544 add_notebook_page (_("Snapshots"), _snapshots->widget ());
545 add_notebook_page (_("Track & Bus Groups"), _route_groups->widget ());
546 add_notebook_page (_("Ranges & Marks"), _locations->widget ());
548 _the_notebook.set_show_tabs (true);
549 _the_notebook.set_scrollable (true);
550 _the_notebook.popup_disable ();
551 _the_notebook.set_tab_pos (Gtk::POS_RIGHT);
552 _the_notebook.show_all ();
554 _notebook_shrunk = false;
556 editor_summary_pane.pack1(edit_packer);
558 Button* summary_arrows_left_left = manage (new Button);
559 summary_arrows_left_left->add (*manage (new Arrow (ARROW_LEFT, SHADOW_NONE)));
560 summary_arrows_left_left->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), LEFT)));
561 summary_arrows_left_left->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
563 Button* summary_arrows_left_right = manage (new Button);
564 summary_arrows_left_right->add (*manage (new Arrow (ARROW_RIGHT, SHADOW_NONE)));
565 summary_arrows_left_right->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), RIGHT)));
566 summary_arrows_left_right->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
568 VBox* summary_arrows_left = manage (new VBox);
569 summary_arrows_left->pack_start (*summary_arrows_left_left);
570 summary_arrows_left->pack_start (*summary_arrows_left_right);
572 Button* summary_arrows_right_up = manage (new Button);
573 summary_arrows_right_up->add (*manage (new Arrow (ARROW_UP, SHADOW_NONE)));
574 summary_arrows_right_up->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), UP)));
575 summary_arrows_right_up->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
577 Button* summary_arrows_right_down = manage (new Button);
578 summary_arrows_right_down->add (*manage (new Arrow (ARROW_DOWN, SHADOW_NONE)));
579 summary_arrows_right_down->signal_pressed().connect (sigc::hide_return (sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), DOWN)));
580 summary_arrows_right_down->signal_released().connect (sigc::mem_fun (*this, &Editor::scroll_release));
582 VBox* summary_arrows_right = manage (new VBox);
583 summary_arrows_right->pack_start (*summary_arrows_right_up);
584 summary_arrows_right->pack_start (*summary_arrows_right_down);
586 Frame* summary_frame = manage (new Frame);
587 summary_frame->set_shadow_type (Gtk::SHADOW_ETCHED_IN);
589 summary_frame->add (*_summary);
590 summary_frame->show ();
592 _summary_hbox.pack_start (*summary_arrows_left, false, false);
593 _summary_hbox.pack_start (*summary_frame, true, true);
594 _summary_hbox.pack_start (*summary_arrows_right, false, false);
596 editor_summary_pane.pack2 (_summary_hbox);
598 edit_pane.pack1 (editor_summary_pane, true, true);
599 edit_pane.pack2 (_the_notebook, false, true);
601 editor_summary_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun (*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&editor_summary_pane)));
603 /* XXX: editor_summary_pane might need similar to the edit_pane */
605 edit_pane.signal_size_allocate().connect (sigc::bind (sigc::mem_fun(*this, &Editor::pane_allocation_handler), static_cast<Paned*> (&edit_pane)));
607 Glib::PropertyProxy<int> proxy = edit_pane.property_position();
608 proxy.signal_changed().connect (bind (sigc::ptr_fun (pane_size_watcher), static_cast<Paned*> (&edit_pane)));
610 top_hbox.pack_start (toolbar_frame);
612 HBox *hbox = manage (new HBox);
613 hbox->pack_start (edit_pane, true, true);
615 global_vpacker.pack_start (top_hbox, false, false);
616 global_vpacker.pack_start (*hbox, true, true);
618 global_hpacker.pack_start (global_vpacker, true, true);
620 set_name ("EditorWindow");
621 add_accel_group (ActionManager::ui_manager->get_accel_group());
623 status_bar_hpacker.show ();
625 vpacker.pack_end (status_bar_hpacker, false, false);
626 vpacker.pack_end (global_hpacker, true, true);
628 /* register actions now so that set_state() can find them and set toggles/checks etc */
631 /* when we start using our own keybinding system for the editor, this
632 * will be uncommented
638 set_zoom_focus (zoom_focus);
639 _snap_type = SnapToBeat;
640 set_snap_to (_snap_type);
641 _snap_mode = SnapOff;
642 set_snap_mode (_snap_mode);
643 set_mouse_mode (MouseObject, true);
644 pre_internal_mouse_mode = MouseObject;
645 pre_internal_snap_type = _snap_type;
646 pre_internal_snap_mode = _snap_mode;
647 internal_snap_type = _snap_type;
648 internal_snap_mode = _snap_mode;
649 set_edit_point_preference (EditAtMouse, true);
651 _playlist_selector = new PlaylistSelector();
652 _playlist_selector->signal_delete_event().connect (sigc::bind (sigc::ptr_fun (just_hide_it), static_cast<Window *> (_playlist_selector)));
654 RegionView::RegionViewGoingAway.connect (*this, invalidator (*this), boost::bind (&Editor::catch_vanishing_regionview, this, _1), gui_context());
658 nudge_forward_button.set_name ("zoom button");
659 nudge_forward_button.add_elements (ArdourButton::FlatFace);
660 nudge_forward_button.set_image(::get_icon("nudge_right"));
662 nudge_backward_button.set_name ("zoom button");
663 nudge_backward_button.add_elements (ArdourButton::FlatFace);
664 nudge_backward_button.set_image(::get_icon("nudge_left"));
666 fade_context_menu.set_name ("ArdourContextMenu");
668 /* icons, titles, WM stuff */
670 list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
671 Glib::RefPtr<Gdk::Pixbuf> icon;
673 if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
674 window_icons.push_back (icon);
676 if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
677 window_icons.push_back (icon);
679 if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
680 window_icons.push_back (icon);
682 if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
683 window_icons.push_back (icon);
685 if (!window_icons.empty()) {
686 // set_icon_list (window_icons);
687 set_default_icon_list (window_icons);
690 WindowTitle title(Glib::get_application_name());
691 title += _("Editor");
692 set_title (title.get_string());
693 set_wmclass (X_("ardour_editor"), PROGRAM_NAME);
696 add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
698 signal_configure_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::configure_handler));
699 signal_delete_event().connect (sigc::mem_fun (*ARDOUR_UI::instance(), &ARDOUR_UI::exit_on_main_window_close));
701 Gtkmm2ext::Keyboard::the_keyboard().ZoomVerticalModifierReleased.connect (sigc::mem_fun (*this, &Editor::zoom_vertical_modifier_released));
703 /* allow external control surfaces/protocols to do various things */
705 ControlProtocol::ZoomToSession.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_session, this), gui_context());
706 ControlProtocol::ZoomIn.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, false), gui_context());
707 ControlProtocol::ZoomOut.connect (*this, invalidator (*this), boost::bind (&Editor::temporal_zoom_step, this, true), gui_context());
708 ControlProtocol::Undo.connect (*this, invalidator (*this), boost::bind (&Editor::undo, this, true), gui_context());
709 ControlProtocol::Redo.connect (*this, invalidator (*this), boost::bind (&Editor::redo, this, true), gui_context());
710 ControlProtocol::ScrollTimeline.connect (*this, invalidator (*this), boost::bind (&Editor::control_scroll, this, _1), gui_context());
711 ControlProtocol::StepTracksUp.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_up, this), gui_context());
712 ControlProtocol::StepTracksDown.connect (*this, invalidator (*this), boost::bind (&Editor::control_step_tracks_down, this), gui_context());
713 ControlProtocol::GotoView.connect (*this, invalidator (*this), boost::bind (&Editor::control_view, this, _1), gui_context());
714 ControlProtocol::CloseDialog.connect (*this, invalidator (*this), Keyboard::close_current_dialog, gui_context());
715 ControlProtocol::VerticalZoomInAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_all, this), gui_context());
716 ControlProtocol::VerticalZoomOutAll.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_all, this), gui_context());
717 ControlProtocol::VerticalZoomInSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_in_selected, this), gui_context());
718 ControlProtocol::VerticalZoomOutSelected.connect (*this, invalidator (*this), boost::bind (&Editor::control_vertical_zoom_out_selected, this), gui_context());
720 ControlProtocol::AddRouteToSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Add), gui_context());
721 ControlProtocol::RemoveRouteFromSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
722 ControlProtocol::SetRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Set), gui_context());
723 ControlProtocol::ToggleRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_select, this, _1, Selection::Toggle), gui_context());
724 ControlProtocol::ClearRouteSelection.connect (*this, invalidator (*this), boost::bind (&Editor::control_unselect, this), gui_context());
726 BasicUI::AccessAction.connect (*this, invalidator (*this), boost::bind (&Editor::access_action, this, _1, _2), gui_context());
728 /* problematic: has to return a value and thus cannot be x-thread */
730 Session::AskAboutPlaylistDeletion.connect_same_thread (*this, boost::bind (&Editor::playlist_deletion_dialog, this, _1));
732 Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
734 TimeAxisView::CatchDeletion.connect (*this, invalidator (*this), boost::bind (&Editor::timeaxisview_deleted, this, _1), gui_context());
736 _ignore_region_action = false;
737 _last_region_menu_was_main = false;
738 _popup_region_menu_item = 0;
740 _show_marker_lines = false;
741 _over_region_trim_target = false;
743 /* Button bindings */
745 button_bindings = new Bindings;
747 XMLNode* node = button_settings();
749 for (XMLNodeList::const_iterator i = node->children().begin(); i != node->children().end(); ++i) {
750 button_bindings->load (**i);
757 setup_fade_images ();
762 delete button_bindings;
764 delete _route_groups;
765 delete _time_bars_canvas_viewport;
766 delete _track_canvas_viewport;
771 Editor::button_settings () const
773 XMLNode* settings = ARDOUR_UI::instance()->editor_settings();
774 XMLNode* node = find_named_node (*settings, X_("Buttons"));
777 node = new XMLNode (X_("Buttons"));
784 Editor::add_toplevel_controls (Container& cont)
786 vpacker.pack_start (cont, false, false);
791 Editor::get_smart_mode () const
793 return ( (current_mouse_mode() == Editing::MouseObject) && smart_mode_action->get_active() );
797 Editor::catch_vanishing_regionview (RegionView *rv)
799 /* note: the selection will take care of the vanishing
800 audioregionview by itself.
803 if (_drags->active() && _drags->have_item (rv->get_canvas_group()) && !_drags->ending()) {
807 if (clicked_regionview == rv) {
808 clicked_regionview = 0;
811 if (entered_regionview == rv) {
812 set_entered_regionview (0);
815 if (!_all_region_actions_sensitized) {
816 sensitize_all_region_actions (true);
819 _over_region_trim_target = false;
823 Editor::set_entered_regionview (RegionView* rv)
825 if (rv == entered_regionview) {
829 if (entered_regionview) {
830 entered_regionview->exited ();
833 if ((entered_regionview = rv) != 0) {
834 entered_regionview->entered (internal_editing ());
837 if (!_all_region_actions_sensitized && _last_region_menu_was_main) {
838 /* This RegionView entry might have changed what region actions
839 are allowed, so sensitize them all in case a key is pressed.
841 sensitize_all_region_actions (true);
846 Editor::set_entered_track (TimeAxisView* tav)
849 entered_track->exited ();
852 if ((entered_track = tav) != 0) {
853 entered_track->entered ();
858 Editor::show_window ()
860 if (!is_visible ()) {
863 /* XXX: this is a bit unfortunate; it would probably
864 be nicer if we could just call show () above rather
865 than needing the show_all ()
868 /* re-hide stuff if necessary */
869 editor_list_button_toggled ();
870 parameter_changed ("show-summary");
871 parameter_changed ("show-group-tabs");
872 parameter_changed ("show-zoom-tools");
874 /* now reset all audio_time_axis heights, because widgets might need
880 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
881 tv = (static_cast<TimeAxisView*>(*i));
885 if (current_mixer_strip) {
886 current_mixer_strip->hide_things ();
887 current_mixer_strip->parameter_changed ("mixer-strip-visibility");
895 Editor::instant_save ()
897 if (!constructed || !ARDOUR_UI::instance()->session_loaded) {
902 _session->add_instant_xml(get_state());
904 Config->add_instant_xml(get_state());
909 Editor::zoom_adjustment_changed ()
915 framecnt_t fpu = llrintf (zoom_range_clock->current_duration() / _visible_canvas_width);
916 bool clamped = clamp_samples_per_pixel (fpu);
919 zoom_range_clock->set ((framepos_t) floor (fpu * _visible_canvas_width));
926 Editor::control_vertical_zoom_in_all ()
928 tav_zoom_smooth (false, true);
932 Editor::control_vertical_zoom_out_all ()
934 tav_zoom_smooth (true, true);
938 Editor::control_vertical_zoom_in_selected ()
940 tav_zoom_smooth (false, false);
944 Editor::control_vertical_zoom_out_selected ()
946 tav_zoom_smooth (true, false);
950 Editor::control_view (uint32_t view)
952 goto_visual_state (view);
956 Editor::control_unselect ()
958 selection->clear_tracks ();
962 Editor::control_select (uint32_t rid, Selection::Operation op)
964 /* handles the (static) signal from the ControlProtocol class that
965 * requests setting the selected track to a given RID
972 boost::shared_ptr<Route> r = _session->route_by_remote_id (rid);
978 TimeAxisView* tav = axis_view_from_route (r);
983 selection->add (tav);
985 case Selection::Toggle:
986 selection->toggle (tav);
988 case Selection::Extend:
991 selection->set (tav);
995 selection->clear_tracks ();
1000 Editor::control_step_tracks_up ()
1002 scroll_tracks_up_line ();
1006 Editor::control_step_tracks_down ()
1008 scroll_tracks_down_line ();
1012 Editor::control_scroll (float fraction)
1014 ENSURE_GUI_THREAD (*this, &Editor::control_scroll, fraction)
1020 double step = fraction * current_page_samples();
1023 _control_scroll_target is an optional<T>
1025 it acts like a pointer to an framepos_t, with
1026 a operator conversion to boolean to check
1027 that it has a value could possibly use
1028 playhead_cursor->current_frame to store the
1029 value and a boolean in the class to know
1030 when it's out of date
1033 if (!_control_scroll_target) {
1034 _control_scroll_target = _session->transport_frame();
1035 _dragging_playhead = true;
1038 if ((fraction < 0.0f) && (*_control_scroll_target < (framepos_t) fabs(step))) {
1039 *_control_scroll_target = 0;
1040 } else if ((fraction > 0.0f) && (max_framepos - *_control_scroll_target < step)) {
1041 *_control_scroll_target = max_framepos - (current_page_samples()*2); // allow room for slop in where the PH is on the screen
1043 *_control_scroll_target += (framepos_t) floor (step);
1046 /* move visuals, we'll catch up with it later */
1048 playhead_cursor->set_position (*_control_scroll_target);
1049 UpdateAllTransportClocks (*_control_scroll_target);
1051 if (*_control_scroll_target > (current_page_samples() / 2)) {
1052 /* try to center PH in window */
1053 reset_x_origin (*_control_scroll_target - (current_page_samples()/2));
1059 Now we do a timeout to actually bring the session to the right place
1060 according to the playhead. This is to avoid reading disk buffers on every
1061 call to control_scroll, which is driven by ScrollTimeline and therefore
1062 probably by a control surface wheel which can generate lots of events.
1064 /* cancel the existing timeout */
1066 control_scroll_connection.disconnect ();
1068 /* add the next timeout */
1070 control_scroll_connection = Glib::signal_timeout().connect (sigc::bind (sigc::mem_fun (*this, &Editor::deferred_control_scroll), *_control_scroll_target), 250);
1074 Editor::deferred_control_scroll (framepos_t /*target*/)
1076 _session->request_locate (*_control_scroll_target, _session->transport_rolling());
1077 // reset for next stream
1078 _control_scroll_target = boost::none;
1079 _dragging_playhead = false;
1084 Editor::access_action (std::string action_group, std::string action_item)
1090 ENSURE_GUI_THREAD (*this, &Editor::access_action, action_group, action_item)
1093 act = ActionManager::get_action( action_group.c_str(), action_item.c_str() );
1101 Editor::on_realize ()
1103 Window::on_realize ();
1108 Editor::map_position_change (framepos_t frame)
1110 ENSURE_GUI_THREAD (*this, &Editor::map_position_change, frame)
1112 if (_session == 0) {
1116 if (_follow_playhead) {
1117 center_screen (frame);
1120 playhead_cursor->set_position (frame);
1124 Editor::center_screen (framepos_t frame)
1126 framecnt_t const page = _visible_canvas_width * samples_per_pixel;
1128 /* if we're off the page, then scroll.
1131 if (frame < leftmost_frame || frame >= leftmost_frame + page) {
1132 center_screen_internal (frame, page);
1137 Editor::center_screen_internal (framepos_t frame, float page)
1142 frame -= (framepos_t) page;
1147 reset_x_origin (frame);
1152 Editor::update_title ()
1154 ENSURE_GUI_THREAD (*this, &Editor::update_title)
1157 bool dirty = _session->dirty();
1159 string session_name;
1161 if (_session->snap_name() != _session->name()) {
1162 session_name = _session->snap_name();
1164 session_name = _session->name();
1168 session_name = "*" + session_name;
1171 WindowTitle title(session_name);
1172 title += Glib::get_application_name();
1173 set_title (title.get_string());
1175 /* ::session_going_away() will have taken care of it */
1180 Editor::set_session (Session *t)
1182 SessionHandlePtr::set_session (t);
1188 zoom_range_clock->set_session (_session);
1189 _playlist_selector->set_session (_session);
1190 nudge_clock->set_session (_session);
1191 _summary->set_session (_session);
1192 _group_tabs->set_session (_session);
1193 _route_groups->set_session (_session);
1194 _regions->set_session (_session);
1195 _snapshots->set_session (_session);
1196 _routes->set_session (_session);
1197 _locations->set_session (_session);
1199 if (rhythm_ferret) {
1200 rhythm_ferret->set_session (_session);
1203 if (analysis_window) {
1204 analysis_window->set_session (_session);
1208 sfbrowser->set_session (_session);
1211 compute_fixed_ruler_scale ();
1213 /* Make sure we have auto loop and auto punch ranges */
1215 Location* loc = _session->locations()->auto_loop_location();
1217 loc = new Location (*_session, 0, _session->current_end_frame(), _("Loop"),(Location::Flags) (Location::IsAutoLoop | Location::IsHidden));
1219 if (loc->start() == loc->end()) {
1220 loc->set_end (loc->start() + 1);
1223 _session->locations()->add (loc, false);
1224 _session->set_auto_loop_location (loc);
1227 loc->set_name (_("Loop"));
1230 loc = _session->locations()->auto_punch_location();
1233 loc = new Location (*_session, 0, _session->current_end_frame(), _("Punch"), (Location::Flags) (Location::IsAutoPunch | Location::IsHidden));
1235 if (loc->start() == loc->end()) {
1236 loc->set_end (loc->start() + 1);
1239 _session->locations()->add (loc, false);
1240 _session->set_auto_punch_location (loc);
1243 loc->set_name (_("Punch"));
1246 refresh_location_display ();
1248 /* This must happen after refresh_location_display(), as (amongst other things) we restore
1249 the selected Marker; this needs the LocationMarker list to be available.
1251 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
1252 set_state (*node, Stateful::loading_state_version);
1254 /* catch up with the playhead */
1256 _session->request_locate (playhead_cursor->current_frame ());
1257 _pending_initial_locate = true;
1261 /* These signals can all be emitted by a non-GUI thread. Therefore the
1262 handlers for them must not attempt to directly interact with the GUI,
1263 but use PBD::Signal<T>::connect() which accepts an event loop
1264 ("context") where the handler will be asked to run.
1267 _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context());
1268 _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_transport_state, this), gui_context());
1269 _session->PositionChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::map_position_change, this, _1), gui_context());
1270 _session->RouteAdded.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_routes, this, _1), gui_context());
1271 _session->DirtyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::update_title, this), gui_context());
1272 _session->tempo_map().PropertyChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::tempo_map_changed, this, _1), gui_context());
1273 _session->Located.connect (_session_connections, invalidator (*this), boost::bind (&Editor::located, this), gui_context());
1274 _session->config.ParameterChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::parameter_changed, this, _1), gui_context());
1275 _session->StateSaved.connect (_session_connections, invalidator (*this), boost::bind (&Editor::session_state_saved, this, _1), gui_context());
1276 _session->locations()->added.connect (_session_connections, invalidator (*this), boost::bind (&Editor::add_new_location, this, _1), gui_context());
1277 _session->locations()->removed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::location_gone, this, _1), gui_context());
1278 _session->locations()->changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1279 _session->locations()->StateChanged.connect (_session_connections, invalidator (*this), boost::bind (&Editor::refresh_location_display, this), gui_context());
1280 _session->history().Changed.connect (_session_connections, invalidator (*this), boost::bind (&Editor::history_changed, this), gui_context());
1282 playhead_cursor->show ();
1284 boost::function<void (string)> pc (boost::bind (&Editor::parameter_changed, this, _1));
1285 Config->map_parameters (pc);
1286 _session->config.map_parameters (pc);
1288 restore_ruler_visibility ();
1289 //tempo_map_changed (PropertyChange (0));
1290 _session->tempo_map().apply_with_metrics (*this, &Editor::draw_metric_marks);
1292 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1293 (static_cast<TimeAxisView*>(*i))->set_samples_per_pixel (samples_per_pixel);
1296 super_rapid_screen_update_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (
1297 sigc::mem_fun (*this, &Editor::super_rapid_screen_update)
1300 switch (_snap_type) {
1301 case SnapToRegionStart:
1302 case SnapToRegionEnd:
1303 case SnapToRegionSync:
1304 case SnapToRegionBoundary:
1305 build_region_boundary_cache ();
1312 /* register for undo history */
1313 _session->register_with_memento_command_factory(id(), this);
1315 ActionManager::ui_manager->signal_pre_activate().connect (sigc::mem_fun (*this, &Editor::action_pre_activated));
1317 start_updating_meters ();
1321 Editor::action_pre_activated (Glib::RefPtr<Action> const & a)
1323 if (a->get_name() == "RegionMenu") {
1324 /* When the main menu's region menu is opened, we setup the actions so that they look right
1325 in the menu. I can't find a way of getting a signal when this menu is subsequently closed,
1326 so we resensitize all region actions when the entered regionview or the region selection
1327 changes. HOWEVER we can't always resensitize on entered_regionview change because that
1328 happens after the region context menu is opened. So we set a flag here, too.
1332 sensitize_the_right_region_actions ();
1333 _last_region_menu_was_main = true;
1338 Editor::fill_xfade_menu (Menu_Helpers::MenuList& items, bool start)
1340 using namespace Menu_Helpers;
1342 void (Editor::*emf)(FadeShape);
1343 std::map<ARDOUR::FadeShape,Gtk::Image*>* images;
1346 images = &_xfade_in_images;
1347 emf = &Editor::set_fade_in_shape;
1349 images = &_xfade_out_images;
1350 emf = &Editor::set_fade_out_shape;
1355 _("Linear (for highly correlated material)"),
1356 *(*images)[FadeLinear],
1357 sigc::bind (sigc::mem_fun (*this, emf), FadeLinear)
1361 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1365 _("Constant power"),
1366 *(*images)[FadeConstantPower],
1367 sigc::bind (sigc::mem_fun (*this, emf), FadeConstantPower)
1370 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1375 *(*images)[FadeSymmetric],
1376 sigc::bind (sigc::mem_fun (*this, emf), FadeSymmetric)
1380 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1385 *(*images)[FadeSlow],
1386 sigc::bind (sigc::mem_fun (*this, emf), FadeSlow)
1389 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1394 *(*images)[FadeFast],
1395 sigc::bind (sigc::mem_fun (*this, emf), FadeFast)
1398 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1401 /** Pop up a context menu for when the user clicks on a start crossfade */
1403 Editor::popup_xfade_in_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1405 using namespace Menu_Helpers;
1407 MenuList& items (xfade_in_context_menu.items());
1409 if (items.empty()) {
1410 fill_xfade_menu (items, true);
1413 xfade_in_context_menu.popup (button, time);
1416 /** Pop up a context menu for when the user clicks on an end crossfade */
1418 Editor::popup_xfade_out_context_menu (int button, int32_t time, ArdourCanvas::Item* /*item*/, ItemType /*item_type*/)
1420 using namespace Menu_Helpers;
1422 MenuList& items (xfade_out_context_menu.items());
1424 if (items.empty()) {
1425 fill_xfade_menu (items, false);
1428 xfade_out_context_menu.popup (button, time);
1432 /** Pop up a context menu for when the user clicks on a fade in or fade out */
1434 Editor::popup_fade_context_menu (int button, int32_t time, ArdourCanvas::Item* item, ItemType item_type)
1436 using namespace Menu_Helpers;
1437 AudioRegionView* arv = static_cast<AudioRegionView*> (item->get_data ("regionview"));
1440 fatal << _("programming error: fade in canvas item has no regionview data pointer!") << endmsg;
1444 MenuList& items (fade_context_menu.items());
1447 switch (item_type) {
1449 case FadeInHandleItem:
1450 if (arv->audio_region()->fade_in_active()) {
1451 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), false)));
1453 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_active), true)));
1456 items.push_back (SeparatorElem());
1458 if (Profile->get_sae()) {
1460 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)));
1461 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)));
1468 *_fade_in_images[FadeLinear],
1469 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeLinear)
1473 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1478 *_fade_in_images[FadeSlow],
1479 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSlow)
1482 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1487 *_fade_in_images[FadeFast],
1488 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeFast)
1491 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1496 *_fade_in_images[FadeSymmetric],
1497 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeSymmetric)
1502 _("Constant power"),
1503 *_fade_in_images[FadeConstantPower],
1504 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_in_shape), FadeConstantPower)
1507 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1513 case FadeOutHandleItem:
1514 if (arv->audio_region()->fade_out_active()) {
1515 items.push_back (MenuElem (_("Deactivate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), false)));
1517 items.push_back (MenuElem (_("Activate"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_active), true)));
1520 items.push_back (SeparatorElem());
1522 if (Profile->get_sae()) {
1523 items.push_back (MenuElem (_("Linear"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)));
1524 items.push_back (MenuElem (_("Slowest"), sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)));
1530 *_fade_out_images[FadeLinear],
1531 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeLinear)
1535 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1540 *_fade_out_images[FadeSlow],
1541 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSlow)
1544 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1549 *_fade_out_images[FadeFast],
1550 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeFast)
1553 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1558 *_fade_out_images[FadeSymmetric],
1559 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeSymmetric)
1564 _("Constant power"),
1565 *_fade_out_images[FadeConstantPower],
1566 sigc::bind (sigc::mem_fun (*this, &Editor::set_fade_out_shape), FadeConstantPower)
1569 dynamic_cast<ImageMenuItem*>(&items.back())->set_always_show_image ();
1575 fatal << _("programming error: ")
1576 << X_("non-fade canvas item passed to popup_fade_context_menu()")
1581 fade_context_menu.popup (button, time);
1585 Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type, bool with_selection)
1587 using namespace Menu_Helpers;
1588 Menu* (Editor::*build_menu_function)();
1591 switch (item_type) {
1593 case RegionViewName:
1594 case RegionViewNameHighlight:
1595 case LeftFrameHandle:
1596 case RightFrameHandle:
1597 if (with_selection) {
1598 build_menu_function = &Editor::build_track_selection_context_menu;
1600 build_menu_function = &Editor::build_track_region_context_menu;
1605 if (with_selection) {
1606 build_menu_function = &Editor::build_track_selection_context_menu;
1608 build_menu_function = &Editor::build_track_context_menu;
1613 if (clicked_routeview->track()) {
1614 build_menu_function = &Editor::build_track_context_menu;
1616 build_menu_function = &Editor::build_track_bus_context_menu;
1621 /* probably shouldn't happen but if it does, we don't care */
1625 menu = (this->*build_menu_function)();
1626 menu->set_name ("ArdourContextMenu");
1628 /* now handle specific situations */
1630 switch (item_type) {
1632 case RegionViewName:
1633 case RegionViewNameHighlight:
1634 case LeftFrameHandle:
1635 case RightFrameHandle:
1636 if (!with_selection) {
1637 if (region_edit_menu_split_item) {
1638 if (clicked_regionview && clicked_regionview->region()->covers (get_preferred_edit_position())) {
1639 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, true);
1641 ActionManager::set_sensitive (ActionManager::edit_point_in_region_sensitive_actions, false);
1644 if (region_edit_menu_split_multichannel_item) {
1645 if (clicked_regionview && clicked_regionview->region()->n_channels() > 1) {
1646 region_edit_menu_split_multichannel_item->set_sensitive (true);
1648 region_edit_menu_split_multichannel_item->set_sensitive (false);
1661 /* probably shouldn't happen but if it does, we don't care */
1665 if (item_type != SelectionItem && clicked_routeview && clicked_routeview->audio_track()) {
1667 /* Bounce to disk */
1669 using namespace Menu_Helpers;
1670 MenuList& edit_items = menu->items();
1672 edit_items.push_back (SeparatorElem());
1674 switch (clicked_routeview->audio_track()->freeze_state()) {
1675 case AudioTrack::NoFreeze:
1676 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1679 case AudioTrack::Frozen:
1680 edit_items.push_back (MenuElem (_("Unfreeze"), sigc::mem_fun(*this, &Editor::unfreeze_route)));
1683 case AudioTrack::UnFrozen:
1684 edit_items.push_back (MenuElem (_("Freeze"), sigc::mem_fun(*this, &Editor::freeze_route)));
1690 if (item_type == StreamItem && clicked_routeview) {
1691 clicked_routeview->build_underlay_menu(menu);
1694 /* When the region menu is opened, we setup the actions so that they look right
1697 sensitize_the_right_region_actions ();
1698 _last_region_menu_was_main = false;
1700 menu->signal_hide().connect (sigc::bind (sigc::mem_fun (*this, &Editor::sensitize_all_region_actions), true));
1701 menu->popup (button, time);
1705 Editor::build_track_context_menu ()
1707 using namespace Menu_Helpers;
1709 MenuList& edit_items = track_context_menu.items();
1712 add_dstream_context_items (edit_items);
1713 return &track_context_menu;
1717 Editor::build_track_bus_context_menu ()
1719 using namespace Menu_Helpers;
1721 MenuList& edit_items = track_context_menu.items();
1724 add_bus_context_items (edit_items);
1725 return &track_context_menu;
1729 Editor::build_track_region_context_menu ()
1731 using namespace Menu_Helpers;
1732 MenuList& edit_items = track_region_context_menu.items();
1735 /* we've just cleared the track region context menu, so the menu that these
1736 two items were on will have disappeared; stop them dangling.
1738 region_edit_menu_split_item = 0;
1739 region_edit_menu_split_multichannel_item = 0;
1741 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
1744 boost::shared_ptr<Track> tr;
1745 boost::shared_ptr<Playlist> pl;
1747 if ((tr = rtv->track())) {
1748 add_region_context_items (edit_items, tr);
1752 add_dstream_context_items (edit_items);
1754 return &track_region_context_menu;
1758 Editor::analyze_region_selection ()
1760 if (analysis_window == 0) {
1761 analysis_window = new AnalysisWindow();
1764 analysis_window->set_session(_session);
1766 analysis_window->show_all();
1769 analysis_window->set_regionmode();
1770 analysis_window->analyze();
1772 analysis_window->present();
1776 Editor::analyze_range_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_rangemode();
1788 analysis_window->analyze();
1790 analysis_window->present();
1794 Editor::build_track_selection_context_menu ()
1796 using namespace Menu_Helpers;
1797 MenuList& edit_items = track_selection_context_menu.items();
1798 edit_items.clear ();
1800 add_selection_context_items (edit_items);
1801 // edit_items.push_back (SeparatorElem());
1802 // add_dstream_context_items (edit_items);
1804 return &track_selection_context_menu;
1808 Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
1810 using namespace Menu_Helpers;
1812 /* OK, stick the region submenu at the top of the list, and then add
1816 RegionSelection rs = get_regions_from_selection_and_entered ();
1818 string::size_type pos = 0;
1819 string menu_item_name = (rs.size() == 1) ? rs.front()->region()->name() : _("Selected Regions");
1821 /* we have to hack up the region name because "_" has a special
1822 meaning for menu titles.
1825 while ((pos = menu_item_name.find ("_", pos)) != string::npos) {
1826 menu_item_name.replace (pos, 1, "__");
1830 if (_popup_region_menu_item == 0) {
1831 _popup_region_menu_item = new MenuItem (menu_item_name);
1832 _popup_region_menu_item->set_submenu (*dynamic_cast<Menu*> (ActionManager::get_widget (X_("/PopupRegionMenu"))));
1833 _popup_region_menu_item->show ();
1835 _popup_region_menu_item->set_label (menu_item_name);
1838 const framepos_t position = get_preferred_edit_position (false, true);
1840 edit_items.push_back (*_popup_region_menu_item);
1841 if (track->playlist()->count_regions_at (position) > 1 && (layering_order_editor == 0 || !layering_order_editor->is_visible ())) {
1842 edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
1844 edit_items.push_back (SeparatorElem());
1847 /** Add context menu items relevant to selection ranges.
1848 * @param edit_items List to add the items to.
1851 Editor::add_selection_context_items (Menu_Helpers::MenuList& edit_items)
1853 using namespace Menu_Helpers;
1855 edit_items.push_back (MenuElem (_("Play Range"), sigc::mem_fun(*this, &Editor::play_selection)));
1856 edit_items.push_back (MenuElem (_("Loop Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), true)));
1858 edit_items.push_back (SeparatorElem());
1859 edit_items.push_back (MenuElem (_("Spectral Analysis"), sigc::mem_fun(*this, &Editor::analyze_range_selection)));
1861 edit_items.push_back (SeparatorElem());
1863 edit_items.push_back (
1865 _("Move Range Start to Previous Region Boundary"),
1866 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, false)
1870 edit_items.push_back (
1872 _("Move Range Start to Next Region Boundary"),
1873 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), false, true)
1877 edit_items.push_back (
1879 _("Move Range End to Previous Region Boundary"),
1880 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, false)
1884 edit_items.push_back (
1886 _("Move Range End to Next Region Boundary"),
1887 sigc::bind (sigc::mem_fun (*this, &Editor::move_range_selection_start_or_end_to_region_boundary), true, true)
1891 edit_items.push_back (SeparatorElem());
1892 edit_items.push_back (MenuElem (_("Convert to Region In-Place"), mem_fun(*this, &Editor::separate_region_from_selection)));
1893 edit_items.push_back (MenuElem (_("Convert to Region in Region List"), sigc::mem_fun(*this, &Editor::new_region_from_selection)));
1895 edit_items.push_back (SeparatorElem());
1896 edit_items.push_back (MenuElem (_("Select All in Range"), sigc::mem_fun(*this, &Editor::select_all_selectables_using_time_selection)));
1898 edit_items.push_back (SeparatorElem());
1899 edit_items.push_back (MenuElem (_("Set Loop from Range"), sigc::bind (sigc::mem_fun(*this, &Editor::set_loop_from_selection), false)));
1900 edit_items.push_back (MenuElem (_("Set Punch from Range"), sigc::mem_fun(*this, &Editor::set_punch_from_selection)));
1902 edit_items.push_back (SeparatorElem());
1903 edit_items.push_back (MenuElem (_("Add Range Markers"), sigc::mem_fun (*this, &Editor::add_location_from_selection)));
1905 edit_items.push_back (SeparatorElem());
1906 edit_items.push_back (MenuElem (_("Crop Region to Range"), sigc::mem_fun(*this, &Editor::crop_region_to_selection)));
1907 edit_items.push_back (MenuElem (_("Fill Range with Region"), sigc::mem_fun(*this, &Editor::region_fill_selection)));
1908 edit_items.push_back (MenuElem (_("Duplicate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::duplicate_range), false)));
1910 edit_items.push_back (SeparatorElem());
1911 edit_items.push_back (MenuElem (_("Consolidate Range"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, false)));
1912 edit_items.push_back (MenuElem (_("Consolidate Range With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), true, true)));
1913 edit_items.push_back (MenuElem (_("Bounce Range to Region List"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, false)));
1914 edit_items.push_back (MenuElem (_("Bounce Range to Region List With Processing"), sigc::bind (sigc::mem_fun(*this, &Editor::bounce_range_selection), false, true)));
1915 edit_items.push_back (MenuElem (_("Export Range..."), sigc::mem_fun(*this, &Editor::export_selection)));
1916 if (ARDOUR_UI::instance()->video_timeline->get_duration() > 0) {
1917 edit_items.push_back (MenuElem (_("Export Video Range..."), sigc::bind (sigc::mem_fun(*this, &Editor::export_video), true)));
1923 Editor::add_dstream_context_items (Menu_Helpers::MenuList& edit_items)
1925 using namespace Menu_Helpers;
1929 Menu *play_menu = manage (new Menu);
1930 MenuList& play_items = play_menu->items();
1931 play_menu->set_name ("ArdourContextMenu");
1933 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
1934 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
1935 play_items.push_back (MenuElem (_("Play Region"), sigc::mem_fun(*this, &Editor::play_selected_region)));
1936 play_items.push_back (SeparatorElem());
1937 play_items.push_back (MenuElem (_("Loop Region"), sigc::bind (sigc::mem_fun (*this, &Editor::set_loop_from_region), true)));
1939 edit_items.push_back (MenuElem (_("Play"), *play_menu));
1943 Menu *select_menu = manage (new Menu);
1944 MenuList& select_items = select_menu->items();
1945 select_menu->set_name ("ArdourContextMenu");
1947 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
1948 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
1949 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
1950 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
1951 select_items.push_back (SeparatorElem());
1952 select_items.push_back (MenuElem (_("Set Range to Loop Range"), sigc::mem_fun(*this, &Editor::set_selection_from_loop)));
1953 select_items.push_back (MenuElem (_("Set Range to Punch Range"), sigc::mem_fun(*this, &Editor::set_selection_from_punch)));
1954 select_items.push_back (SeparatorElem());
1955 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
1956 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
1957 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
1958 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
1959 select_items.push_back (MenuElem (_("Select All Between Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), false)));
1960 select_items.push_back (MenuElem (_("Select All Within Playhead and Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_between), true)));
1961 select_items.push_back (MenuElem (_("Select Range Between Playhead and Edit Point"), sigc::mem_fun(*this, &Editor::select_range_between)));
1963 edit_items.push_back (MenuElem (_("Select"), *select_menu));
1967 Menu *cutnpaste_menu = manage (new Menu);
1968 MenuList& cutnpaste_items = cutnpaste_menu->items();
1969 cutnpaste_menu->set_name ("ArdourContextMenu");
1971 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
1972 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
1973 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
1975 cutnpaste_items.push_back (SeparatorElem());
1977 cutnpaste_items.push_back (MenuElem (_("Align"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions), ARDOUR::SyncPoint)));
1978 cutnpaste_items.push_back (MenuElem (_("Align Relative"), sigc::bind (sigc::mem_fun (*this, &Editor::align_regions_relative), ARDOUR::SyncPoint)));
1980 edit_items.push_back (MenuElem (_("Edit"), *cutnpaste_menu));
1982 /* Adding new material */
1984 edit_items.push_back (SeparatorElem());
1985 edit_items.push_back (MenuElem (_("Insert Selected Region"), sigc::bind (sigc::mem_fun(*this, &Editor::insert_region_list_selection), 1.0f)));
1986 edit_items.push_back (MenuElem (_("Insert Existing Media"), sigc::bind (sigc::mem_fun(*this, &Editor::add_external_audio_action), ImportToTrack)));
1990 Menu *nudge_menu = manage (new Menu());
1991 MenuList& nudge_items = nudge_menu->items();
1992 nudge_menu->set_name ("ArdourContextMenu");
1994 edit_items.push_back (SeparatorElem());
1995 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
1996 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
1997 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
1998 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2000 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2004 Editor::add_bus_context_items (Menu_Helpers::MenuList& edit_items)
2006 using namespace Menu_Helpers;
2010 Menu *play_menu = manage (new Menu);
2011 MenuList& play_items = play_menu->items();
2012 play_menu->set_name ("ArdourContextMenu");
2014 play_items.push_back (MenuElem (_("Play From Edit Point"), sigc::mem_fun(*this, &Editor::play_from_edit_point)));
2015 play_items.push_back (MenuElem (_("Play From Start"), sigc::mem_fun(*this, &Editor::play_from_start)));
2016 edit_items.push_back (MenuElem (_("Play"), *play_menu));
2020 Menu *select_menu = manage (new Menu);
2021 MenuList& select_items = select_menu->items();
2022 select_menu->set_name ("ArdourContextMenu");
2024 select_items.push_back (MenuElem (_("Select All in Track"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_in_track), Selection::Set)));
2025 select_items.push_back (MenuElem (_("Select All"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all), Selection::Set)));
2026 select_items.push_back (MenuElem (_("Invert Selection in Track"), sigc::mem_fun(*this, &Editor::invert_selection_in_track)));
2027 select_items.push_back (MenuElem (_("Invert Selection"), sigc::mem_fun(*this, &Editor::invert_selection)));
2028 select_items.push_back (SeparatorElem());
2029 select_items.push_back (MenuElem (_("Select All After Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), true)));
2030 select_items.push_back (MenuElem (_("Select All Before Edit Point"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_edit), false)));
2031 select_items.push_back (MenuElem (_("Select All After Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, true)));
2032 select_items.push_back (MenuElem (_("Select All Before Playhead"), sigc::bind (sigc::mem_fun(*this, &Editor::select_all_selectables_using_cursor), playhead_cursor, false)));
2034 edit_items.push_back (MenuElem (_("Select"), *select_menu));
2038 Menu *cutnpaste_menu = manage (new Menu);
2039 MenuList& cutnpaste_items = cutnpaste_menu->items();
2040 cutnpaste_menu->set_name ("ArdourContextMenu");
2042 cutnpaste_items.push_back (MenuElem (_("Cut"), sigc::mem_fun(*this, &Editor::cut)));
2043 cutnpaste_items.push_back (MenuElem (_("Copy"), sigc::mem_fun(*this, &Editor::copy)));
2044 cutnpaste_items.push_back (MenuElem (_("Paste"), sigc::bind (sigc::mem_fun(*this, &Editor::paste), 1.0f, true)));
2046 Menu *nudge_menu = manage (new Menu());
2047 MenuList& nudge_items = nudge_menu->items();
2048 nudge_menu->set_name ("ArdourContextMenu");
2050 edit_items.push_back (SeparatorElem());
2051 nudge_items.push_back (MenuElem (_("Nudge Entire Track Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, true))));
2052 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Later"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, true))));
2053 nudge_items.push_back (MenuElem (_("Nudge Entire Track Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), false, false))));
2054 nudge_items.push_back (MenuElem (_("Nudge Track After Edit Point Earlier"), (sigc::bind (sigc::mem_fun(*this, &Editor::nudge_track), true, false))));
2056 edit_items.push_back (MenuElem (_("Nudge"), *nudge_menu));
2060 Editor::snap_type() const
2066 Editor::snap_mode() const
2072 Editor::set_snap_to (SnapType st)
2074 unsigned int snap_ind = (unsigned int)st;
2078 if (snap_ind > snap_type_strings.size() - 1) {
2080 _snap_type = (SnapType)snap_ind;
2083 string str = snap_type_strings[snap_ind];
2085 if (str != snap_type_selector.get_active_text()) {
2086 snap_type_selector.set_active_text (str);
2091 switch (_snap_type) {
2092 case SnapToBeatDiv128:
2093 case SnapToBeatDiv64:
2094 case SnapToBeatDiv32:
2095 case SnapToBeatDiv28:
2096 case SnapToBeatDiv24:
2097 case SnapToBeatDiv20:
2098 case SnapToBeatDiv16:
2099 case SnapToBeatDiv14:
2100 case SnapToBeatDiv12:
2101 case SnapToBeatDiv10:
2102 case SnapToBeatDiv8:
2103 case SnapToBeatDiv7:
2104 case SnapToBeatDiv6:
2105 case SnapToBeatDiv5:
2106 case SnapToBeatDiv4:
2107 case SnapToBeatDiv3:
2108 case SnapToBeatDiv2: {
2109 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
2110 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
2112 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(),
2113 current_bbt_points_begin, current_bbt_points_end);
2114 compute_bbt_ruler_scale (leftmost_frame, leftmost_frame + current_page_samples(),
2115 current_bbt_points_begin, current_bbt_points_end);
2116 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
2120 case SnapToRegionStart:
2121 case SnapToRegionEnd:
2122 case SnapToRegionSync:
2123 case SnapToRegionBoundary:
2124 build_region_boundary_cache ();
2132 SnapChanged (); /* EMIT SIGNAL */
2136 Editor::set_snap_mode (SnapMode mode)
2138 string str = snap_mode_strings[(int)mode];
2140 if (_internal_editing) {
2141 internal_snap_mode = mode;
2143 pre_internal_snap_mode = mode;
2148 if (str != snap_mode_selector.get_active_text ()) {
2149 snap_mode_selector.set_active_text (str);
2155 Editor::set_edit_point_preference (EditPoint ep, bool force)
2157 bool changed = (_edit_point != ep);
2160 string str = edit_point_strings[(int)ep];
2162 if (str != edit_point_selector.get_active_text ()) {
2163 edit_point_selector.set_active_text (str);
2166 set_canvas_cursor ();
2168 if (!force && !changed) {
2172 const char* action=NULL;
2174 switch (_edit_point) {
2175 case EditAtPlayhead:
2176 action = "edit-at-playhead";
2178 case EditAtSelectedMarker:
2179 action = "edit-at-marker";
2182 action = "edit-at-mouse";
2186 Glib::RefPtr<Action> act = ActionManager::get_action ("Editor", action);
2188 Glib::RefPtr<RadioAction>::cast_dynamic(act)->set_active (true);
2192 bool in_track_canvas;
2194 if (!mouse_frame (foo, in_track_canvas)) {
2195 in_track_canvas = false;
2198 reset_canvas_action_sensitivity (in_track_canvas);
2204 Editor::set_state (const XMLNode& node, int /*version*/)
2206 const XMLProperty* prop;
2213 g.base_width = default_width;
2214 g.base_height = default_height;
2218 if ((geometry = find_named_node (node, "geometry")) != 0) {
2222 if ((prop = geometry->property("x_size")) == 0) {
2223 prop = geometry->property ("x-size");
2226 g.base_width = atoi(prop->value());
2228 if ((prop = geometry->property("y_size")) == 0) {
2229 prop = geometry->property ("y-size");
2232 g.base_height = atoi(prop->value());
2235 if ((prop = geometry->property ("x_pos")) == 0) {
2236 prop = geometry->property ("x-pos");
2239 x = atoi (prop->value());
2242 if ((prop = geometry->property ("y_pos")) == 0) {
2243 prop = geometry->property ("y-pos");
2246 y = atoi (prop->value());
2250 set_default_size (g.base_width, g.base_height);
2253 if (_session && (prop = node.property ("playhead"))) {
2255 sscanf (prop->value().c_str(), "%" PRIi64, &pos);
2256 playhead_cursor->set_position (pos);
2258 playhead_cursor->set_position (0);
2261 if ((prop = node.property ("mixer-width"))) {
2262 editor_mixer_strip_width = Width (string_2_enum (prop->value(), editor_mixer_strip_width));
2265 if ((prop = node.property ("zoom-focus"))) {
2266 set_zoom_focus ((ZoomFocus) string_2_enum (prop->value(), zoom_focus));
2269 if ((prop = node.property ("zoom"))) {
2270 /* older versions of ardour used floating point samples_per_pixel */
2271 double f = PBD::atof (prop->value());
2272 reset_zoom (llrintf (f));
2274 reset_zoom (samples_per_pixel);
2277 if ((prop = node.property ("snap-to"))) {
2278 set_snap_to ((SnapType) string_2_enum (prop->value(), _snap_type));
2281 if ((prop = node.property ("snap-mode"))) {
2282 set_snap_mode ((SnapMode) string_2_enum (prop->value(), _snap_mode));
2285 if ((prop = node.property ("internal-snap-to"))) {
2286 internal_snap_type = (SnapType) string_2_enum (prop->value(), internal_snap_type);
2289 if ((prop = node.property ("internal-snap-mode"))) {
2290 internal_snap_mode = (SnapMode) string_2_enum (prop->value(), internal_snap_mode);
2293 if ((prop = node.property ("pre-internal-snap-to"))) {
2294 pre_internal_snap_type = (SnapType) string_2_enum (prop->value(), pre_internal_snap_type);
2298 if ((prop = node.property ("pre-internal-snap-mode"))) {
2299 pre_internal_snap_mode = (SnapMode) string_2_enum (prop->value(), pre_internal_snap_mode);
2302 if ((prop = node.property ("mouse-mode"))) {
2303 MouseMode m = str2mousemode(prop->value());
2304 set_mouse_mode (m, true);
2306 set_mouse_mode (MouseObject, true);
2309 if ((prop = node.property ("left-frame")) != 0) {
2311 if (sscanf (prop->value().c_str(), "%" PRId64, &pos) == 1) {
2315 reset_x_origin (pos);
2319 if ((prop = node.property ("y-origin")) != 0) {
2320 reset_y_origin (atof (prop->value ()));
2323 if ((prop = node.property ("internal-edit"))) {
2324 bool yn = string_is_affirmative (prop->value());
2325 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("toggle-internal-edit"));
2327 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2328 tact->set_active (!yn);
2329 tact->set_active (yn);
2333 if ((prop = node.property ("join-object-range"))) {
2334 RefPtr<Action> act = ActionManager::get_action (X_("MouseMode"), X_("set-mouse-mode-object-range"));
2335 bool yn = string_is_affirmative (prop->value());
2337 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2338 tact->set_active (!yn);
2339 tact->set_active (yn);
2341 set_mouse_mode(mouse_mode, true);
2344 if ((prop = node.property ("edit-point"))) {
2345 set_edit_point_preference ((EditPoint) string_2_enum (prop->value(), _edit_point), true);
2348 if ((prop = node.property ("show-measures"))) {
2349 bool yn = string_is_affirmative (prop->value());
2350 _show_measures = yn;
2351 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("ToggleMeasureVisibility"));
2353 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2354 /* do it twice to force the change */
2355 tact->set_active (!yn);
2356 tact->set_active (yn);
2360 if ((prop = node.property ("follow-playhead"))) {
2361 bool yn = string_is_affirmative (prop->value());
2362 set_follow_playhead (yn);
2363 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
2365 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2366 if (tact->get_active() != yn) {
2367 tact->set_active (yn);
2372 if ((prop = node.property ("stationary-playhead"))) {
2373 bool yn = string_is_affirmative (prop->value());
2374 set_stationary_playhead (yn);
2375 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
2377 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
2378 if (tact->get_active() != yn) {
2379 tact->set_active (yn);
2384 if ((prop = node.property ("region-list-sort-type"))) {
2385 RegionListSortType st;
2386 _regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
2389 if ((prop = node.property ("show-editor-mixer"))) {
2391 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2394 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2395 bool yn = string_is_affirmative (prop->value());
2397 /* do it twice to force the change */
2399 tact->set_active (!yn);
2400 tact->set_active (yn);
2403 if ((prop = node.property ("show-editor-list"))) {
2405 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2408 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2409 bool yn = string_is_affirmative (prop->value());
2411 /* do it twice to force the change */
2413 tact->set_active (!yn);
2414 tact->set_active (yn);
2417 if ((prop = node.property (X_("editor-list-page")))) {
2418 _the_notebook.set_current_page (atoi (prop->value ()));
2421 if ((prop = node.property (X_("show-marker-lines")))) {
2422 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-marker-lines"));
2424 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic (act);
2425 bool yn = string_is_affirmative (prop->value ());
2427 tact->set_active (!yn);
2428 tact->set_active (yn);
2431 XMLNodeList children = node.children ();
2432 for (XMLNodeList::const_iterator i = children.begin(); i != children.end(); ++i) {
2433 selection->set_state (**i, Stateful::current_state_version);
2434 _regions->set_state (**i);
2437 if ((prop = node.property ("maximised"))) {
2438 bool yn = string_is_affirmative (prop->value());
2440 ActionManager::do_action ("Common", "ToggleMaximalEditor");
2444 if ((prop = node.property ("nudge-clock-value"))) {
2446 sscanf (prop->value().c_str(), "%" PRId64, &f);
2447 nudge_clock->set (f);
2449 nudge_clock->set_mode (AudioClock::Timecode);
2450 nudge_clock->set (_session->frame_rate() * 5, true);
2457 Editor::get_state ()
2459 XMLNode* node = new XMLNode ("Editor");
2462 id().print (buf, sizeof (buf));
2463 node->add_property ("id", buf);
2465 if (is_realized()) {
2466 Glib::RefPtr<Gdk::Window> win = get_window();
2468 int x, y, width, height;
2469 win->get_root_origin(x, y);
2470 win->get_size(width, height);
2472 XMLNode* geometry = new XMLNode ("geometry");
2474 snprintf(buf, sizeof(buf), "%d", width);
2475 geometry->add_property("x-size", string(buf));
2476 snprintf(buf, sizeof(buf), "%d", height);
2477 geometry->add_property("y-size", string(buf));
2478 snprintf(buf, sizeof(buf), "%d", x);
2479 geometry->add_property("x-pos", string(buf));
2480 snprintf(buf, sizeof(buf), "%d", y);
2481 geometry->add_property("y-pos", string(buf));
2482 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&edit_pane)->gobj()));
2483 geometry->add_property("edit-horizontal-pane-pos", string(buf));
2484 geometry->add_property("notebook-shrunk", _notebook_shrunk ? "1" : "0");
2485 snprintf(buf,sizeof(buf), "%d",gtk_paned_get_position (static_cast<Paned*>(&editor_summary_pane)->gobj()));
2486 geometry->add_property("edit-vertical-pane-pos", string(buf));
2488 node->add_child_nocopy (*geometry);
2491 maybe_add_mixer_strip_width (*node);
2493 node->add_property ("zoom-focus", enum_2_string (zoom_focus));
2495 snprintf (buf, sizeof(buf), "%" PRId64, samples_per_pixel);
2496 node->add_property ("zoom", buf);
2497 node->add_property ("snap-to", enum_2_string (_snap_type));
2498 node->add_property ("snap-mode", enum_2_string (_snap_mode));
2499 node->add_property ("internal-snap-to", enum_2_string (internal_snap_type));
2500 node->add_property ("internal-snap-mode", enum_2_string (internal_snap_mode));
2501 node->add_property ("pre-internal-snap-to", enum_2_string (pre_internal_snap_type));
2502 node->add_property ("pre-internal-snap-mode", enum_2_string (pre_internal_snap_mode));
2503 node->add_property ("edit-point", enum_2_string (_edit_point));
2505 snprintf (buf, sizeof (buf), "%" PRIi64, playhead_cursor->current_frame ());
2506 node->add_property ("playhead", buf);
2507 snprintf (buf, sizeof (buf), "%" PRIi64, leftmost_frame);
2508 node->add_property ("left-frame", buf);
2509 snprintf (buf, sizeof (buf), "%f", vertical_adjustment.get_value ());
2510 node->add_property ("y-origin", buf);
2512 node->add_property ("show-measures", _show_measures ? "yes" : "no");
2513 node->add_property ("maximised", _maximised ? "yes" : "no");
2514 node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
2515 node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
2516 node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
2517 node->add_property ("mouse-mode", enum2str(mouse_mode));
2518 node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
2519 node->add_property ("join-object-range", smart_mode_action->get_active () ? "yes" : "no");
2521 Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
2523 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2524 node->add_property (X_("show-editor-mixer"), tact->get_active() ? "yes" : "no");
2527 act = ActionManager::get_action (X_("Editor"), X_("show-editor-list"));
2529 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(act);
2530 node->add_property (X_("show-editor-list"), tact->get_active() ? "yes" : "no");
2533 snprintf (buf, sizeof (buf), "%d", _the_notebook.get_current_page ());
2534 node->add_property (X_("editor-list-page"), buf);
2536 if (button_bindings) {
2537 XMLNode* bb = new XMLNode (X_("Buttons"));
2538 button_bindings->save (*bb);
2539 node->add_child_nocopy (*bb);
2542 node->add_property (X_("show-marker-lines"), _show_marker_lines ? "yes" : "no");
2544 node->add_child_nocopy (selection->get_state ());
2545 node->add_child_nocopy (_regions->get_state ());
2547 snprintf (buf, sizeof (buf), "%" PRId64, nudge_clock->current_duration());
2548 node->add_property ("nudge-clock-value", buf);
2555 /** @param y y offset from the top of all trackviews.
2556 * @return pair: TimeAxisView that y is over, layer index.
2557 * TimeAxisView may be 0. Layer index is the layer number if the TimeAxisView is valid and is
2558 * in stacked or expanded region display mode, otherwise 0.
2560 std::pair<TimeAxisView *, double>
2561 Editor::trackview_by_y_position (double y)
2563 for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
2565 std::pair<TimeAxisView*, double> const r = (*iter)->covers_y_position (y);
2571 return std::make_pair ( (TimeAxisView *) 0, 0);
2574 /** Snap a position to the grid, if appropriate, taking into account current
2575 * grid settings and also the state of any snap modifier keys that may be pressed.
2576 * @param start Position to snap.
2577 * @param event Event to get current key modifier information from, or 0.
2580 Editor::snap_to_with_modifier (framepos_t& start, GdkEvent const * event, int32_t direction, bool for_mark)
2582 if (!_session || !event) {
2586 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier())) {
2587 if (_snap_mode == SnapOff) {
2588 snap_to_internal (start, direction, for_mark);
2591 if (_snap_mode != SnapOff) {
2592 snap_to_internal (start, direction, for_mark);
2598 Editor::snap_to (framepos_t& start, int32_t direction, bool for_mark)
2600 if (!_session || _snap_mode == SnapOff) {
2604 snap_to_internal (start, direction, for_mark);
2608 Editor::timecode_snap_to_internal (framepos_t& start, int32_t direction, bool /*for_mark*/)
2610 const framepos_t one_timecode_second = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame());
2611 framepos_t one_timecode_minute = (framepos_t)(rint(_session->timecode_frames_per_second()) * _session->frames_per_timecode_frame() * 60);
2613 switch (_snap_type) {
2614 case SnapToTimecodeFrame:
2615 if (((direction == 0) && (fmod((double)start, (double)_session->frames_per_timecode_frame()) > (_session->frames_per_timecode_frame() / 2))) || (direction > 0)) {
2616 start = (framepos_t) (ceil ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2618 start = (framepos_t) (floor ((double) start / _session->frames_per_timecode_frame()) * _session->frames_per_timecode_frame());
2622 case SnapToTimecodeSeconds:
2623 if (_session->config.get_timecode_offset_negative()) {
2624 start += _session->config.get_timecode_offset ();
2626 start -= _session->config.get_timecode_offset ();
2628 if (((direction == 0) && (start % one_timecode_second > one_timecode_second / 2)) || direction > 0) {
2629 start = (framepos_t) ceil ((double) start / one_timecode_second) * one_timecode_second;
2631 start = (framepos_t) floor ((double) start / one_timecode_second) * one_timecode_second;
2634 if (_session->config.get_timecode_offset_negative()) {
2635 start -= _session->config.get_timecode_offset ();
2637 start += _session->config.get_timecode_offset ();
2641 case SnapToTimecodeMinutes:
2642 if (_session->config.get_timecode_offset_negative()) {
2643 start += _session->config.get_timecode_offset ();
2645 start -= _session->config.get_timecode_offset ();
2647 if (((direction == 0) && (start % one_timecode_minute > one_timecode_minute / 2)) || direction > 0) {
2648 start = (framepos_t) ceil ((double) start / one_timecode_minute) * one_timecode_minute;
2650 start = (framepos_t) floor ((double) start / one_timecode_minute) * one_timecode_minute;
2652 if (_session->config.get_timecode_offset_negative()) {
2653 start -= _session->config.get_timecode_offset ();
2655 start += _session->config.get_timecode_offset ();
2659 fatal << "Editor::smpte_snap_to_internal() called with non-timecode snap type!" << endmsg;
2665 Editor::snap_to_internal (framepos_t& start, int32_t direction, bool for_mark)
2667 const framepos_t one_second = _session->frame_rate();
2668 const framepos_t one_minute = _session->frame_rate() * 60;
2669 framepos_t presnap = start;
2673 switch (_snap_type) {
2674 case SnapToTimecodeFrame:
2675 case SnapToTimecodeSeconds:
2676 case SnapToTimecodeMinutes:
2677 return timecode_snap_to_internal (start, direction, for_mark);
2680 if (((direction == 0) && (start % (one_second/75) > (one_second/75) / 2)) || (direction > 0)) {
2681 start = (framepos_t) ceil ((double) start / (one_second / 75)) * (one_second / 75);
2683 start = (framepos_t) floor ((double) start / (one_second / 75)) * (one_second / 75);
2688 if (((direction == 0) && (start % one_second > one_second / 2)) || (direction > 0)) {
2689 start = (framepos_t) ceil ((double) start / one_second) * one_second;
2691 start = (framepos_t) floor ((double) start / one_second) * one_second;
2696 if (((direction == 0) && (start % one_minute > one_minute / 2)) || (direction > 0)) {
2697 start = (framepos_t) ceil ((double) start / one_minute) * one_minute;
2699 start = (framepos_t) floor ((double) start / one_minute) * one_minute;
2704 start = _session->tempo_map().round_to_bar (start, direction);
2708 start = _session->tempo_map().round_to_beat (start, direction);
2711 case SnapToBeatDiv128:
2712 start = _session->tempo_map().round_to_beat_subdivision (start, 128, direction);
2714 case SnapToBeatDiv64:
2715 start = _session->tempo_map().round_to_beat_subdivision (start, 64, direction);
2717 case SnapToBeatDiv32:
2718 start = _session->tempo_map().round_to_beat_subdivision (start, 32, direction);
2720 case SnapToBeatDiv28:
2721 start = _session->tempo_map().round_to_beat_subdivision (start, 28, direction);
2723 case SnapToBeatDiv24:
2724 start = _session->tempo_map().round_to_beat_subdivision (start, 24, direction);
2726 case SnapToBeatDiv20:
2727 start = _session->tempo_map().round_to_beat_subdivision (start, 20, direction);
2729 case SnapToBeatDiv16:
2730 start = _session->tempo_map().round_to_beat_subdivision (start, 16, direction);
2732 case SnapToBeatDiv14:
2733 start = _session->tempo_map().round_to_beat_subdivision (start, 14, direction);
2735 case SnapToBeatDiv12:
2736 start = _session->tempo_map().round_to_beat_subdivision (start, 12, direction);
2738 case SnapToBeatDiv10:
2739 start = _session->tempo_map().round_to_beat_subdivision (start, 10, direction);
2741 case SnapToBeatDiv8:
2742 start = _session->tempo_map().round_to_beat_subdivision (start, 8, direction);
2744 case SnapToBeatDiv7:
2745 start = _session->tempo_map().round_to_beat_subdivision (start, 7, direction);
2747 case SnapToBeatDiv6:
2748 start = _session->tempo_map().round_to_beat_subdivision (start, 6, direction);
2750 case SnapToBeatDiv5:
2751 start = _session->tempo_map().round_to_beat_subdivision (start, 5, direction);
2753 case SnapToBeatDiv4:
2754 start = _session->tempo_map().round_to_beat_subdivision (start, 4, direction);
2756 case SnapToBeatDiv3:
2757 start = _session->tempo_map().round_to_beat_subdivision (start, 3, direction);
2759 case SnapToBeatDiv2:
2760 start = _session->tempo_map().round_to_beat_subdivision (start, 2, direction);
2768 _session->locations()->marks_either_side (start, before, after);
2770 if (before == max_framepos && after == max_framepos) {
2771 /* No marks to snap to, so just don't snap */
2773 } else if (before == max_framepos) {
2775 } else if (after == max_framepos) {
2777 } else if (before != max_framepos && after != max_framepos) {
2778 /* have before and after */
2779 if ((start - before) < (after - start)) {
2788 case SnapToRegionStart:
2789 case SnapToRegionEnd:
2790 case SnapToRegionSync:
2791 case SnapToRegionBoundary:
2792 if (!region_boundary_cache.empty()) {
2794 vector<framepos_t>::iterator prev = region_boundary_cache.end ();
2795 vector<framepos_t>::iterator next = region_boundary_cache.end ();
2797 if (direction > 0) {
2798 next = std::upper_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2800 next = std::lower_bound (region_boundary_cache.begin(), region_boundary_cache.end(), start);
2803 if (next != region_boundary_cache.begin ()) {
2808 framepos_t const p = (prev == region_boundary_cache.end()) ? region_boundary_cache.front () : *prev;
2809 framepos_t const n = (next == region_boundary_cache.end()) ? region_boundary_cache.back () : *next;
2811 if (start > (p + n) / 2) {
2820 switch (_snap_mode) {
2826 if (presnap > start) {
2827 if (presnap > (start + pixel_to_sample(snap_threshold))) {
2831 } else if (presnap < start) {
2832 if (presnap < (start - pixel_to_sample(snap_threshold))) {
2838 /* handled at entry */
2846 Editor::setup_toolbar ()
2848 HBox* mode_box = manage(new HBox);
2849 mode_box->set_border_width (2);
2850 mode_box->set_spacing(4);
2852 HBox* mouse_mode_box = manage (new HBox);
2853 HBox* mouse_mode_hbox = manage (new HBox);
2854 VBox* mouse_mode_vbox = manage (new VBox);
2855 Alignment* mouse_mode_align = manage (new Alignment);
2857 Glib::RefPtr<SizeGroup> mouse_mode_size_group = SizeGroup::create (SIZE_GROUP_BOTH);
2858 // mouse_mode_size_group->add_widget (smart_mode_button);
2859 mouse_mode_size_group->add_widget (mouse_move_button);
2860 mouse_mode_size_group->add_widget (mouse_select_button);
2861 mouse_mode_size_group->add_widget (mouse_zoom_button);
2862 mouse_mode_size_group->add_widget (mouse_gain_button);
2863 mouse_mode_size_group->add_widget (mouse_timefx_button);
2864 mouse_mode_size_group->add_widget (mouse_audition_button);
2865 mouse_mode_size_group->add_widget (mouse_draw_button);
2866 mouse_mode_size_group->add_widget (internal_edit_button);
2868 /* make them just a bit bigger */
2869 mouse_move_button.set_size_request (-1, 30);
2871 mouse_mode_hbox->set_spacing (2);
2873 mouse_mode_hbox->pack_start (smart_mode_button, false, false);
2874 mouse_mode_hbox->pack_start (mouse_move_button, false, false);
2875 mouse_mode_hbox->pack_start (mouse_select_button, false, false);
2876 mouse_mode_hbox->pack_start (mouse_zoom_button, false, false);
2877 mouse_mode_hbox->pack_start (mouse_gain_button, false, false);
2878 mouse_mode_hbox->pack_start (mouse_timefx_button, false, false);
2879 mouse_mode_hbox->pack_start (mouse_audition_button, false, false);
2880 mouse_mode_hbox->pack_start (mouse_draw_button, false, false);
2881 mouse_mode_hbox->pack_start (internal_edit_button, false, false, 8);
2883 mouse_mode_vbox->pack_start (*mouse_mode_hbox);
2885 mouse_mode_align->add (*mouse_mode_vbox);
2886 mouse_mode_align->set (0.5, 1.0, 0.0, 0.0);
2888 mouse_mode_box->pack_start (*mouse_mode_align, false, false);
2890 edit_mode_strings.push_back (edit_mode_to_string (Slide));
2891 if (!Profile->get_sae()) {
2892 edit_mode_strings.push_back (edit_mode_to_string (Splice));
2894 edit_mode_strings.push_back (edit_mode_to_string (Lock));
2896 edit_mode_selector.set_name ("EditModeSelector");
2897 set_popdown_strings (edit_mode_selector, edit_mode_strings);
2898 edit_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_mode_selection_done));
2900 mode_box->pack_start (edit_mode_selector, false, false);
2901 mode_box->pack_start (*mouse_mode_box, false, false);
2903 _mouse_mode_tearoff = manage (new TearOff (*mode_box));
2904 _mouse_mode_tearoff->set_name ("MouseModeBase");
2905 _mouse_mode_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_mouse_mode_tearoff->tearoff_window()), false);
2907 if (Profile->get_sae()) {
2908 _mouse_mode_tearoff->set_can_be_torn_off (false);
2911 _mouse_mode_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2912 &_mouse_mode_tearoff->tearoff_window()));
2913 _mouse_mode_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2914 &_mouse_mode_tearoff->tearoff_window(), 1));
2915 _mouse_mode_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2916 &_mouse_mode_tearoff->tearoff_window()));
2917 _mouse_mode_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2918 &_mouse_mode_tearoff->tearoff_window(), 1));
2922 _zoom_box.set_spacing (2);
2923 _zoom_box.set_border_width (2);
2927 zoom_in_button.set_name ("zoom button");
2928 zoom_in_button.add_elements ( ArdourButton::FlatFace );
2929 zoom_in_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2930 zoom_in_button.set_image(::get_icon ("zoom_in"));
2931 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-in"));
2932 zoom_in_button.set_related_action (act);
2934 zoom_out_button.set_name ("zoom button");
2935 zoom_out_button.add_elements ( ArdourButton::FlatFace );
2936 zoom_out_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2937 zoom_out_button.set_image(::get_icon ("zoom_out"));
2938 act = ActionManager::get_action (X_("Editor"), X_("temporal-zoom-out"));
2939 zoom_out_button.set_related_action (act);
2941 zoom_out_full_button.set_name ("zoom button");
2942 zoom_out_full_button.add_elements ( ArdourButton::FlatFace );
2943 zoom_out_full_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2944 zoom_out_full_button.set_image(::get_icon ("zoom_full"));
2945 act = ActionManager::get_action (X_("Editor"), X_("zoom-to-session"));
2946 zoom_out_full_button.set_related_action (act);
2948 zoom_focus_selector.set_name ("ZoomFocusSelector");
2949 set_popdown_strings (zoom_focus_selector, zoom_focus_strings);
2950 zoom_focus_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::zoom_focus_selection_done));
2952 _zoom_box.pack_start (zoom_out_button, false, false);
2953 _zoom_box.pack_start (zoom_in_button, false, false);
2954 _zoom_box.pack_start (zoom_out_full_button, false, false);
2956 _zoom_box.pack_start (zoom_focus_selector, false, false);
2958 /* Track zoom buttons */
2959 tav_expand_button.set_name ("zoom button");
2960 tav_expand_button.add_elements ( ArdourButton::FlatFace );
2961 tav_expand_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2962 tav_expand_button.set_size_request (-1, 20);
2963 tav_expand_button.set_image(::get_icon ("tav_exp"));
2964 act = ActionManager::get_action (X_("Editor"), X_("expand-tracks"));
2965 tav_expand_button.set_related_action (act);
2967 tav_shrink_button.set_name ("zoom button");
2968 tav_shrink_button.add_elements ( ArdourButton::FlatFace );
2969 tav_shrink_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
2970 tav_shrink_button.set_size_request (-1, 20);
2971 tav_shrink_button.set_image(::get_icon ("tav_shrink"));
2972 act = ActionManager::get_action (X_("Editor"), X_("shrink-tracks"));
2973 tav_shrink_button.set_related_action (act);
2975 _zoom_box.pack_start (tav_shrink_button);
2976 _zoom_box.pack_start (tav_expand_button);
2978 _zoom_tearoff = manage (new TearOff (_zoom_box));
2980 _zoom_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2981 &_zoom_tearoff->tearoff_window()));
2982 _zoom_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2983 &_zoom_tearoff->tearoff_window(), 0));
2984 _zoom_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
2985 &_zoom_tearoff->tearoff_window()));
2986 _zoom_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
2987 &_zoom_tearoff->tearoff_window(), 0));
2989 snap_box.set_spacing (2);
2990 snap_box.set_border_width (2);
2992 snap_type_selector.set_name ("SnapTypeSelector");
2993 set_popdown_strings (snap_type_selector, snap_type_strings);
2994 snap_type_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_type_selection_done));
2996 snap_mode_selector.set_name ("SnapModeSelector");
2997 set_popdown_strings (snap_mode_selector, snap_mode_strings);
2998 snap_mode_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::snap_mode_selection_done));
3000 edit_point_selector.set_name ("EditPointSelector");
3001 set_popdown_strings (edit_point_selector, edit_point_strings);
3002 edit_point_selector.signal_changed().connect (sigc::mem_fun(*this, &Editor::edit_point_selection_done));
3004 snap_box.pack_start (snap_mode_selector, false, false);
3005 snap_box.pack_start (snap_type_selector, false, false);
3006 snap_box.pack_start (edit_point_selector, false, false);
3010 HBox *nudge_box = manage (new HBox);
3011 nudge_box->set_spacing (2);
3012 nudge_box->set_border_width (2);
3014 nudge_forward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_forward_release), false);
3015 nudge_backward_button.signal_button_release_event().connect (sigc::mem_fun(*this, &Editor::nudge_backward_release), false);
3017 nudge_forward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3018 nudge_backward_button.set_tweaks ((ArdourButton::Tweaks) (ArdourButton::ShowClick) );
3020 nudge_box->pack_start (nudge_backward_button, false, false);
3021 nudge_box->pack_start (nudge_forward_button, false, false);
3022 nudge_box->pack_start (*nudge_clock, false, false);
3025 /* Pack everything in... */
3027 HBox* hbox = manage (new HBox);
3028 hbox->set_spacing(10);
3030 _tools_tearoff = manage (new TearOff (*hbox));
3031 _tools_tearoff->set_name ("MouseModeBase");
3032 _tools_tearoff->tearoff_window().signal_key_press_event().connect (sigc::bind (sigc::ptr_fun (relay_key_press), &_tools_tearoff->tearoff_window()), false);
3034 if (Profile->get_sae()) {
3035 _tools_tearoff->set_can_be_torn_off (false);
3038 _tools_tearoff->Detach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3039 &_tools_tearoff->tearoff_window()));
3040 _tools_tearoff->Attach.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3041 &_tools_tearoff->tearoff_window(), 0));
3042 _tools_tearoff->Hidden.connect (sigc::bind (sigc::mem_fun(*this, &Editor::detach_tearoff), static_cast<Box*>(&toolbar_hbox),
3043 &_tools_tearoff->tearoff_window()));
3044 _tools_tearoff->Visible.connect (sigc::bind (sigc::mem_fun(*this, &Editor::reattach_tearoff), static_cast<Box*> (&toolbar_hbox),
3045 &_tools_tearoff->tearoff_window(), 0));
3047 toolbar_hbox.set_spacing (10);
3048 toolbar_hbox.set_border_width (1);
3050 toolbar_hbox.pack_start (*_mouse_mode_tearoff, false, false);
3051 toolbar_hbox.pack_start (*_zoom_tearoff, false, false);
3052 toolbar_hbox.pack_start (*_tools_tearoff, false, false);
3054 hbox->pack_start (snap_box, false, false);
3055 if (!Profile->get_small_screen()) {
3056 hbox->pack_start (*nudge_box, false, false);
3058 ARDOUR_UI::instance()->editor_transport_box().pack_start (*nudge_box, false, false);
3060 hbox->pack_start (panic_box, false, false);
3064 toolbar_base.set_name ("ToolBarBase");
3065 toolbar_base.add (toolbar_hbox);
3067 _toolbar_viewport.add (toolbar_base);
3068 /* stick to the required height but allow width to vary if there's not enough room */
3069 _toolbar_viewport.set_size_request (1, -1);
3071 toolbar_frame.set_shadow_type (SHADOW_OUT);
3072 toolbar_frame.set_name ("BaseFrame");
3073 toolbar_frame.add (_toolbar_viewport);
3077 Editor::setup_tooltips ()
3079 ARDOUR_UI::instance()->set_tip (smart_mode_button, _("Smart Mode (add Range functions to Object mode)"));
3080 ARDOUR_UI::instance()->set_tip (mouse_move_button, _("Object Mode (select/move Objects)"));
3081 ARDOUR_UI::instance()->set_tip (mouse_select_button, _("Range Mode (select/move Ranges)"));
3082 ARDOUR_UI::instance()->set_tip (mouse_draw_button, _("Draw/Edit MIDI Notes"));
3083 ARDOUR_UI::instance()->set_tip (mouse_gain_button, _("Draw Region Gain"));
3084 ARDOUR_UI::instance()->set_tip (mouse_zoom_button, _("Select Zoom Range"));
3085 ARDOUR_UI::instance()->set_tip (mouse_timefx_button, _("Stretch/Shrink Regions and MIDI Notes"));
3086 ARDOUR_UI::instance()->set_tip (mouse_audition_button, _("Listen to Specific Regions"));
3087 ARDOUR_UI::instance()->set_tip (internal_edit_button, _("Note Level Editing"));
3088 ARDOUR_UI::instance()->set_tip (*_group_tabs, _("Groups: click to (de)activate\nContext-click for other operations"));
3089 ARDOUR_UI::instance()->set_tip (nudge_forward_button, _("Nudge Region/Selection Later"));
3090 ARDOUR_UI::instance()->set_tip (nudge_backward_button, _("Nudge Region/Selection Earlier"));
3091 ARDOUR_UI::instance()->set_tip (zoom_in_button, _("Zoom In"));
3092 ARDOUR_UI::instance()->set_tip (zoom_out_button, _("Zoom Out"));
3093 ARDOUR_UI::instance()->set_tip (zoom_out_full_button, _("Zoom to Session"));
3094 ARDOUR_UI::instance()->set_tip (zoom_focus_selector, _("Zoom focus"));
3095 ARDOUR_UI::instance()->set_tip (tav_expand_button, _("Expand Tracks"));
3096 ARDOUR_UI::instance()->set_tip (tav_shrink_button, _("Shrink Tracks"));
3097 ARDOUR_UI::instance()->set_tip (snap_type_selector, _("Snap/Grid Units"));
3098 ARDOUR_UI::instance()->set_tip (snap_mode_selector, _("Snap/Grid Mode"));
3099 ARDOUR_UI::instance()->set_tip (edit_point_selector, _("Edit point"));
3100 ARDOUR_UI::instance()->set_tip (edit_mode_selector, _("Edit Mode"));
3101 ARDOUR_UI::instance()->set_tip (nudge_clock, _("Nudge Clock\n(controls distance used to nudge regions and selections)"));
3105 Editor::convert_drop_to_paths (
3106 vector<string>& paths,
3107 const RefPtr<Gdk::DragContext>& /*context*/,
3110 const SelectionData& data,
3114 if (_session == 0) {
3118 vector<string> uris = data.get_uris();
3122 /* This is seriously fucked up. Nautilus doesn't say that its URI lists
3123 are actually URI lists. So do it by hand.
3126 if (data.get_target() != "text/plain") {
3130 /* Parse the "uri-list" format that Nautilus provides,
3131 where each pathname is delimited by \r\n.
3133 THERE MAY BE NO NULL TERMINATING CHAR!!!
3136 string txt = data.get_text();
3140 p = (char *) malloc (txt.length() + 1);
3141 txt.copy (p, txt.length(), 0);
3142 p[txt.length()] = '\0';
3148 while (g_ascii_isspace (*p))
3152 while (*q && (*q != '\n') && (*q != '\r')) {
3159 while (q > p && g_ascii_isspace (*q))
3164 uris.push_back (string (p, q - p + 1));
3168 p = strchr (p, '\n');
3180 for (vector<string>::iterator i = uris.begin(); i != uris.end(); ++i) {
3182 if ((*i).substr (0,7) == "file://") {
3184 string const p = PBD::url_decode (*i);
3186 // scan forward past three slashes
3188 string::size_type slashcnt = 0;
3189 string::size_type n = 0;
3190 string::const_iterator x = p.begin();
3192 while (slashcnt < 3 && x != p.end()) {
3195 } else if (slashcnt == 3) {
3202 if (slashcnt != 3 || x == p.end()) {
3203 error << _("malformed URL passed to drag-n-drop code") << endmsg;
3207 paths.push_back (p.substr (n - 1));
3215 Editor::new_tempo_section ()
3221 Editor::map_transport_state ()
3223 ENSURE_GUI_THREAD (*this, &Editor::map_transport_state);
3225 if (_session && _session->transport_stopped()) {
3226 have_pending_keyboard_selection = false;
3229 update_loop_range_view (true);
3235 Editor::begin_reversible_command (string name)
3238 _session->begin_reversible_command (name);
3243 Editor::begin_reversible_command (GQuark q)
3246 _session->begin_reversible_command (q);
3251 Editor::commit_reversible_command ()
3254 _session->commit_reversible_command ();
3259 Editor::history_changed ()
3263 if (undo_action && _session) {
3264 if (_session->undo_depth() == 0) {
3265 label = S_("Command|Undo");
3267 label = string_compose(S_("Command|Undo (%1)"), _session->next_undo());
3269 undo_action->property_label() = label;
3272 if (redo_action && _session) {
3273 if (_session->redo_depth() == 0) {
3276 label = string_compose(_("Redo (%1)"), _session->next_redo());
3278 redo_action->property_label() = label;
3283 Editor::duplicate_range (bool with_dialog)
3287 RegionSelection rs = get_regions_from_selection_and_entered ();
3289 if ( selection->time.length() == 0 && rs.empty()) {
3295 ArdourDialog win (_("Duplicate"));
3296 Label label (_("Number of duplications:"));
3297 Adjustment adjustment (1.0, 1.0, 1000000.0, 1.0, 5.0);
3298 SpinButton spinner (adjustment, 0.0, 1);
3301 win.get_vbox()->set_spacing (12);
3302 win.get_vbox()->pack_start (hbox);
3303 hbox.set_border_width (6);
3304 hbox.pack_start (label, PACK_EXPAND_PADDING, 12);
3306 /* dialogs have ::add_action_widget() but that puts the spinner in the wrong
3307 place, visually. so do this by hand.
3310 hbox.pack_start (spinner, PACK_EXPAND_PADDING, 12);
3311 spinner.signal_activate().connect (sigc::bind (sigc::mem_fun (win, &ArdourDialog::response), RESPONSE_ACCEPT));
3312 spinner.grab_focus();
3318 win.add_button (Stock::CANCEL, RESPONSE_CANCEL);
3319 win.add_button (_("Duplicate"), RESPONSE_ACCEPT);
3320 win.set_default_response (RESPONSE_ACCEPT);
3322 spinner.grab_focus ();
3324 switch (win.run ()) {
3325 case RESPONSE_ACCEPT:
3331 times = adjustment.get_value();
3334 if ((current_mouse_mode() == Editing::MouseRange)) {
3335 if (selection->time.length()) {
3336 duplicate_selection (times);
3338 } else if (get_smart_mode()) {
3339 if (selection->time.length()) {
3340 duplicate_selection (times);
3342 duplicate_some_regions (rs, times);
3344 duplicate_some_regions (rs, times);
3349 Editor::set_edit_mode (EditMode m)
3351 Config->set_edit_mode (m);
3355 Editor::cycle_edit_mode ()
3357 switch (Config->get_edit_mode()) {
3359 if (Profile->get_sae()) {
3360 Config->set_edit_mode (Lock);
3362 Config->set_edit_mode (Splice);
3366 Config->set_edit_mode (Lock);
3369 Config->set_edit_mode (Slide);
3375 Editor::edit_mode_selection_done ()
3377 string s = edit_mode_selector.get_active_text ();
3380 Config->set_edit_mode (string_to_edit_mode (s));
3385 Editor::snap_type_selection_done ()
3387 string choice = snap_type_selector.get_active_text();
3388 SnapType snaptype = SnapToBeat;
3390 if (choice == _("Beats/2")) {
3391 snaptype = SnapToBeatDiv2;
3392 } else if (choice == _("Beats/3")) {
3393 snaptype = SnapToBeatDiv3;
3394 } else if (choice == _("Beats/4")) {
3395 snaptype = SnapToBeatDiv4;
3396 } else if (choice == _("Beats/5")) {
3397 snaptype = SnapToBeatDiv5;
3398 } else if (choice == _("Beats/6")) {
3399 snaptype = SnapToBeatDiv6;
3400 } else if (choice == _("Beats/7")) {
3401 snaptype = SnapToBeatDiv7;
3402 } else if (choice == _("Beats/8")) {
3403 snaptype = SnapToBeatDiv8;
3404 } else if (choice == _("Beats/10")) {
3405 snaptype = SnapToBeatDiv10;
3406 } else if (choice == _("Beats/12")) {
3407 snaptype = SnapToBeatDiv12;
3408 } else if (choice == _("Beats/14")) {
3409 snaptype = SnapToBeatDiv14;
3410 } else if (choice == _("Beats/16")) {
3411 snaptype = SnapToBeatDiv16;
3412 } else if (choice == _("Beats/20")) {
3413 snaptype = SnapToBeatDiv20;
3414 } else if (choice == _("Beats/24")) {
3415 snaptype = SnapToBeatDiv24;
3416 } else if (choice == _("Beats/28")) {
3417 snaptype = SnapToBeatDiv28;
3418 } else if (choice == _("Beats/32")) {
3419 snaptype = SnapToBeatDiv32;
3420 } else if (choice == _("Beats/64")) {
3421 snaptype = SnapToBeatDiv64;
3422 } else if (choice == _("Beats/128")) {
3423 snaptype = SnapToBeatDiv128;
3424 } else if (choice == _("Beats")) {
3425 snaptype = SnapToBeat;
3426 } else if (choice == _("Bars")) {
3427 snaptype = SnapToBar;
3428 } else if (choice == _("Marks")) {
3429 snaptype = SnapToMark;
3430 } else if (choice == _("Region starts")) {
3431 snaptype = SnapToRegionStart;
3432 } else if (choice == _("Region ends")) {
3433 snaptype = SnapToRegionEnd;
3434 } else if (choice == _("Region bounds")) {
3435 snaptype = SnapToRegionBoundary;
3436 } else if (choice == _("Region syncs")) {
3437 snaptype = SnapToRegionSync;
3438 } else if (choice == _("CD Frames")) {
3439 snaptype = SnapToCDFrame;
3440 } else if (choice == _("Timecode Frames")) {
3441 snaptype = SnapToTimecodeFrame;
3442 } else if (choice == _("Timecode Seconds")) {
3443 snaptype = SnapToTimecodeSeconds;
3444 } else if (choice == _("Timecode Minutes")) {
3445 snaptype = SnapToTimecodeMinutes;
3446 } else if (choice == _("Seconds")) {
3447 snaptype = SnapToSeconds;
3448 } else if (choice == _("Minutes")) {
3449 snaptype = SnapToMinutes;
3452 RefPtr<RadioAction> ract = snap_type_action (snaptype);
3454 ract->set_active ();
3459 Editor::snap_mode_selection_done ()
3461 string choice = snap_mode_selector.get_active_text();
3462 SnapMode mode = SnapNormal;
3464 if (choice == _("No Grid")) {
3466 } else if (choice == _("Grid")) {
3468 } else if (choice == _("Magnetic")) {
3469 mode = SnapMagnetic;
3472 RefPtr<RadioAction> ract = snap_mode_action (mode);
3475 ract->set_active (true);
3480 Editor::cycle_edit_point (bool with_marker)
3482 switch (_edit_point) {
3484 set_edit_point_preference (EditAtPlayhead);
3486 case EditAtPlayhead:
3488 set_edit_point_preference (EditAtSelectedMarker);
3490 set_edit_point_preference (EditAtMouse);
3493 case EditAtSelectedMarker:
3494 set_edit_point_preference (EditAtMouse);
3500 Editor::edit_point_selection_done ()
3502 string choice = edit_point_selector.get_active_text();
3503 EditPoint ep = EditAtSelectedMarker;
3505 if (choice == _("Marker")) {
3506 set_edit_point_preference (EditAtSelectedMarker);
3507 } else if (choice == _("Playhead")) {
3508 set_edit_point_preference (EditAtPlayhead);
3510 set_edit_point_preference (EditAtMouse);
3513 RefPtr<RadioAction> ract = edit_point_action (ep);
3516 ract->set_active (true);
3521 Editor::zoom_focus_selection_done ()
3523 string choice = zoom_focus_selector.get_active_text();
3524 ZoomFocus focus_type = ZoomFocusLeft;
3526 if (choice == _("Left")) {
3527 focus_type = ZoomFocusLeft;
3528 } else if (choice == _("Right")) {
3529 focus_type = ZoomFocusRight;
3530 } else if (choice == _("Center")) {
3531 focus_type = ZoomFocusCenter;
3532 } else if (choice == _("Playhead")) {
3533 focus_type = ZoomFocusPlayhead;
3534 } else if (choice == _("Mouse")) {
3535 focus_type = ZoomFocusMouse;
3536 } else if (choice == _("Edit point")) {
3537 focus_type = ZoomFocusEdit;
3540 RefPtr<RadioAction> ract = zoom_focus_action (focus_type);
3543 ract->set_active ();
3548 Editor::edit_controls_button_release (GdkEventButton* ev)
3550 if (Keyboard::is_context_menu_event (ev)) {
3551 ARDOUR_UI::instance()->add_route (this);
3552 } else if (ev->button == 1) {
3553 selection->clear_tracks ();
3560 Editor::mouse_select_button_release (GdkEventButton* ev)
3562 /* this handles just right-clicks */
3564 if (ev->button != 3) {
3572 Editor::set_zoom_focus (ZoomFocus f)
3574 string str = zoom_focus_strings[(int)f];
3576 if (str != zoom_focus_selector.get_active_text()) {
3577 zoom_focus_selector.set_active_text (str);
3580 if (zoom_focus != f) {
3587 Editor::cycle_zoom_focus ()
3589 switch (zoom_focus) {
3591 set_zoom_focus (ZoomFocusRight);
3593 case ZoomFocusRight:
3594 set_zoom_focus (ZoomFocusCenter);
3596 case ZoomFocusCenter:
3597 set_zoom_focus (ZoomFocusPlayhead);
3599 case ZoomFocusPlayhead:
3600 set_zoom_focus (ZoomFocusMouse);
3602 case ZoomFocusMouse:
3603 set_zoom_focus (ZoomFocusEdit);
3606 set_zoom_focus (ZoomFocusLeft);
3612 Editor::ensure_float (Window& win)
3614 win.set_transient_for (*this);
3618 Editor::pane_allocation_handler (Allocation &alloc, Paned* which)
3620 /* recover or initialize pane positions. do this here rather than earlier because
3621 we don't want the positions to change the child allocations, which they seem to do.
3627 XMLNode* node = ARDOUR_UI::instance()->editor_settings();
3636 XMLNode* geometry = find_named_node (*node, "geometry");
3638 if (which == static_cast<Paned*> (&edit_pane)) {
3640 if (done & Horizontal) {
3644 if (geometry && (prop = geometry->property ("notebook-shrunk"))) {
3645 _notebook_shrunk = string_is_affirmative (prop->value ());
3648 if (!geometry || (prop = geometry->property ("edit-horizontal-pane-pos")) == 0) {
3649 /* initial allocation is 90% to canvas, 10% to notebook */
3650 pos = (int) floor (alloc.get_width() * 0.90f);
3651 snprintf (buf, sizeof(buf), "%d", pos);
3653 pos = atoi (prop->value());
3656 if (GTK_WIDGET(edit_pane.gobj())->allocation.width > pos) {
3657 edit_pane.set_position (pos);
3660 done = (Pane) (done | Horizontal);
3662 } else if (which == static_cast<Paned*> (&editor_summary_pane)) {
3664 if (done & Vertical) {
3668 if (!geometry || (prop = geometry->property ("edit-vertical-pane-pos")) == 0) {
3669 /* initial allocation is 90% to canvas, 10% to summary */
3670 pos = (int) floor (alloc.get_height() * 0.90f);
3671 snprintf (buf, sizeof(buf), "%d", pos);
3674 pos = atoi (prop->value());
3677 if (GTK_WIDGET(editor_summary_pane.gobj())->allocation.height > pos) {
3678 editor_summary_pane.set_position (pos);
3681 done = (Pane) (done | Vertical);
3686 Editor::detach_tearoff (Box* /*b*/, Window* /*w*/)
3688 if ((_tools_tearoff->torn_off() || !_tools_tearoff->visible()) &&
3689 (_mouse_mode_tearoff->torn_off() || !_mouse_mode_tearoff->visible()) &&
3690 (_zoom_tearoff->torn_off() || !_zoom_tearoff->visible())) {
3691 top_hbox.remove (toolbar_frame);
3696 Editor::reattach_tearoff (Box* /*b*/, Window* /*w*/, int32_t /*n*/)
3698 if (toolbar_frame.get_parent() == 0) {
3699 top_hbox.pack_end (toolbar_frame);
3704 Editor::set_show_measures (bool yn)
3706 if (_show_measures != yn) {
3709 if ((_show_measures = yn) == true) {
3711 tempo_lines->show();
3714 ARDOUR::TempoMap::BBTPointList::const_iterator begin;
3715 ARDOUR::TempoMap::BBTPointList::const_iterator end;
3717 compute_current_bbt_points (leftmost_frame, leftmost_frame + current_page_samples(), begin, end);
3718 draw_measures (begin, end);
3726 Editor::toggle_follow_playhead ()
3728 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-follow-playhead"));
3730 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3731 set_follow_playhead (tact->get_active());
3735 /** @param yn true to follow playhead, otherwise false.
3736 * @param catch_up true to reset the editor view to show the playhead (if yn == true), otherwise false.
3739 Editor::set_follow_playhead (bool yn, bool catch_up)
3741 if (_follow_playhead != yn) {
3742 if ((_follow_playhead = yn) == true && catch_up) {
3744 reset_x_origin_to_follow_playhead ();
3751 Editor::toggle_stationary_playhead ()
3753 RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("toggle-stationary-playhead"));
3755 RefPtr<ToggleAction> tact = RefPtr<ToggleAction>::cast_dynamic(act);
3756 set_stationary_playhead (tact->get_active());
3761 Editor::set_stationary_playhead (bool yn)
3763 if (_stationary_playhead != yn) {
3764 if ((_stationary_playhead = yn) == true) {
3766 // FIXME need a 3.0 equivalent of this 2.X call
3767 // update_current_screen ();
3774 Editor::playlist_selector () const
3776 return *_playlist_selector;
3780 Editor::get_grid_type_as_beats (bool& success, framepos_t position)
3784 switch (_snap_type) {
3789 case SnapToBeatDiv128:
3792 case SnapToBeatDiv64:
3795 case SnapToBeatDiv32:
3798 case SnapToBeatDiv28:
3801 case SnapToBeatDiv24:
3804 case SnapToBeatDiv20:
3807 case SnapToBeatDiv16:
3810 case SnapToBeatDiv14:
3813 case SnapToBeatDiv12:
3816 case SnapToBeatDiv10:
3819 case SnapToBeatDiv8:
3822 case SnapToBeatDiv7:
3825 case SnapToBeatDiv6:
3828 case SnapToBeatDiv5:
3831 case SnapToBeatDiv4:
3834 case SnapToBeatDiv3:
3837 case SnapToBeatDiv2:
3843 return _session->tempo_map().meter_at (position).divisions_per_bar();
3848 case SnapToTimecodeFrame:
3849 case SnapToTimecodeSeconds:
3850 case SnapToTimecodeMinutes:
3853 case SnapToRegionStart:
3854 case SnapToRegionEnd:
3855 case SnapToRegionSync:
3856 case SnapToRegionBoundary:
3866 Editor::get_nudge_distance (framepos_t pos, framecnt_t& next)
3870 ret = nudge_clock->current_duration (pos);
3871 next = ret + 1; /* XXXX fix me */
3877 Editor::playlist_deletion_dialog (boost::shared_ptr<Playlist> pl)
3879 ArdourDialog dialog (_("Playlist Deletion"));
3880 Label label (string_compose (_("Playlist %1 is currently unused.\n"
3881 "If it is kept, its audio files will not be cleaned.\n"
3882 "If it is deleted, audio files used by it alone will be cleaned."),
3885 dialog.set_position (WIN_POS_CENTER);
3886 dialog.get_vbox()->pack_start (label);
3890 dialog.add_button (_("Delete Playlist"), RESPONSE_ACCEPT);
3891 dialog.add_button (_("Keep Playlist"), RESPONSE_REJECT);
3892 dialog.add_button (_("Cancel"), RESPONSE_CANCEL);
3894 switch (dialog.run ()) {
3895 case RESPONSE_ACCEPT:
3896 /* delete the playlist */
3900 case RESPONSE_REJECT:
3901 /* keep the playlist */
3913 Editor::audio_region_selection_covers (framepos_t where)
3915 for (RegionSelection::iterator a = selection->regions.begin(); a != selection->regions.end(); ++a) {
3916 if ((*a)->region()->covers (where)) {
3925 Editor::prepare_for_cleanup ()
3927 cut_buffer->clear_regions ();
3928 cut_buffer->clear_playlists ();
3930 selection->clear_regions ();
3931 selection->clear_playlists ();
3933 _regions->suspend_redisplay ();
3937 Editor::finish_cleanup ()
3939 _regions->resume_redisplay ();
3943 Editor::transport_loop_location()
3946 return _session->locations()->auto_loop_location();
3953 Editor::transport_punch_location()
3956 return _session->locations()->auto_punch_location();
3963 Editor::control_layout_scroll (GdkEventScroll* ev)
3965 if (Keyboard::some_magic_widget_has_focus()) {
3969 switch (ev->direction) {
3971 scroll_tracks_up_line ();
3975 case GDK_SCROLL_DOWN:
3976 scroll_tracks_down_line ();
3980 /* no left/right handling yet */
3988 Editor::session_state_saved (string)
3991 _snapshots->redisplay ();
3995 Editor::update_tearoff_visibility()
3997 bool visible = Config->get_keep_tearoffs();
3998 _mouse_mode_tearoff->set_visible (visible);
3999 _tools_tearoff->set_visible (visible);
4000 _zoom_tearoff->set_visible (visible);
4004 Editor::maximise_editing_space ()
4016 Editor::restore_editing_space ()
4028 * Make new playlists for a given track and also any others that belong
4029 * to the same active route group with the `select' property.
4034 Editor::new_playlists (TimeAxisView* v)
4036 begin_reversible_command (_("new playlists"));
4037 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4038 _session->playlists->get (playlists);
4039 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_new_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4040 commit_reversible_command ();
4044 * Use a copy of the current playlist for a given track and also any others that belong
4045 * to the same active route group with the `select' property.
4050 Editor::copy_playlists (TimeAxisView* v)
4052 begin_reversible_command (_("copy playlists"));
4053 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4054 _session->playlists->get (playlists);
4055 mapover_tracks (sigc::bind (sigc::mem_fun (*this, &Editor::mapped_use_copy_playlist), playlists), v, ARDOUR::Properties::select.property_id);
4056 commit_reversible_command ();
4059 /** Clear the current playlist for a given track and also any others that belong
4060 * to the same active route group with the `select' property.
4065 Editor::clear_playlists (TimeAxisView* v)
4067 begin_reversible_command (_("clear playlists"));
4068 vector<boost::shared_ptr<ARDOUR::Playlist> > playlists;
4069 _session->playlists->get (playlists);
4070 mapover_tracks (sigc::mem_fun (*this, &Editor::mapped_clear_playlist), v, ARDOUR::Properties::select.property_id);
4071 commit_reversible_command ();
4075 Editor::mapped_use_new_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4077 atv.use_new_playlist (sz > 1 ? false : true, playlists);
4081 Editor::mapped_use_copy_playlist (RouteTimeAxisView& atv, uint32_t sz, vector<boost::shared_ptr<ARDOUR::Playlist> > const & playlists)
4083 atv.use_copy_playlist (sz > 1 ? false : true, playlists);
4087 Editor::mapped_clear_playlist (RouteTimeAxisView& atv, uint32_t /*sz*/)
4089 atv.clear_playlist ();
4093 Editor::on_key_press_event (GdkEventKey* ev)
4095 return key_press_focus_accelerator_handler (*this, ev);
4099 Editor::on_key_release_event (GdkEventKey* ev)
4101 return Gtk::Window::on_key_release_event (ev);
4102 // return key_press_focus_accelerator_handler (*this, ev);
4105 /** Queue up a change to the viewport x origin.
4106 * @param frame New x origin.
4109 Editor::reset_x_origin (framepos_t frame)
4111 pending_visual_change.add (VisualChange::TimeOrigin);
4112 pending_visual_change.time_origin = frame;
4113 ensure_visual_change_idle_handler ();
4117 Editor::reset_y_origin (double y)
4119 pending_visual_change.add (VisualChange::YOrigin);
4120 pending_visual_change.y_origin = y;
4121 ensure_visual_change_idle_handler ();
4125 Editor::reset_zoom (framecnt_t spp)
4127 clamp_samples_per_pixel (spp);
4129 if (spp == samples_per_pixel) {
4133 pending_visual_change.add (VisualChange::ZoomLevel);
4134 pending_visual_change.samples_per_pixel = spp;
4135 ensure_visual_change_idle_handler ();
4139 Editor::reposition_and_zoom (framepos_t frame, double fpu)
4141 reset_x_origin (frame);
4144 if (!no_save_visual) {
4145 undo_visual_stack.push_back (current_visual_state(false));
4149 Editor::VisualState::VisualState (bool with_tracks)
4150 : gui_state (with_tracks ? new GUIObjectState : 0)
4154 Editor::VisualState::~VisualState ()
4159 Editor::VisualState*
4160 Editor::current_visual_state (bool with_tracks)
4162 VisualState* vs = new VisualState (with_tracks);
4163 vs->y_position = vertical_adjustment.get_value();
4164 vs->samples_per_pixel = samples_per_pixel;
4165 vs->leftmost_frame = leftmost_frame;
4166 vs->zoom_focus = zoom_focus;
4169 *vs->gui_state = *ARDOUR_UI::instance()->gui_object_state;
4176 Editor::undo_visual_state ()
4178 if (undo_visual_stack.empty()) {
4182 VisualState* vs = undo_visual_stack.back();
4183 undo_visual_stack.pop_back();
4186 redo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4188 use_visual_state (*vs);
4192 Editor::redo_visual_state ()
4194 if (redo_visual_stack.empty()) {
4198 VisualState* vs = redo_visual_stack.back();
4199 redo_visual_stack.pop_back();
4201 undo_visual_stack.push_back (current_visual_state (vs ? vs->gui_state != 0 : false));
4203 use_visual_state (*vs);
4207 Editor::swap_visual_state ()
4209 if (undo_visual_stack.empty()) {
4210 redo_visual_state ();
4212 undo_visual_state ();
4217 Editor::use_visual_state (VisualState& vs)
4219 PBD::Unwinder<bool> nsv (no_save_visual, true);
4221 _routes->suspend_redisplay ();
4223 vertical_adjustment.set_value (vs.y_position);
4225 set_zoom_focus (vs.zoom_focus);
4226 reposition_and_zoom (vs.leftmost_frame, vs.samples_per_pixel);
4229 *ARDOUR_UI::instance()->gui_object_state = *vs.gui_state;
4231 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4232 (*i)->reset_visual_state ();
4236 _routes->update_visibility ();
4237 _routes->resume_redisplay ();
4240 /** This is the core function that controls the zoom level of the canvas. It is called
4241 * whenever one or more calls are made to reset_zoom(). It executes in an idle handler.
4242 * @param fpu New frames per unit; should already have been clamped so that it is sensible.
4245 Editor::set_samples_per_pixel (framecnt_t spp)
4247 clamp_samples_per_pixel (spp);
4248 samples_per_pixel = spp;
4251 tempo_lines->tempo_map_changed();
4254 /* convert fpu to frame count */
4256 framepos_t frames = samples_per_pixel * _visible_canvas_width;
4258 if (samples_per_pixel != zoom_range_clock->current_duration()) {
4259 zoom_range_clock->set (frames);
4262 bool const showing_time_selection = selection->time.length() > 0;
4264 if (showing_time_selection && selection->time.start () != selection->time.end_frame ()) {
4265 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4266 (*i)->reshow_selection (selection->time);
4270 ZoomChanged (); /* EMIT_SIGNAL */
4272 //reset_scrolling_region ();
4274 if (playhead_cursor) {
4275 playhead_cursor->set_position (playhead_cursor->current_frame ());
4278 refresh_location_display();
4279 _summary->set_overlays_dirty ();
4281 update_marker_labels ();
4287 Editor::queue_visual_videotimeline_update ()
4290 * pending_visual_change.add (VisualChange::VideoTimeline);
4291 * or maybe even more specific: which videotimeline-image
4292 * currently it calls update_video_timeline() to update
4293 * _all outdated_ images on the video-timeline.
4294 * see 'exposeimg()' in video_image_frame.cc
4296 ensure_visual_change_idle_handler ();
4300 Editor::ensure_visual_change_idle_handler ()
4302 if (pending_visual_change.idle_handler_id < 0) {
4303 pending_visual_change.idle_handler_id = g_idle_add (_idle_visual_changer, this);
4304 pending_visual_change.being_handled = false;
4309 Editor::_idle_visual_changer (void* arg)
4311 return static_cast<Editor*>(arg)->idle_visual_changer ();
4315 Editor::idle_visual_changer ()
4317 /* set_horizontal_position() below (and maybe other calls) call
4318 gtk_main_iteration(), so it's possible that a signal will be handled
4319 half-way through this method. If this signal wants an
4320 idle_visual_changer we must schedule another one after this one, so
4321 mark the idle_handler_id as -1 here to allow that. Also make a note
4322 that we are doing the visual change, so that changes in response to
4323 super-rapid-screen-update can be dropped if we are still processing
4327 pending_visual_change.idle_handler_id = -1;
4328 pending_visual_change.being_handled = true;
4330 VisualChange::Type p = pending_visual_change.pending;
4331 pending_visual_change.pending = (VisualChange::Type) 0;
4333 double const last_time_origin = horizontal_position ();
4336 if (p & VisualChange::ZoomLevel) {
4337 set_samples_per_pixel (pending_visual_change.samples_per_pixel);
4339 compute_fixed_ruler_scale ();
4341 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_begin;
4342 ARDOUR::TempoMap::BBTPointList::const_iterator current_bbt_points_end;
4344 compute_current_bbt_points (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4345 current_bbt_points_begin, current_bbt_points_end);
4346 compute_bbt_ruler_scale (pending_visual_change.time_origin, pending_visual_change.time_origin + current_page_samples(),
4347 current_bbt_points_begin, current_bbt_points_end);
4348 update_tempo_based_rulers (current_bbt_points_begin, current_bbt_points_end);
4350 update_video_timeline();
4353 if (p & VisualChange::TimeOrigin) {
4354 set_horizontal_position (pending_visual_change.time_origin / samples_per_pixel);
4357 if (p & VisualChange::YOrigin) {
4358 vertical_adjustment.set_value (pending_visual_change.y_origin);
4361 if (last_time_origin == horizontal_position ()) {
4362 /* changed signal not emitted */
4363 update_fixed_rulers ();
4364 redisplay_tempo (true);
4367 if (!(p & VisualChange::ZoomLevel)) {
4368 update_video_timeline();
4371 _summary->set_overlays_dirty ();
4373 pending_visual_change.being_handled = false;
4374 return 0; /* this is always a one-shot call */
4377 struct EditorOrderTimeAxisSorter {
4378 bool operator() (const TimeAxisView* a, const TimeAxisView* b) const {
4379 return a->order () < b->order ();
4384 Editor::sort_track_selection (TrackViewList& sel)
4386 EditorOrderTimeAxisSorter cmp;
4391 Editor::get_preferred_edit_position (bool ignore_playhead, bool from_context_menu)
4394 framepos_t where = 0;
4395 EditPoint ep = _edit_point;
4397 if (from_context_menu && (ep == EditAtMouse)) {
4398 return window_event_frame (&context_click_event, 0, 0);
4401 if (entered_marker) {
4402 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use entered marker @ %1\n", entered_marker->position()));
4403 return entered_marker->position();
4406 if (ignore_playhead && ep == EditAtPlayhead) {
4407 ep = EditAtSelectedMarker;
4411 case EditAtPlayhead:
4412 where = _session->audible_frame();
4413 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use playhead @ %1\n", where));
4416 case EditAtSelectedMarker:
4417 if (!selection->markers.empty()) {
4419 Location* loc = find_location_from_marker (selection->markers.front(), is_start);
4422 where = loc->start();
4426 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use selected marker @ %1\n", where));
4434 if (!mouse_frame (where, ignored)) {
4435 /* XXX not right but what can we do ? */
4439 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("GPEP: use mouse @ %1\n", where));
4447 Editor::set_loop_range (framepos_t start, framepos_t end, string cmd)
4449 if (!_session) return;
4451 begin_reversible_command (cmd);
4455 if ((tll = transport_loop_location()) == 0) {
4456 Location* loc = new Location (*_session, start, end, _("Loop"), Location::IsAutoLoop);
4457 XMLNode &before = _session->locations()->get_state();
4458 _session->locations()->add (loc, true);
4459 _session->set_auto_loop_location (loc);
4460 XMLNode &after = _session->locations()->get_state();
4461 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4463 XMLNode &before = tll->get_state();
4464 tll->set_hidden (false, this);
4465 tll->set (start, end);
4466 XMLNode &after = tll->get_state();
4467 _session->add_command (new MementoCommand<Location>(*tll, &before, &after));
4470 commit_reversible_command ();
4474 Editor::set_punch_range (framepos_t start, framepos_t end, string cmd)
4476 if (!_session) return;
4478 begin_reversible_command (cmd);
4482 if ((tpl = transport_punch_location()) == 0) {
4483 Location* loc = new Location (*_session, start, end, _("Punch"), Location::IsAutoPunch);
4484 XMLNode &before = _session->locations()->get_state();
4485 _session->locations()->add (loc, true);
4486 _session->set_auto_loop_location (loc);
4487 XMLNode &after = _session->locations()->get_state();
4488 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
4491 XMLNode &before = tpl->get_state();
4492 tpl->set_hidden (false, this);
4493 tpl->set (start, end);
4494 XMLNode &after = tpl->get_state();
4495 _session->add_command (new MementoCommand<Location>(*tpl, &before, &after));
4498 commit_reversible_command ();
4501 /** Find regions which exist at a given time, and optionally on a given list of tracks.
4502 * @param rs List to which found regions are added.
4503 * @param where Time to look at.
4504 * @param ts Tracks to look on; if this is empty, all tracks are examined.
4507 Editor::get_regions_at (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4509 const TrackViewList* tracks;
4512 tracks = &track_views;
4517 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4519 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4522 boost::shared_ptr<Track> tr;
4523 boost::shared_ptr<Playlist> pl;
4525 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4527 boost::shared_ptr<RegionList> regions = pl->regions_at (
4528 (framepos_t) floor ( (double) where * tr->speed()));
4530 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4531 RegionView* rv = rtv->view()->find_view (*i);
4542 Editor::get_regions_after (RegionSelection& rs, framepos_t where, const TrackViewList& ts) const
4544 const TrackViewList* tracks;
4547 tracks = &track_views;
4552 for (TrackViewList::const_iterator t = tracks->begin(); t != tracks->end(); ++t) {
4553 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*t);
4555 boost::shared_ptr<Track> tr;
4556 boost::shared_ptr<Playlist> pl;
4558 if ((tr = rtv->track()) && ((pl = tr->playlist()))) {
4560 boost::shared_ptr<RegionList> regions = pl->regions_touched (
4561 (framepos_t) floor ( (double)where * tr->speed()), max_framepos);
4563 for (RegionList::iterator i = regions->begin(); i != regions->end(); ++i) {
4565 RegionView* rv = rtv->view()->find_view (*i);
4576 /** Get regions using the following method:
4578 * Make a region list using the selected regions, unless
4579 * the edit point is `mouse' and the mouse is over an unselected
4580 * region. In this case, use just that region.
4582 * If the edit point is not 'mouse', and there are no regions selected,
4583 * search the list of selected tracks and return regions that are under
4584 * the edit point on these tracks. If there are no selected tracks and
4585 * 'No Selection = All Tracks' is active, search all tracks,
4587 * The rationale here is that the mouse edit point is special in that
4588 * its position describes both a time and a track; the other edit
4589 * modes only describe a time. Hence if the edit point is `mouse' we
4590 * ignore selected tracks, as we assume the user means something by
4591 * pointing at a particular track. Also in this case we take note of
4592 * the region directly under the edit point, as there is always just one
4593 * (rather than possibly several with non-mouse edit points).
4597 Editor::get_regions_from_selection_and_edit_point ()
4599 RegionSelection regions;
4601 if (_edit_point == EditAtMouse && entered_regionview && !selection->regions.contains (entered_regionview)) {
4602 regions.add (entered_regionview);
4604 regions = selection->regions;
4608 if (regions.empty() && _edit_point != EditAtMouse) {
4609 TrackViewList tracks = selection->tracks;
4611 if (_route_groups->all_group_active_button().get_active() && tracks.empty()) {
4612 /* tracks is empty (no track selected), and 'No Selection = All Tracks'
4613 * is enabled, so consider all tracks
4615 tracks = track_views;
4618 if (!tracks.empty()) {
4619 /* no region selected or entered, but some selected tracks:
4620 * act on all regions on the selected tracks at the edit point
4622 framepos_t const where = get_preferred_edit_position ();
4623 get_regions_at(regions, where, tracks);
4629 /** Start with regions that are selected, or the entered regionview if none are selected.
4630 * Then add equivalent regions on tracks in the same active edit-enabled route group as any
4631 * of the regions that we started with.
4635 Editor::get_regions_from_selection_and_entered ()
4637 RegionSelection regions = selection->regions;
4639 if (regions.empty() && entered_regionview) {
4640 regions.add (entered_regionview);
4647 Editor::get_regions_corresponding_to (boost::shared_ptr<Region> region, vector<RegionView*>& regions, bool src_comparison)
4649 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4651 RouteTimeAxisView* tatv;
4653 if ((tatv = dynamic_cast<RouteTimeAxisView*> (*i)) != 0) {
4655 boost::shared_ptr<Playlist> pl;
4656 vector<boost::shared_ptr<Region> > results;
4658 boost::shared_ptr<Track> tr;
4660 if ((tr = tatv->track()) == 0) {
4665 if ((pl = (tr->playlist())) != 0) {
4666 if (src_comparison) {
4667 pl->get_source_equivalent_regions (region, results);
4669 pl->get_region_list_equivalent_regions (region, results);
4673 for (vector<boost::shared_ptr<Region> >::iterator ir = results.begin(); ir != results.end(); ++ir) {
4674 if ((marv = tatv->view()->find_view (*ir)) != 0) {
4675 regions.push_back (marv);
4684 Editor::show_rhythm_ferret ()
4686 if (rhythm_ferret == 0) {
4687 rhythm_ferret = new RhythmFerret(*this);
4690 rhythm_ferret->set_session (_session);
4691 rhythm_ferret->show ();
4692 rhythm_ferret->present ();
4696 Editor::first_idle ()
4698 MessageDialog* dialog = 0;
4700 if (track_views.size() > 1) {
4701 dialog = new MessageDialog (
4703 string_compose (_("Please wait while %1 loads visual data."), PROGRAM_NAME),
4707 ARDOUR_UI::instance()->flush_pending ();
4710 for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
4714 // first idle adds route children (automation tracks), so we need to redisplay here
4715 _routes->redisplay ();
4722 Editor::_idle_resize (gpointer arg)
4724 return ((Editor*)arg)->idle_resize ();
4728 Editor::add_to_idle_resize (TimeAxisView* view, int32_t h)
4730 if (resize_idle_id < 0) {
4731 resize_idle_id = g_idle_add (_idle_resize, this);
4732 _pending_resize_amount = 0;
4735 /* make a note of the smallest resulting height, so that we can clamp the
4736 lower limit at TimeAxisView::hSmall */
4738 int32_t min_resulting = INT32_MAX;
4740 _pending_resize_amount += h;
4741 _pending_resize_view = view;
4743 min_resulting = min (min_resulting, int32_t (_pending_resize_view->current_height()) + _pending_resize_amount);
4745 if (selection->tracks.contains (_pending_resize_view)) {
4746 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4747 min_resulting = min (min_resulting, int32_t ((*i)->current_height()) + _pending_resize_amount);
4751 if (min_resulting < 0) {
4756 if (uint32_t (min_resulting) < TimeAxisView::preset_height (HeightSmall)) {
4757 _pending_resize_amount += TimeAxisView::preset_height (HeightSmall) - min_resulting;
4761 /** Handle pending resizing of tracks */
4763 Editor::idle_resize ()
4765 _pending_resize_view->idle_resize (_pending_resize_view->current_height() + _pending_resize_amount);
4767 if (dynamic_cast<AutomationTimeAxisView*> (_pending_resize_view) == 0 &&
4768 selection->tracks.contains (_pending_resize_view)) {
4770 for (TrackViewList::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4771 if (*i != _pending_resize_view) {
4772 (*i)->idle_resize ((*i)->current_height() + _pending_resize_amount);
4777 _pending_resize_amount = 0;
4778 _group_tabs->set_dirty ();
4779 resize_idle_id = -1;
4787 ENSURE_GUI_THREAD (*this, &Editor::located);
4790 playhead_cursor->set_position (_session->audible_frame ());
4791 if (_follow_playhead && !_pending_initial_locate) {
4792 reset_x_origin_to_follow_playhead ();
4796 _pending_locate_request = false;
4797 _pending_initial_locate = false;
4801 Editor::region_view_added (RegionView *)
4803 _summary->set_dirty ();
4807 Editor::region_view_removed ()
4809 _summary->set_dirty ();
4813 Editor::axis_view_from_route (boost::shared_ptr<Route> r) const
4815 TrackViewList::const_iterator j = track_views.begin ();
4816 while (j != track_views.end()) {
4817 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*j);
4818 if (rtv && rtv->route() == r) {
4829 Editor::axis_views_from_routes (boost::shared_ptr<RouteList> r) const
4833 for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
4834 TimeAxisView* tv = axis_view_from_route (*i);
4844 Editor::add_routes (RouteList& routes)
4846 ENSURE_GUI_THREAD (*this, &Editor::handle_new_route, routes)
4848 RouteTimeAxisView *rtv;
4849 list<RouteTimeAxisView*> new_views;
4851 for (RouteList::iterator x = routes.begin(); x != routes.end(); ++x) {
4852 boost::shared_ptr<Route> route = (*x);
4854 if (route->is_auditioner() || route->is_monitor()) {
4858 DataType dt = route->input()->default_type();
4860 if (dt == ARDOUR::DataType::AUDIO) {
4861 rtv = new AudioTimeAxisView (*this, _session, *_track_canvas);
4862 rtv->set_route (route);
4863 } else if (dt == ARDOUR::DataType::MIDI) {
4864 rtv = new MidiTimeAxisView (*this, _session, *_track_canvas);
4865 rtv->set_route (route);
4867 throw unknown_type();
4870 new_views.push_back (rtv);
4871 track_views.push_back (rtv);
4873 rtv->effective_gain_display ();
4875 if (internal_editing()) {
4876 rtv->enter_internal_edit_mode ();
4878 rtv->leave_internal_edit_mode ();
4881 rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &Editor::region_view_added));
4882 rtv->view()->RegionViewRemoved.connect (sigc::mem_fun (*this, &Editor::region_view_removed));
4885 _routes->routes_added (new_views);
4886 _summary->routes_added (new_views);
4888 if (show_editor_mixer_when_tracks_arrive) {
4889 show_editor_mixer (true);
4892 editor_list_button.set_sensitive (true);
4896 Editor::timeaxisview_deleted (TimeAxisView *tv)
4898 if (_session && _session->deletion_in_progress()) {
4899 /* the situation is under control */
4903 ENSURE_GUI_THREAD (*this, &Editor::timeaxisview_deleted, tv);
4905 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (tv);
4907 _routes->route_removed (tv);
4909 if (tv == entered_track) {
4913 TimeAxisView::Children c = tv->get_child_list ();
4914 for (TimeAxisView::Children::const_iterator i = c.begin(); i != c.end(); ++i) {
4915 if (entered_track == i->get()) {
4920 /* remove it from the list of track views */
4922 TrackViewList::iterator i;
4924 if ((i = find (track_views.begin(), track_views.end(), tv)) != track_views.end()) {
4925 i = track_views.erase (i);
4928 /* update whatever the current mixer strip is displaying, if revelant */
4930 boost::shared_ptr<Route> route;
4933 route = rtav->route ();
4936 if (current_mixer_strip && current_mixer_strip->route() == route) {
4938 TimeAxisView* next_tv;
4940 if (track_views.empty()) {
4942 } else if (i == track_views.end()) {
4943 next_tv = track_views.front();
4950 set_selected_mixer_strip (*next_tv);
4952 /* make the editor mixer strip go away setting the
4953 * button to inactive (which also unticks the menu option)
4956 ActionManager::uncheck_toggleaction ("<Actions>/Editor/show-editor-mixer");
4962 Editor::hide_track_in_display (TimeAxisView* tv, bool apply_to_selection)
4964 if (apply_to_selection) {
4965 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ) {
4967 TrackSelection::iterator j = i;
4970 hide_track_in_display (*i, false);
4975 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
4977 if (rtv && current_mixer_strip && (rtv->route() == current_mixer_strip->route())) {
4978 // this will hide the mixer strip
4979 set_selected_mixer_strip (*tv);
4982 _routes->hide_track_in_display (*tv);
4987 Editor::sync_track_view_list_and_routes ()
4989 track_views = TrackViewList (_routes->views ());
4991 _summary->set_dirty ();
4992 _group_tabs->set_dirty ();
4994 return false; // do not call again (until needed)
4998 Editor::foreach_time_axis_view (sigc::slot<void,TimeAxisView&> theslot)
5000 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5005 /** Find a RouteTimeAxisView by the ID of its route */
5007 Editor::get_route_view_by_route_id (const PBD::ID& id) const
5009 RouteTimeAxisView* v;
5011 for (TrackViewList::const_iterator i = track_views.begin(); i != track_views.end(); ++i) {
5012 if((v = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5013 if(v->route()->id() == id) {
5023 Editor::fit_route_group (RouteGroup *g)
5025 TrackViewList ts = axis_views_from_routes (g->route_list ());
5030 Editor::consider_auditioning (boost::shared_ptr<Region> region)
5032 boost::shared_ptr<AudioRegion> r = boost::dynamic_pointer_cast<AudioRegion> (region);
5035 _session->cancel_audition ();
5039 if (_session->is_auditioning()) {
5040 _session->cancel_audition ();
5041 if (r == last_audition_region) {
5046 _session->audition_region (r);
5047 last_audition_region = r;
5052 Editor::hide_a_region (boost::shared_ptr<Region> r)
5054 r->set_hidden (true);
5058 Editor::show_a_region (boost::shared_ptr<Region> r)
5060 r->set_hidden (false);
5064 Editor::audition_region_from_region_list ()
5066 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::consider_auditioning));
5070 Editor::hide_region_from_region_list ()
5072 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::hide_a_region));
5076 Editor::show_region_in_region_list ()
5078 _regions->selection_mapover (sigc::mem_fun (*this, &Editor::show_a_region));
5082 Editor::step_edit_status_change (bool yn)
5085 start_step_editing ();
5087 stop_step_editing ();
5092 Editor::start_step_editing ()
5094 step_edit_connection = Glib::signal_timeout().connect (sigc::mem_fun (*this, &Editor::check_step_edit), 20);
5098 Editor::stop_step_editing ()
5100 step_edit_connection.disconnect ();
5104 Editor::check_step_edit ()
5106 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5107 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (*i);
5109 mtv->check_step_edit ();
5113 return true; // do it again, till we stop
5117 Editor::scroll_press (Direction dir)
5119 ++_scroll_callbacks;
5121 if (_scroll_connection.connected() && _scroll_callbacks < 5) {
5122 /* delay the first auto-repeat */
5128 scroll_backward (1);
5136 scroll_tracks_up_line ();
5140 scroll_tracks_down_line ();
5144 /* do hacky auto-repeat */
5145 if (!_scroll_connection.connected ()) {
5147 _scroll_connection = Glib::signal_timeout().connect (
5148 sigc::bind (sigc::mem_fun (*this, &Editor::scroll_press), dir), 100
5151 _scroll_callbacks = 0;
5158 Editor::scroll_release ()
5160 _scroll_connection.disconnect ();
5163 /** Queue a change for the Editor viewport x origin to follow the playhead */
5165 Editor::reset_x_origin_to_follow_playhead ()
5167 framepos_t const frame = playhead_cursor->current_frame ();
5169 if (frame < leftmost_frame || frame > leftmost_frame + current_page_samples()) {
5171 if (_session->transport_speed() < 0) {
5173 if (frame > (current_page_samples() / 2)) {
5174 center_screen (frame-(current_page_samples()/2));
5176 center_screen (current_page_samples()/2);
5183 if (frame < leftmost_frame) {
5185 if (_session->transport_rolling()) {
5186 /* rolling; end up with the playhead at the right of the page */
5187 l = frame - current_page_samples ();
5189 /* not rolling: end up with the playhead 1/4 of the way along the page */
5190 l = frame - current_page_samples() / 4;
5194 if (_session->transport_rolling()) {
5195 /* rolling: end up with the playhead on the left of the page */
5198 /* not rolling: end up with the playhead 3/4 of the way along the page */
5199 l = frame - 3 * current_page_samples() / 4;
5207 center_screen_internal (l + (current_page_samples() / 2), current_page_samples ());
5213 Editor::super_rapid_screen_update ()
5215 if (!_session || !_session->engine().running()) {
5219 /* METERING / MIXER STRIPS */
5221 /* update track meters, if required */
5222 if (is_mapped() && meters_running) {
5223 RouteTimeAxisView* rtv;
5224 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5225 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
5226 rtv->fast_update ();
5231 /* and any current mixer strip */
5232 if (current_mixer_strip) {
5233 current_mixer_strip->fast_update ();
5236 /* PLAYHEAD AND VIEWPORT */
5238 framepos_t const frame = _session->audible_frame();
5240 /* There are a few reasons why we might not update the playhead / viewport stuff:
5242 * 1. we don't update things when there's a pending locate request, otherwise
5243 * when the editor requests a locate there is a chance that this method
5244 * will move the playhead before the locate request is processed, causing
5246 * 2. if we're not rolling, there's nothing to do here (locates are handled elsewhere).
5247 * 3. if we're still at the same frame that we were last time, there's nothing to do.
5250 if (!_pending_locate_request && _session->transport_speed() != 0 && frame != last_update_frame) {
5252 last_update_frame = frame;
5254 if (!_dragging_playhead) {
5255 playhead_cursor->set_position (frame);
5258 if (!_stationary_playhead) {
5260 if (!_dragging_playhead && _follow_playhead && _session->requested_return_frame() < 0 && !pending_visual_change.being_handled) {
5261 /* We only do this if we aren't already
5262 handling a visual change (ie if
5263 pending_visual_change.being_handled is
5264 false) so that these requests don't stack
5265 up there are too many of them to handle in
5268 reset_x_origin_to_follow_playhead ();
5273 /* don't do continuous scroll till the new position is in the rightmost quarter of the
5277 // FIXME DO SOMETHING THAT WORKS HERE - this is 2.X code
5278 double target = ((double)frame - (double)current_page_samples()/2.0) / samples_per_pixel;
5279 if (target <= 0.0) {
5282 if (fabs(target - current) < current_page_samples() / samples_per_pixel) {
5283 target = (target * 0.15) + (current * 0.85);
5289 set_horizontal_position (current);
5298 Editor::session_going_away ()
5300 _have_idled = false;
5302 _session_connections.drop_connections ();
5304 super_rapid_screen_update_connection.disconnect ();
5306 selection->clear ();
5307 cut_buffer->clear ();
5309 clicked_regionview = 0;
5310 clicked_axisview = 0;
5311 clicked_routeview = 0;
5312 entered_regionview = 0;
5314 last_update_frame = 0;
5317 playhead_cursor->hide ();
5319 /* rip everything out of the list displays */
5323 _route_groups->clear ();
5325 /* do this first so that deleting a track doesn't reset cms to null
5326 and thus cause a leak.
5329 if (current_mixer_strip) {
5330 if (current_mixer_strip->get_parent() != 0) {
5331 global_hpacker.remove (*current_mixer_strip);
5333 delete current_mixer_strip;
5334 current_mixer_strip = 0;
5337 /* delete all trackviews */
5339 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5342 track_views.clear ();
5344 zoom_range_clock->set_session (0);
5345 nudge_clock->set_session (0);
5347 editor_list_button.set_active(false);
5348 editor_list_button.set_sensitive(false);
5350 /* clear tempo/meter rulers */
5351 remove_metric_marks ();
5353 clear_marker_display ();
5355 stop_step_editing ();
5357 /* get rid of any existing editor mixer strip */
5359 WindowTitle title(Glib::get_application_name());
5360 title += _("Editor");
5362 set_title (title.get_string());
5364 SessionHandlePtr::session_going_away ();
5369 Editor::show_editor_list (bool yn)
5372 _the_notebook.show ();
5374 _the_notebook.hide ();
5379 Editor::change_region_layering_order (bool from_context_menu)
5381 const framepos_t position = get_preferred_edit_position (false, from_context_menu);
5383 if (!clicked_routeview) {
5384 if (layering_order_editor) {
5385 layering_order_editor->hide ();
5390 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (clicked_routeview->route());
5396 boost::shared_ptr<Playlist> pl = track->playlist();
5402 if (layering_order_editor == 0) {
5403 layering_order_editor = new RegionLayeringOrderEditor (*this);
5406 layering_order_editor->set_context (clicked_routeview->name(), _session, clicked_routeview, pl, position);
5407 layering_order_editor->maybe_present ();
5411 Editor::update_region_layering_order_editor ()
5413 if (layering_order_editor && layering_order_editor->is_visible ()) {
5414 change_region_layering_order (true);
5419 Editor::setup_fade_images ()
5421 _fade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadein-linear")));
5422 _fade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadein-short-cut")));
5423 _fade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadein-slow-cut")));
5424 _fade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadein-fast-cut")));
5425 _fade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadein-long-cut")));
5427 _fade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5428 _fade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5429 _fade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5430 _fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5431 _fade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5433 _xfade_in_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5434 _xfade_in_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5435 _xfade_in_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5436 _xfade_in_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5437 _xfade_in_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5439 _xfade_out_images[FadeLinear] = new Gtk::Image (get_icon_path (X_("fadeout-linear")));
5440 _xfade_out_images[FadeSymmetric] = new Gtk::Image (get_icon_path (X_("fadeout-short-cut")));
5441 _xfade_out_images[FadeFast] = new Gtk::Image (get_icon_path (X_("fadeout-slow-cut")));
5442 _xfade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("fadeout-fast-cut")));
5443 _xfade_out_images[FadeConstantPower] = new Gtk::Image (get_icon_path (X_("fadeout-long-cut")));
5447 /** @return Gtk::manage()d menu item for a given action from `editor_actions' */
5449 Editor::action_menu_item (std::string const & name)
5451 Glib::RefPtr<Action> a = editor_actions->get_action (name);
5454 return *manage (a->create_menu_item ());
5458 Editor::add_notebook_page (string const & name, Gtk::Widget& widget)
5460 EventBox* b = manage (new EventBox);
5461 b->signal_button_press_event().connect (sigc::bind (sigc::mem_fun (*this, &Editor::notebook_tab_clicked), &widget));
5462 Label* l = manage (new Label (name));
5466 _the_notebook.append_page (widget, *b);
5470 Editor::notebook_tab_clicked (GdkEventButton* ev, Gtk::Widget* page)
5472 if (ev->type == GDK_BUTTON_PRESS || ev->type == GDK_2BUTTON_PRESS) {
5473 _the_notebook.set_current_page (_the_notebook.page_num (*page));
5476 if (ev->type == GDK_2BUTTON_PRESS) {
5478 /* double-click on a notebook tab shrinks or expands the notebook */
5480 if (_notebook_shrunk) {
5481 if (pre_notebook_shrink_pane_width) {
5482 edit_pane.set_position (*pre_notebook_shrink_pane_width);
5484 _notebook_shrunk = false;
5486 pre_notebook_shrink_pane_width = edit_pane.get_position();
5488 /* this expands the LHS of the edit pane to cover the notebook
5489 PAGE but leaves the tabs visible.
5491 edit_pane.set_position (edit_pane.get_position() + page->get_width());
5492 _notebook_shrunk = true;
5500 Editor::popup_control_point_context_menu (ArdourCanvas::Item* item, GdkEvent* event)
5502 using namespace Menu_Helpers;
5504 MenuList& items = _control_point_context_menu.items ();
5507 items.push_back (MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_control_point), item)));
5508 items.push_back (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun (*this, &Editor::remove_control_point), item)));
5509 if (!can_remove_control_point (item)) {
5510 items.back().set_sensitive (false);
5513 _control_point_context_menu.popup (event->button.button, event->button.time);
5517 Editor::zoom_vertical_modifier_released()
5519 _stepping_axis_view = 0;